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