https://mooseframework.inl.gov
RepeatableRayStudyBase.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "RepeatableRayStudyBase.h"
11 
12 // libMesh includes
13 #include "libmesh/parallel_sync.h"
14 
15 #include "DataIO.h"
16 
19 {
20  auto params = RayTracingStudy::validParams();
21 
22  // Whether or not the _rays filled by defineRays() are replicated
23  // (the same across all processors)
24  params.addPrivateParam<bool>("_define_rays_replicated", true);
25  // Whether or not Rays need to be claimed after calling defineRays()
26  params.addPrivateParam<bool>("_claim_after_define_rays", true);
27 
28  return params;
29 }
30 
32  : RayTracingStudy(parameters),
33  _rays(declareRestartableDataWithContext<std::vector<std::shared_ptr<Ray>>>("rays", this)),
34  _define_rays_replicated(getParam<bool>("_claim_after_define_rays")
35  ? getParam<bool>("_define_rays_replicated")
36  : false),
37  _claim_after_define_rays(getParam<bool>("_claim_after_define_rays")),
38  _should_define_rays(declareRestartableData<bool>("should_define_rays", true)),
39  _local_rays(
40  declareRestartableDataWithContext<std::vector<std::shared_ptr<Ray>>>("local_rays", this)),
41  _claim_rays(*this,
42  _rays,
43  _local_rays,
44  /* do_exchange = */ !_define_rays_replicated),
45  _should_claim_rays(
46  declareRestartableData<bool>("claim_after_define_rays", _claim_after_define_rays))
47 {
48  if (!_claim_after_define_rays && getParam<bool>("_define_rays_replicated"))
49  mooseWarning("The combination of private parameters:",
50  "\n '_define_rays_replicated' == true",
51  "\n '_claim_after_define_rays' == false",
52  "\nis not a valid combination.",
53  "\n\n_define_rays_replicated is being set to false.");
54 }
55 
56 void
58 {
59  // Initially, the user is to define the Rays that they want to trace by overriding
60  // defineRays() and filling into _rays within this method. These Rays are not
61  // the Rays that will actually be traced, they just serve as a template for
62  // Rays that will be put into the tracer to be traced.
63  //
64  // If the private parameter '_claim_after_define_rays' == true, it is assumed
65  // that the Rays that were filled into _rays from the overridden defineRays()
66  // do not have their starting element and incoming sides set. The Rays in _rays
67  // will be "claimed" later and communicated to the processors that will start them
68  // with their starting element set and incoming side set (if any). An example of this
69  // is in RepeatableRayStudy.
70  //
71  // If the private parameter '_claim_after_define_rays' == false, it is assumed
72  // that the Rays that were filled into _rays from the overridden defineRays():
73  // - Have their starting element and incoming side (if applicable) set and it is
74  // correct
75  // - Are on the processor that will start them (the processor that contains
76  // the starting element)
77  // At this point, the Rays in _rays will be also inserted into _local_rays
78  // because they are on the right processor with starting information set.
79  // An example of this is in LotsOfRaysRayStudy.
81  {
82  _should_define_rays = false;
83 
85  }
86 
88  {
89  _should_claim_rays = false;
90 
92  }
93 
94  // Reserve ahead of time how many Rays we are adding to the buffer
96 
97  // To make this study "repeatable", we will not trace the Rays that
98  // are ready to go in _local_rays. We will instead create new Rays
99  // that are duplicates of the ones in _local_rays, and trace those.
100  // This ensures that on multiple executions of this study, we always
101  // have the information to create the same Rays.
102  for (const auto & ray : _local_rays)
103  {
104  // This acquires a new ray that is copied from a Ray that has already
105  // been claimed to begin on this processor with the user-defined trajectory
106  std::shared_ptr<Ray> copied_ray = acquireCopiedRay(*ray);
107 
108  // This calls std::move() on the ray, which means that copied_ray in this context
109  // is no longer valid. We use the move method because copied_ray is a shared_ptr
110  // and otherwise we would increase the count as we add it to the buffer and also
111  // decrease the count once this goes out of scope.
112  moveRayToBuffer(copied_ray);
113  }
114 }
115 
116 void
118 {
120 
121  // Need to reclaim after this
122  _should_claim_rays = true;
123 
124  // Invalidate all of the old starting info because we can't be sure those elements still exist
125  for (const auto & ray : _rays)
126  {
127  ray->invalidateStartingElem();
128  ray->invalidateStartingIncomingSide();
129  }
130  for (const auto & ray : _local_rays)
131  {
132  ray->invalidateStartingElem();
133  ray->invalidateStartingIncomingSide();
134  }
135 }
136 
137 void
139 {
140  TIME_SECTION("claimRaysInternal", 2, "Claiming Rays");
141 
142  _claim_rays.claim();
143 }
144 
145 void
147 {
148  {
149  TIME_SECTION("defineRaysInternal", 2, "Defining Rays");
150 
151  _rays.clear();
152  _local_rays.clear();
153 
154  defineRays();
155  }
156 
157  // Do we actually have Rays
158  auto num_rays = _rays.size();
159  _communicator.sum(num_rays);
160  if (!num_rays)
161  mooseError("No Rays were moved to _rays in defineRays()");
162  for (const auto & ray : _rays)
163  if (!ray)
164  mooseError("A nullptr Ray was found in _rays after defineRays().");
165 
166  // The Rays in _rays are ready to go as is: they have their starting element
167  // set, their incoming set (if any), and are on the processor that owns said
168  // starting element. Therefore, we move them right into _local_rays and
169  // set that we don't need to claim.
171  {
172  _local_rays.reserve(_rays.size());
173  for (const std::shared_ptr<Ray> & ray : _rays)
174  _local_rays.emplace_back(ray);
175 
176  _should_claim_rays = false;
177  }
178  // Claiming is required after defining. The Rays in _rays should not
179  // have their starting elems or incoming sides set - verify that.
180  else
181  {
182  for (const std::shared_ptr<Ray> & ray : _rays)
183  if (ray->currentElem() || !ray->invalidCurrentIncomingSide())
184  mooseError(
185  "A Ray was found in _rays after defineRays() that has a starting element or "
186  "incoming side set.\n\n",
187  "With the mode in which the private param '_claim_after_define_rays' == true,",
188  "\nthe defined Rays at this point should not have their starting elem/side set.\n",
189  "\nTheir starting information will be set internally using a claiming process.\n\n",
190  ray->getInfo());
191  }
192 
193  // Sanity checks on if the Rays are actually replicated
196 }
197 
198 void
200 {
201  TIME_SECTION("verifyReplicatedRays", 2, "Verifying Replicated Rays");
202 
203  const std::string error_suffix =
204  "\n\nThe Rays added in defineRays() must be replicated across all processors\nwith the "
205  "private param '_define_rays_replicated' == true.";
206 
207  // First, verify that our _rays have unique IDs beacuse we will do mapping based on Ray ID
208  verifyUniqueRayIDs(_rays.begin(),
209  _rays.end(),
210  /* global = */ false,
211  "in _rays after calling defineRays()." + error_suffix);
212 
213  // Tag for sending rays from rank 0 -> all other ranks
214  const auto tag = comm().get_unique_tag();
215 
216  // Send a copy of the rays on rank 0 to all other processors for verification
217  if (_pid == 0)
218  {
219  std::vector<Parallel::Request> requests(n_processors() - 1);
220  auto request_it = requests.begin();
221 
222  for (processor_id_type pid = 0; pid < n_processors(); ++pid)
223  if (pid != 0)
225  pid, parallelStudy(), _rays.begin(), _rays.end(), *request_it++, tag);
226 
227  Parallel::wait(requests);
228  }
229  // All other processors will receive and verify that their rays match the rays on rank 0
230  else
231  {
232  // Map of RayID -> Ray for comparison from the Rays on rank 0 to the local rays
233  std::unordered_map<RayID, const Ray *> ray_map;
234  ray_map.reserve(_rays.size());
235  for (const auto & ray : _rays)
236  ray_map.emplace(ray->id(), ray.get());
237 
238  // Receive the duplicated rays from rank 0
239  std::vector<std::shared_ptr<Ray>> rank_0_rays;
240  rank_0_rays.reserve(_rays.size());
242  0, parallelStudy(), std::back_inserter(rank_0_rays), (std::shared_ptr<Ray> *)nullptr, tag);
243 
244  // The sizes better match
245  if (rank_0_rays.size() != _rays.size())
246  mooseError("The size of _rays on rank ",
247  _pid,
248  " does not match the size of rays on rank 0.",
249  error_suffix);
250 
251  // Make sure we have a matching local ray for each ray from rank 0
252  for (const auto & ray : rank_0_rays)
253  {
254  const auto find = ray_map.find(ray->id());
255  if (find == ray_map.end())
256  mooseError("A Ray was found on rank ",
257  _pid,
258  " with an ID that does not exist on rank 0.",
259  error_suffix,
260  "\n\n",
261  ray->getInfo());
262 
263  const Ray * root_ray = find->second;
264  if (*root_ray != *ray)
265  {
266  mooseError("A Ray was found on rank ",
267  _pid,
268  " that does not exist on rank 0.",
269  error_suffix,
270  "\n\nLocal ray:\n\n",
271  ray->getInfo(),
272  "\n\nRank 0 ray:\n\n",
273  root_ray->getInfo());
274  }
275  }
276  }
277 }
ParallelStudy< std::shared_ptr< Ray >, Ray > * parallelStudy()
The underlying parallel study: used for the context for calling the packed range routines.
virtual void generateRays() override
Subclasses should override this to determine how to generate Rays.
void verifyUniqueRayIDs(const std::vector< std::shared_ptr< Ray >>::const_iterator begin, const std::vector< std::shared_ptr< Ray >>::const_iterator end, const bool global, const std::string &error_suffix) const
Verifies that the Rays in the given range have unique Ray IDs.
MessageTag get_unique_tag(int tagvalue=MessageTag::invalid_tag) const
std::string getInfo() const
Helper function for getting information about the Ray.
Definition: Ray.C:469
const Parallel::Communicator & comm() const
const Parallel::Communicator & _communicator
void send_packed_range(const unsigned int dest_processor_id, const Context *context, Iter range_begin, const Iter range_end, const MessageTag &tag=no_tag, std::size_t approx_buffer_size=1000000) const
void mooseWarning(Args &&... args) const
bool & _should_claim_rays
Whether or not we should call claimRays() on the next generateRays() (restartable) ...
uint8_t processor_id_type
processor_id_type n_processors() const
bool verifyRays() const
Whether or not to verify if Rays have valid information before being traced.
const bool _define_rays_replicated
Whether or not the Rays filled into _rays are replicated across all processors.
virtual void meshChanged() override
void receive_packed_range(const unsigned int dest_processor_id, Context *context, OutputIter out, const T *output_type, const MessageTag &tag=any_tag) const
bool & _should_define_rays
Whether or not we should call defineRays() on the next generateRays() Can be set to true in derived c...
RepeatableRayStudyBase(const InputParameters &parameters)
void reserveRayBuffer(const std::size_t size)
Reserve size entires in the Ray buffer.
static InputParameters validParams()
Basic datastructure for a ray that will traverse the mesh.
Definition: Ray.h:56
virtual void meshChanged() override
std::vector< std::shared_ptr< Ray > > & _local_rays
Storage for all of the Rays this processor is responsible for (restartable)
void claim()
Claim the Rays.
Definition: ClaimRays.C:42
void verifyReplicatedRays()
Verifies that the Rays in _rays are replicated across processors.
void mooseError(Args &&... args) const
std::vector< std::shared_ptr< Ray > > & _rays
Vector of Rays that the user will fill into in defineRays() (restartable)
const processor_id_type _pid
The rank of this processor (this actually takes time to lookup - so just do it once) ...
void moveRayToBuffer(std::shared_ptr< Ray > &ray)
Moves a ray to the buffer to be traced during generateRays().
ClaimRays _claim_rays
The object used to claim Rays.
const bool _claim_after_define_rays
Whether or not Rays need to be claimed after defineRays()
static InputParameters validParams()
std::shared_ptr< Ray > acquireCopiedRay(const Ray &ray)
Acquires a Ray that that is copied from another Ray within generateRays().
virtual void defineRays()=0
Entry point for the user to create Rays.
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...