https://mooseframework.inl.gov
ClaimRays.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 "ClaimRays.h"
11 
12 // Local includes
13 #include "RayTracingStudy.h"
14 
15 // libMesh includes
16 #include "libmesh/elem.h"
17 #include "libmesh/parallel_algebra.h"
18 #include "libmesh/parallel_sync.h"
19 #include "libmesh/enum_point_locator_type.h"
20 #include "libmesh/mesh_tools.h"
21 
22 using namespace libMesh;
23 
25  const std::vector<std::shared_ptr<Ray>> & rays,
26  std::vector<std::shared_ptr<Ray>> & local_rays,
27  const bool do_exchange)
28  : ParallelObject(study.comm()),
29  MeshChangedInterface(study.parameters()),
30  _mesh(study.mesh()),
31  _pid(comm().rank()),
32  _do_exchange(do_exchange),
33  _study(study),
34  _parallel_study(*_study.parallelStudy()),
35  _rays(rays),
36  _local_rays(local_rays),
37  _needs_init(true)
38 {
39 }
40 
41 void
43 {
44  if (_needs_init)
45  {
46  init();
47  _needs_init = false;
48  }
49 
50  preClaim();
51 
52  // Clear these as we're about to fill
53  _local_rays.clear();
54 
55  // Grab the point locator
56  _point_locator = PointLocatorBase::build(TREE_LOCAL_ELEMENTS, _mesh.getMesh());
57  _point_locator->enable_out_of_mesh_mode();
58 
59  // Exchange: filter Rays into processors that _may_ claim them
60  std::unordered_map<processor_id_type, std::vector<std::shared_ptr<Ray>>> rays_to_send;
61  if (_do_exchange)
62  for (processor_id_type pid = 0; pid < comm().size(); ++pid)
63  if (_pid != pid)
64  {
65  const BoundingBox & pid_bbox = inflatedBoundingBox(pid);
66  for (auto & ray : _rays)
67  if (pid_bbox.contains_point(ray->currentPoint()))
68  rays_to_send[pid].push_back(ray);
69  }
70 
71  // Functor for possibly claiming a vector of Rays
72  auto claim_functor =
73  [&](processor_id_type /* pid */, const std::vector<std::shared_ptr<Ray>> & rays)
74  {
75  for (auto & ray : rays)
76  possiblyClaim(ray);
77  };
78 
79  // Send the relevant Rays to everyone and then attempt to claim the ones that we receive
80  if (_do_exchange)
81  Parallel::push_parallel_packed_range(comm(), rays_to_send, &_parallel_study, claim_functor);
82 
83  // Attempt to claim the locally generated rays in _rays
84  claim_functor(_pid, _rays);
85 
86  // Verify the claiming if the study so desires
87  if (_study.verifyRays())
89 
90  postClaim();
91 }
92 
93 void
94 ClaimRays::possiblyClaim(const std::shared_ptr<Ray> & ray)
95 {
97 
98  const auto elem =
99  claimPoint(ray->currentPoint(), getID(ray), (*_point_locator)(ray->currentPoint()));
100  if (elem)
101  {
102  _local_rays.push_back(ray);
103  postClaimRay(_local_rays.back(), elem);
104  }
105 }
106 
107 const Elem *
108 ClaimRays::claimPoint(const Point & point, const RayID id, const Elem * elem)
109 {
110  if (elem)
111  {
112  // Looking for smallest (even ID Ray) or largest (odd ID Ray) elem id
113  const bool smallest = id % 2 == 0;
114 
115  // Start with the element we found, as it is a valid candidate
116  const Elem * extremum_elem = elem;
117 
118  // All point neighbors for this element
119  mooseAssert(_elem_point_neighbors.count(elem->id()), "Not in point neighbor map");
120  const auto & neighbors = _elem_point_neighbors.at(elem->id());
121 
122  // Find element that matches the extremum criteria
123  for (const auto & neighbor : neighbors)
124  {
125  mooseAssert(neighbor->active(), "Inactive neighbor");
126 
127  if ((smallest && neighbor->id() < extremum_elem->id()) || // satisfies
128  (!smallest && neighbor->id() > extremum_elem->id())) // ...one of the id checks
129  if (neighbor->contains_point(point)) // and also contains the point
130  extremum_elem = neighbor;
131  }
132 
133  // Claim the object if we own the extremum elem
134  if (extremum_elem->processor_id() == _pid)
135  {
136  mooseAssert(extremum_elem->active(), "Inactive element");
137  return extremum_elem;
138  }
139  }
140 
141  return nullptr;
142 }
143 
144 void
145 ClaimRays::postClaimRay(std::shared_ptr<Ray> & ray, const Elem * elem)
146 {
147  mooseAssert(_mesh.queryElemPtr(elem->id()) == elem, "Mesh doesn't contain elem");
148  mooseAssert(elem->active(), "Inactive element");
149 
150  // If the incoming side is set and is not incoming, or if it is not set at all, see
151  // if we can find an incoming side that is valid.
152  auto starting_incoming_side = RayTracingCommon::invalid_side;
153  if (!(!ray->invalidCurrentIncomingSide() &&
154  _study.elemSide(*elem, ray->currentIncomingSide()).contains_point(ray->currentPoint()) &&
155  _study.sideIsIncoming(elem, ray->currentIncomingSide(), ray->direction(), /* tid = */ 0)))
156  for (const auto s : elem->side_index_range())
157  if (_study.elemSide(*elem, s).contains_point(ray->currentPoint()) &&
158  _study.sideIsIncoming(elem, s, ray->direction(), /* tid = */ 0))
159  {
160  starting_incoming_side = s;
161  break;
162  }
163 
164  ray->setStart(ray->currentPoint(), elem, starting_incoming_side);
165 }
166 
167 void
169 {
172 }
173 
174 void
176 {
177  _needs_init = true;
178 }
179 
180 void
182 {
183  // Local bounding box
184  const auto bbox = MeshTools::create_local_bounding_box(_mesh.getMesh());
185 
186  // Gather the bounding boxes of all processors
187  std::vector<std::pair<Point, Point>> bb_points = {static_cast<std::pair<Point, Point>>(bbox)};
188  comm().allgather(bb_points, true);
189 
190  // Inflate the local bboxes by a bit and store
191  _inflated_bboxes.resize(comm().size());
192  for (processor_id_type pid = 0; pid < comm().size(); ++pid)
193  {
194  BoundingBox pid_bbox = static_cast<BoundingBox>(bb_points[pid]);
195  pid_bbox.scale(0.01);
196  _inflated_bboxes[pid] = pid_bbox;
197  }
198 }
199 
200 void
202 {
203  _elem_point_neighbors.clear();
204  const auto & node_to_elem_map = _mesh.nodeToElemMap();
205 
206  for (const auto & elem : _mesh.getMesh().active_element_ptr_range())
207  {
208  auto & fill = _elem_point_neighbors[elem->id()];
209  for (unsigned int v = 0; v < elem->n_vertices(); ++v)
210  {
211  const auto & node = elem->node_ptr(v);
212  for (const auto & neighbor_id : node_to_elem_map.at(node->id()))
213  {
214  if (neighbor_id == elem->id())
215  continue;
216 
217  const auto & neighbor = _mesh.elemPtr(neighbor_id);
218  if (std::count(fill.begin(), fill.end(), neighbor) == 0)
219  fill.emplace_back(neighbor);
220  }
221  }
222  }
223 }
224 
225 void
227 {
228  // NOTE for all of the following: we use char here in place of bool.
229  // This is because bool is not instantiated as a StandardType in
230  // TIMPI due to the fun of std::vector<bool>
231 
232  // Map from Ray ID -> whether or not it was generated (false) or
233  // claimed/possibly also generated (true)
234  std::map<RayID, char> local_map;
235  auto add_to_local_map =
236  [this, &local_map](const std::vector<std::shared_ptr<Ray>> & rays, const bool claimed_rays)
237  {
238  for (const auto & ray : rays)
239  {
240  const auto id = getID(ray);
241 
242  // Try to insert into the map
243  auto emplace_pair = local_map.emplace(id, claimed_rays);
244 
245  // If it already exists but has not been claimed yet, set it to being claimed
246  if (!emplace_pair.second && claimed_rays)
247  {
248  mooseAssert(!emplace_pair.first->second,
249  "Ray was claimed more than once on a single processor");
250  emplace_pair.first->second = true;
251  }
252  }
253  };
254 
255  // Build the local_map
256  add_to_local_map(_rays, false);
257  add_to_local_map(_local_rays, true);
258 
259  // Build the structure to send the local generation/claiming information to rank 0
260  std::map<processor_id_type, std::vector<std::pair<RayID, char>>> send_info;
261  if (local_map.size())
262  send_info.emplace(std::piecewise_construct,
263  std::forward_as_tuple(0),
264  std::forward_as_tuple(local_map.begin(), local_map.end()));
265 
266  // The mapping (filled on rank 0) from Ray ID -> (processor id, claiming status)
267  std::map<RayID, std::vector<std::pair<processor_id_type, char>>> global_map;
268 
269  // Functor for receiving the generation/claiming information
270  auto receive_functor = [&global_map](processor_id_type pid,
271  const std::vector<std::pair<RayID, char>> & id_claimed_pairs)
272  {
273  for (const auto & id_claimed_pair : id_claimed_pairs)
274  global_map[id_claimed_pair.first].emplace_back(pid, id_claimed_pair.second);
275  };
276 
277  // Send claiming information to rank 0
278  Parallel::push_parallel_vector_data(comm(), send_info, receive_functor);
279 
280  // Rank 0 will make sure everything looks good
281  if (_pid == 0)
282  for (const auto & id_pairs_pair : global_map)
283  {
284  const RayID id = id_pairs_pair.first;
285  const std::vector<std::pair<processor_id_type, char>> & pid_claimed_pairs =
286  id_pairs_pair.second;
287 
288  std::vector<processor_id_type> claimed_pids;
289  for (const auto & pid_claimed_pair : pid_claimed_pairs)
290  if (pid_claimed_pair.second)
291  claimed_pids.push_back(pid_claimed_pair.first);
292 
293  if (claimed_pids.size() == 0)
294  _study.mooseError("Failed to claim the Ray with ID ", id);
295  mooseAssert(claimed_pids.size() == 1, "Ray was claimed on multiple processors");
296  }
297 }
static const unsigned short invalid_side
Identifier for an invalid side index.
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
bool _needs_init
Whether or not an init is needed (bounding boxes, neighbors)
Definition: ClaimRays.h:171
unsigned long int RayID
Type for a Ray&#39;s ID.
Definition: Ray.h:43
virtual Elem * elemPtr(const dof_id_type i)
bool contains_point(const Point &) const
IntRange< unsigned short > side_index_range() const
ClaimRays(RayTracingStudy &study, const std::vector< std::shared_ptr< Ray >> &rays, std::vector< std::shared_ptr< Ray >> &local_rays, const bool do_exchange)
Constructor.
Definition: ClaimRays.C:24
void verifyClaiming()
Verifies that the claiming process succeeded.
Definition: ClaimRays.C:226
MeshBase & mesh
const Parallel::Communicator & comm() const
virtual void postClaimRay(std::shared_ptr< Ray > &ray, const Elem *elem)
Entry point for acting on a Ray after it is claimed.
Definition: ClaimRays.C:145
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
ParallelStudy< std::shared_ptr< Ray >, Ray > & _parallel_study
The ParallelStudy, used as the context for communicating rays.
Definition: ClaimRays.h:120
virtual void postClaim()
Entry point after claim()
Definition: ClaimRays.h:78
const processor_id_type _pid
This processor ID.
Definition: ClaimRays.h:112
void buildPointNeighbors()
Build the map of elements to all of their point neighbors.
Definition: ClaimRays.C:201
const std::vector< std::shared_ptr< Ray > > & _rays
The Rays that need to be searched to possibly claimed.
Definition: ClaimRays.h:157
virtual Elem * queryElemPtr(const dof_id_type i)
processor_id_type size() const
uint8_t processor_id_type
bool verifyRays() const
Whether or not to verify if Rays have valid information before being traced.
std::vector< libMesh::BoundingBox > _inflated_bboxes
The inflated bounding boxes for all processors.
Definition: ClaimRays.h:165
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
dof_id_type id() const
MeshBase & getMesh()
MooseMesh & _mesh
The mesh.
Definition: ClaimRays.h:110
std::vector< std::shared_ptr< Ray > > & _local_rays
The local Rays that are claimed.
Definition: ClaimRays.h:159
RayTracingStudy & _study
The RayTracingStudy.
Definition: ClaimRays.h:118
virtual RayID getID(const std::shared_ptr< Ray > &ray) const
Gets an ID associated with the Ray for claiming purposes.
Definition: ClaimRays.h:99
void buildBoundingBoxes()
Builds the bounding boxes (_inflated_bboxes).
Definition: ClaimRays.C:181
void claim()
Claim the Rays.
Definition: ClaimRays.C:42
void possiblyClaim(const std::shared_ptr< Ray > &obj)
Possibly claim a Ray.
Definition: ClaimRays.C:94
const bool _do_exchange
Whether or not the Rays need to be initially exchanged.
Definition: ClaimRays.h:115
virtual void preClaim()
Entry point before claim()
Definition: ClaimRays.h:74
virtual void meshChanged() override
Call on mesh changes to reinit the necessary data structures.
Definition: ClaimRays.C:175
static const std::string v
Definition: NS.h:84
std::unordered_map< dof_id_type, std::vector< const Elem * > > _elem_point_neighbors
Map of point neighbors for each element.
Definition: ClaimRays.h:168
const libMesh::Elem & elemSide(const libMesh::Elem &elem, const unsigned int s, const THREAD_ID tid=0)
Get an element&#39;s side pointer without excessive memory allocation.
const libMesh::BoundingBox & inflatedBoundingBox(const processor_id_type pid) const
Get the inflated bounding box for rank .
Definition: ClaimRays.h:104
TREE_LOCAL_ELEMENTS
void mooseError(Args &&... args) const
std::unique_ptr< libMesh::PointLocatorBase > _point_locator
The point locator.
Definition: ClaimRays.h:162
void scale(const Real factor)
bool active() const
processor_id_type processor_id() const
bool sideIsIncoming(const Elem *const elem, const unsigned short side, const Point &direction, const THREAD_ID tid)
Whether or not side is incoming on element elem in direction direction.
const Elem * claimPoint(const Point &point, const RayID id, const Elem *elem)
Try to claim a spatial point.
Definition: ClaimRays.C:108
const std::map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
virtual void prePossiblyClaimRay(const std::shared_ptr< Ray > &)
Entry point before possibly claiming a Ray.
Definition: ClaimRays.h:82
virtual void init()
Initialize the object.
Definition: ClaimRays.C:168
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...