Line data Source code
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 "RayTracingStudy.h"
11 :
12 : // Local Includes
13 : #include "AuxRayKernel.h"
14 : #include "RayBoundaryConditionBase.h"
15 : #include "RayKernel.h"
16 : #include "TraceRay.h"
17 : #include "TraceRayTools.h"
18 :
19 : // MOOSE Includes
20 : #include "AuxiliarySystem.h"
21 : #include "Assembly.h"
22 : #include "NonlinearSystemBase.h"
23 :
24 : // libMesh Includes
25 : #include "libmesh/enum_to_string.h"
26 : #include "libmesh/mesh_tools.h"
27 : #include "libmesh/parallel_sync.h"
28 : #include "libmesh/remote_elem.h"
29 :
30 : using namespace libMesh;
31 :
32 : InputParameters
33 7576 : RayTracingStudy::validParams()
34 : {
35 7576 : auto params = GeneralUserObject::validParams();
36 :
37 : // Parameters for the execution of the rays
38 7576 : params += ParallelRayStudy::validParams();
39 :
40 22728 : params.addRangeCheckedParam<Real>("ray_distance",
41 15152 : std::numeric_limits<Real>::max(),
42 : "ray_distance > 0",
43 : "The maximum distance all Rays can travel");
44 :
45 15152 : params.addParam<bool>(
46 15152 : "tolerate_failure", false, "Whether or not to tolerate a ray tracing failure");
47 :
48 15152 : MooseEnum work_buffers("lifo circular", "circular");
49 15152 : params.addParam<MooseEnum>("work_buffer_type", work_buffers, "The work buffer type to use");
50 :
51 15152 : params.addParam<bool>(
52 15152 : "ray_kernel_coverage_check", true, "Whether or not to perform coverage checks on RayKernels");
53 15152 : params.addParam<bool>("warn_non_planar",
54 15152 : true,
55 : "Whether or not to produce a warning if any element faces are non-planar.");
56 :
57 15152 : params.addParam<bool>(
58 : "always_cache_traces",
59 15152 : false,
60 : "Whether or not to cache the Ray traces on every execution, primarily for use in output. "
61 : "Warning: this can get expensive very quick with a large number of rays!");
62 15152 : params.addParam<bool>("data_on_cache_traces",
63 15152 : false,
64 : "Whether or not to also cache the Ray's data when caching its traces");
65 15152 : params.addParam<bool>("aux_data_on_cache_traces",
66 15152 : false,
67 : "Whether or not to also cache the Ray's aux data when caching its traces");
68 15152 : params.addParam<bool>(
69 : "segments_on_cache_traces",
70 15152 : true,
71 : "Whether or not to cache individual segments when trace caching is enabled. If false, we "
72 : "will instead cache a segment for each part of the trace where the direction is the same. "
73 : "This minimizes the number of segments requied to represent the Ray's path, but removes the "
74 : "ability to show Ray field data on each segment through an element.");
75 :
76 15152 : params.addParam<bool>("use_internal_sidesets",
77 15152 : false,
78 : "Whether or not to use internal sidesets for RayBCs in ray tracing");
79 :
80 15152 : params.addParam<bool>("warn_subdomain_hmax",
81 15152 : true,
82 : "Whether or not to warn if the approximated hmax (constant on subdomain) "
83 : "varies significantly for an element");
84 :
85 15152 : params.addParam<bool>(
86 : "verify_rays",
87 15152 : true,
88 : "Whether or not to verify the generated Rays. This includes checking their "
89 : "starting information and the uniqueness of Rays before and after execution. This is also "
90 : "used by derived studies for more specific verification.");
91 15152 : params.addParam<bool>("verify_trace_intersections",
92 15152 : true,
93 : "Whether or not to verify the trace intersections in devel and dbg modes. "
94 : "Trace intersections are not verified regardless of this parameter in "
95 : "optimized modes (opt, oprof).");
96 :
97 15152 : params.addParam<bool>("allow_other_flags_with_prekernels",
98 15152 : false,
99 : "Whether or not to allow the list of execution flags to have PRE_KERNELS "
100 : "mixed with other flags. If this parameter is not set then if PRE_KERNELS "
101 : "is provided it must be the only execution flag.");
102 :
103 7576 : ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
104 7576 : exec_enum.addAvailableFlags(EXEC_PRE_KERNELS);
105 :
106 15152 : params.addParamNamesToGroup(
107 : "always_cache_traces data_on_cache_traces aux_data_on_cache_traces segments_on_cache_traces",
108 : "Trace cache");
109 15152 : params.addParamNamesToGroup("warn_non_planar warn_subdomain_hmax", "Tracing Warnings");
110 15152 : params.addParamNamesToGroup("ray_kernel_coverage_check verify_rays verify_trace_intersections",
111 : "Checks and verifications");
112 :
113 : // Whether or not each Ray must be registered using the registerRay() API
114 7576 : params.addPrivateParam<bool>("_use_ray_registration", true);
115 : // Whether or not to bank Rays on completion
116 7576 : params.addPrivateParam<bool>("_bank_rays_on_completion", true);
117 : /// Whether or not subdomain setup is dependent on the Ray
118 15152 : params.addPrivateParam<bool>("_ray_dependent_subdomain_setup", true);
119 :
120 : // Add a point neighbor relationship manager
121 15152 : params.addRelationshipManager("ElementPointNeighborLayers",
122 : Moose::RelationshipManagerType::GEOMETRIC |
123 : Moose::RelationshipManagerType::ALGEBRAIC,
124 11285 : [](const InputParameters &, InputParameters & rm_params)
125 11285 : { rm_params.set<unsigned short>("layers") = 1; });
126 :
127 7576 : return params;
128 7576 : }
129 :
130 3827 : RayTracingStudy::RayTracingStudy(const InputParameters & parameters)
131 : : GeneralUserObject(parameters),
132 3827 : _mesh(_fe_problem.mesh()),
133 3827 : _comm(_mesh.comm()),
134 3827 : _pid(_comm.rank()),
135 :
136 7654 : _ray_kernel_coverage_check(getParam<bool>("ray_kernel_coverage_check")),
137 7654 : _warn_non_planar(getParam<bool>("warn_non_planar")),
138 7654 : _use_ray_registration(getParam<bool>("_use_ray_registration")),
139 7654 : _use_internal_sidesets(getParam<bool>("use_internal_sidesets")),
140 7654 : _tolerate_failure(getParam<bool>("tolerate_failure")),
141 7654 : _bank_rays_on_completion(getParam<bool>("_bank_rays_on_completion")),
142 7654 : _ray_dependent_subdomain_setup(getParam<bool>("_ray_dependent_subdomain_setup")),
143 :
144 7654 : _always_cache_traces(getParam<bool>("always_cache_traces")),
145 7654 : _data_on_cache_traces(getParam<bool>("data_on_cache_traces")),
146 7654 : _aux_data_on_cache_traces(getParam<bool>("aux_data_on_cache_traces")),
147 7654 : _segments_on_cache_traces(getParam<bool>("segments_on_cache_traces")),
148 7654 : _ray_max_distance(getParam<Real>("ray_distance")),
149 7654 : _verify_rays(getParam<bool>("verify_rays")),
150 : #ifndef NDEBUG
151 : _verify_trace_intersections(getParam<bool>("verify_trace_intersections")),
152 : #endif
153 :
154 3827 : _threaded_elem_side_builders(libMesh::n_threads()),
155 :
156 3827 : _registered_ray_map(
157 3827 : declareRestartableData<std::unordered_map<std::string, RayID>>("registered_ray_map")),
158 3827 : _reverse_registered_ray_map(
159 7654 : declareRestartableData<std::vector<std::string>>("reverse_registered_ray_map")),
160 :
161 3827 : _threaded_cached_traces(libMesh::n_threads()),
162 :
163 3827 : _num_cached(libMesh::n_threads(), 0),
164 :
165 3827 : _has_non_planar_sides(true),
166 3827 : _has_same_level_active_elems(sameLevelActiveElems()),
167 :
168 3827 : _b_box(MeshTools::create_nodal_bounding_box(_mesh.getMesh())),
169 3827 : _domain_max_length(1.01 * (_b_box.max() - _b_box.min()).norm()),
170 3827 : _total_volume(computeTotalVolume()),
171 :
172 3827 : _threaded_cache_ray_kernel(libMesh::n_threads()),
173 3827 : _threaded_cache_ray_bc(libMesh::n_threads()),
174 3827 : _threaded_ray_object_registration(libMesh::n_threads()),
175 3827 : _threaded_current_ray_kernels(libMesh::n_threads()),
176 3827 : _threaded_trace_ray(libMesh::n_threads()),
177 3827 : _threaded_fe_face(libMesh::n_threads()),
178 3827 : _threaded_q_face(libMesh::n_threads()),
179 3827 : _threaded_cached_normals(libMesh::n_threads()),
180 3827 : _threaded_next_ray_id(libMesh::n_threads()),
181 :
182 3827 : _parallel_ray_study(std::make_unique<ParallelRayStudy>(*this, _threaded_trace_ray)),
183 :
184 3827 : _local_trace_ray_results(TraceRay::FAILED_TRACES + 1, 0),
185 :
186 3827 : _called_initial_setup(false),
187 :
188 15308 : _elem_index_helper(_mesh.getMesh(), name() + "_elem_index")
189 : {
190 : // Initialize a tracing object for each thread
191 8378 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
192 : {
193 : // Initialize a tracing object for each thread
194 9102 : _threaded_trace_ray[tid] = std::make_shared<TraceRay>(*this, tid);
195 :
196 : // Setup the face FEs for normal computation on the fly
197 9102 : _threaded_fe_face[tid] = FEBase::build(_mesh.dimension(), FEType(CONSTANT, MONOMIAL));
198 9102 : _threaded_q_face[tid] = QBase::build(QGAUSS, _mesh.dimension() - 1, CONSTANT);
199 : _threaded_fe_face[tid]->attach_quadrature_rule(_threaded_q_face[tid].get());
200 : _threaded_fe_face[tid]->get_normals();
201 : }
202 :
203 : // Evaluating on residual and Jacobian evaluation
204 3827 : if (_execute_enum.isValueSet(EXEC_PRE_KERNELS))
205 : {
206 534 : if (!getParam<bool>("allow_other_flags_with_prekernels") && _execute_enum.size() > 1)
207 2 : paramError("execute_on",
208 : "PRE_KERNELS cannot be mixed with any other execution flag.\nThat is, you cannot "
209 : "currently "
210 : "mix RayKernels that contribute to the Jacobian/residual with those that do not.");
211 :
212 176 : if (_app.useEigenvalue())
213 2 : mooseError("Execution on residual and Jacobian evaluation (execute_on = PRE_KERNELS)\n",
214 : "is not supported for an eigenvalue solve.");
215 : }
216 :
217 3823 : resetUniqueRayIDs();
218 3823 : resetReplicatedRayIDs();
219 :
220 : // Scale the bounding box for loose checking
221 : _loose_b_box = _b_box;
222 3823 : _loose_b_box.scale(TOLERANCE * TOLERANCE);
223 3823 : }
224 :
225 : void
226 3709 : RayTracingStudy::initialSetup()
227 : {
228 : // Keep track of initialSetup call to avoid registration of various things
229 3709 : _called_initial_setup = true;
230 :
231 : // Sets up a local index for each elem this proc knows about
232 3709 : localElemIndexSetup();
233 :
234 : // Check for RayKernel coverage
235 3709 : coverageChecks();
236 :
237 : // Make sure the dependencies exist, if any
238 3707 : dependencyChecks();
239 :
240 : // Check for traceable element types
241 3703 : traceableMeshChecks();
242 :
243 : // Setup for internal sidesets
244 3701 : internalSidesetSetup();
245 :
246 3697 : nonPlanarSideSetup();
247 :
248 : // Setup approximate hmax for each subdomain
249 3695 : subdomainHMaxSetup();
250 :
251 : // Call initial setup on all of the objects
252 12082 : for (auto & rto : getRayTracingObjects())
253 12082 : rto->initialSetup();
254 :
255 : // Check for proper exec flags with RayKernels
256 : std::vector<RayKernelBase *> ray_kernels;
257 3693 : getRayKernels(ray_kernels, 0);
258 6949 : for (const auto & rkb : ray_kernels)
259 3258 : if (dynamic_cast<RayKernel *>(rkb) && !_execute_enum.isValueSet(EXEC_PRE_KERNELS))
260 2 : mooseError("This study has RayKernel objects that contribute to residuals and Jacobians.",
261 : "\nIn this case, the study must use the execute_on = PRE_KERNELS");
262 :
263 : // Build 1D quadrature rule for along a segment
264 : _segment_qrule =
265 7382 : QBase::build(QGAUSS, 1, _fe_problem.getSystemBase(_sys.number()).getMinQuadratureOrder());
266 3691 : }
267 :
268 : void
269 4708 : RayTracingStudy::residualSetup()
270 : {
271 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
272 : mooseAssert(_num_cached[tid] == 0, "Cached residuals/Jacobians not empty");
273 :
274 13743 : for (auto & rto : getRayTracingObjects())
275 13743 : rto->residualSetup();
276 4708 : }
277 :
278 : void
279 300 : RayTracingStudy::jacobianSetup()
280 : {
281 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
282 : mooseAssert(_num_cached[tid] == 0, "Cached residuals/Jacobians not empty");
283 :
284 1148 : for (auto & rto : getRayTracingObjects())
285 1148 : rto->jacobianSetup();
286 300 : }
287 :
288 : void
289 3246 : RayTracingStudy::timestepSetup()
290 : {
291 10427 : for (auto & rto : getRayTracingObjects())
292 10427 : rto->timestepSetup();
293 3246 : }
294 :
295 : void
296 228 : RayTracingStudy::meshChanged()
297 : {
298 228 : localElemIndexSetup();
299 228 : internalSidesetSetup();
300 228 : nonPlanarSideSetup();
301 228 : subdomainHMaxSetup();
302 :
303 228 : _has_same_level_active_elems = sameLevelActiveElems();
304 :
305 506 : for (const auto & trace_ray : _threaded_trace_ray)
306 278 : trace_ray->meshChanged();
307 228 : }
308 :
309 : void
310 8023 : RayTracingStudy::execute()
311 : {
312 8023 : executeStudy();
313 7923 : }
314 :
315 : void
316 3709 : RayTracingStudy::coverageChecks()
317 : {
318 : // Check for coverage of RayKernels on domain
319 3709 : if (_ray_kernel_coverage_check)
320 : {
321 : std::vector<RayKernelBase *> ray_kernels;
322 2900 : getRayKernels(ray_kernels, 0);
323 :
324 : std::set<SubdomainID> ray_kernel_blocks;
325 6146 : for (const auto & rk : ray_kernels)
326 6492 : ray_kernel_blocks.insert(rk->blockIDs().begin(), rk->blockIDs().end());
327 :
328 : std::set<SubdomainID> missing;
329 5800 : std::set_difference(_mesh.meshSubdomains().begin(),
330 2900 : _mesh.meshSubdomains().end(),
331 : ray_kernel_blocks.begin(),
332 : ray_kernel_blocks.end(),
333 : std::inserter(missing, missing.begin()));
334 :
335 2900 : if (!missing.empty() && !ray_kernel_blocks.count(Moose::ANY_BLOCK_ID))
336 : {
337 2 : std::ostringstream error;
338 2 : error << "Subdomains { ";
339 2 : std::copy(missing.begin(), missing.end(), std::ostream_iterator<SubdomainID>(error, " "));
340 2 : error << "} do not have RayKernels defined!";
341 :
342 2 : mooseError(error.str());
343 0 : }
344 2898 : }
345 3707 : }
346 :
347 : void
348 3707 : RayTracingStudy::dependencyChecks()
349 : {
350 : std::vector<RayTracingObject *> ray_tracing_objects;
351 :
352 3707 : getRayKernels(ray_tracing_objects, 0);
353 3707 : verifyDependenciesExist(ray_tracing_objects);
354 :
355 3705 : getRayBCs(ray_tracing_objects, 0);
356 3705 : verifyDependenciesExist(ray_tracing_objects);
357 3703 : }
358 :
359 : void
360 7412 : RayTracingStudy::verifyDependenciesExist(const std::vector<RayTracingObject *> & rtos)
361 : {
362 14576 : for (const auto & rto : rtos)
363 7288 : for (const auto & dep_name : rto->getRequestedItems())
364 : {
365 : bool found = false;
366 256 : for (const auto & rto_search : rtos)
367 252 : if (rto_search->name() == dep_name)
368 : {
369 : found = true;
370 : break;
371 : }
372 :
373 124 : if (!found)
374 4 : rto->paramError("depends_on", "The ", rto->getBase(), " '", dep_name, "' does not exist");
375 : }
376 7408 : }
377 :
378 : void
379 3703 : RayTracingStudy::traceableMeshChecks()
380 : {
381 :
382 466239 : for (const auto & elem : *_mesh.getActiveLocalElementRange())
383 : {
384 462538 : if (_fe_problem.adaptivity().isOn())
385 : {
386 5670 : if (!TraceRayTools::isAdaptivityTraceableElem(elem))
387 2 : mooseError("Element type ",
388 2 : Utility::enum_to_string(elem->type()),
389 : " is not supported in ray tracing with adaptivity");
390 : }
391 456868 : else if (!TraceRayTools::isTraceableElem(elem))
392 0 : mooseError("Element type ",
393 0 : Utility::enum_to_string(elem->type()),
394 : " is not supported in ray tracing");
395 : }
396 3701 : }
397 :
398 : void
399 3937 : RayTracingStudy::localElemIndexSetup()
400 : {
401 : // TODO: We could probably minimize this to local active elements followed by
402 : // boundary point neighbors, but if using distibuted mesh it really shouldn't matter
403 3937 : _elem_index_helper.initialize(_mesh.getMesh().active_element_ptr_range());
404 3937 : }
405 :
406 : void
407 3929 : RayTracingStudy::internalSidesetSetup()
408 : {
409 : // Even if we have _use_internal_sidesets == false, we will make sure the user didn't add RayBCs
410 : // on internal boundaries
411 :
412 : // Clear the data structures and size the map based on the elements that we know about
413 : _internal_sidesets.clear();
414 3929 : _internal_sidesets_map.clear();
415 3929 : _internal_sidesets_map.resize(_elem_index_helper.maxIndex() + 1);
416 :
417 : // First, we are going to store all elements with internal sidesets (if any) that have active
418 : // RayBCs on them as elem -> vector of (side, vector of boundary ids)
419 287808 : for (const auto & bnd_elem : *_mesh.getBoundaryElementRange())
420 : {
421 283881 : Elem * elem = bnd_elem->_elem;
422 283881 : const unsigned int side = bnd_elem->_side;
423 283881 : const auto bnd_id = bnd_elem->_bnd_id;
424 :
425 : // Not internal
426 : const Elem * const neighbor = elem->neighbor_ptr(side);
427 283881 : if (!neighbor || neighbor == remote_elem)
428 276718 : continue;
429 :
430 : // No RayBCs on this sideset
431 : std::vector<RayBoundaryConditionBase *> result;
432 7163 : getRayBCs(result, bnd_id, 0);
433 7163 : if (result.empty())
434 : continue;
435 :
436 7163 : if (neighbor->subdomain_id() == elem->subdomain_id())
437 2 : mooseError("RayBCs exist on internal sidesets that are not bounded by a different",
438 : "\nsubdomain on each side.",
439 : "\n\nIn order to use RayBCs on internal sidesets, said sidesets must have",
440 : "\na different subdomain on each side.");
441 :
442 : // Mark that this boundary is an internal sideset with RayBC(s)
443 7161 : _internal_sidesets.insert(bnd_id);
444 :
445 : // Get elem's entry in the internal sidset data structure
446 : const auto index = _elem_index_helper.getIndex(elem);
447 : auto & entry = _internal_sidesets_map[index];
448 :
449 : // Initialize this elem's sides if they have not been already
450 7161 : if (entry.empty())
451 5864 : entry.resize(elem->n_sides(), std::vector<BoundaryID>());
452 :
453 : // Add the internal boundary to the side entry
454 7161 : entry[side].push_back(bnd_id);
455 7161 : }
456 :
457 3927 : if (!_use_internal_sidesets && _internal_sidesets.size())
458 2 : mooseError("RayBCs are defined on internal sidesets, but the study is not set to use ",
459 : "internal sidesets during tracing.",
460 : "\n\nSet the parameter use_internal_sidesets = true to enable this capability.");
461 3925 : }
462 :
463 : void
464 3925 : RayTracingStudy::nonPlanarSideSetup()
465 : {
466 3925 : _has_non_planar_sides = false;
467 3925 : bool warned = !_warn_non_planar;
468 :
469 : // Nothing to do here for 2D or 1D
470 3925 : if (_mesh.dimension() != 3)
471 : return;
472 :
473 : // Clear the data structure and size it based on the elements that we know about
474 1590 : _non_planar_sides.clear();
475 1590 : _non_planar_sides.resize(_elem_index_helper.maxIndex() + 1);
476 :
477 1840841 : for (const Elem * elem : _mesh.getMesh().active_element_ptr_range())
478 : {
479 : const auto index = _elem_index_helper.getIndex(elem);
480 : auto & entry = _non_planar_sides[index];
481 612555 : entry.resize(elem->n_sides(), 0);
482 :
483 3467221 : for (const auto s : elem->side_index_range())
484 : {
485 2854668 : const auto & side = elemSide(*elem, s);
486 2854668 : if (side.n_vertices() < 4)
487 2076172 : continue;
488 :
489 778496 : if (!side.has_affine_map())
490 : {
491 11466 : entry[s] = 1;
492 11466 : _has_non_planar_sides = true;
493 :
494 11466 : if (!warned)
495 : {
496 2 : mooseWarning("The mesh contains non-planar faces.\n\n",
497 : "Ray tracing on non-planar faces is an approximation and may fail.\n\n",
498 : "Use at your own risk! You can disable this warning by setting the\n",
499 : "parameter 'warn_non_planar' to false.");
500 : warned = true;
501 : }
502 : }
503 : }
504 1588 : }
505 : }
506 :
507 : void
508 3923 : RayTracingStudy::subdomainHMaxSetup()
509 : {
510 : // Setup map with subdomain keys
511 : _subdomain_hmax.clear();
512 8568 : for (const auto subdomain_id : _mesh.meshSubdomains())
513 4645 : _subdomain_hmax[subdomain_id] = std::numeric_limits<Real>::min();
514 :
515 : // Set local max for each subdomain
516 474177 : for (const auto & elem : *_mesh.getActiveLocalElementRange())
517 : {
518 470254 : auto & entry = _subdomain_hmax.at(elem->subdomain_id());
519 475378 : entry = std::max(entry, elem->hmax());
520 : }
521 :
522 : // Accumulate global max for each subdomain
523 3923 : _communicator.max(_subdomain_hmax);
524 :
525 7846 : if (getParam<bool>("warn_subdomain_hmax"))
526 : {
527 3923 : const auto warn_prefix = type() + " '" + name() + "': ";
528 3923 : const auto warn_suffix =
529 : "\n\nRay tracing uses an approximate element size for each subdomain to scale the\n"
530 : "tolerances used in computing ray intersections. This warning suggests that the\n"
531 : "approximate element size is not a good approximation. This is likely due to poor\n"
532 : "element aspect ratios.\n\n"
533 : "This warning is only output for the first element affected.\n"
534 : "To disable this warning, set warn_subdomain_hmax = false.\n";
535 :
536 474175 : for (const auto & elem : *_mesh.getActiveLocalElementRange())
537 : {
538 470254 : const auto hmin = elem->hmin();
539 470254 : const auto hmax = elem->hmax();
540 470254 : const auto max_hmax = subdomainHmax(elem->subdomain_id());
541 :
542 470254 : const auto hmax_rel = hmax / max_hmax;
543 470254 : if (hmax_rel < 1.e-2 || hmax_rel > 1.e2)
544 0 : mooseDoOnce(mooseWarning(warn_prefix,
545 : "Element hmax varies significantly from subdomain hmax.\n",
546 : warn_suffix,
547 : "First element affected:\n",
548 : Moose::stringify(*elem)););
549 :
550 470254 : const auto h_rel = max_hmax / hmin;
551 470254 : if (h_rel > 1.e2)
552 2 : mooseDoOnce(mooseWarning(warn_prefix,
553 : "Element hmin varies significantly from subdomain hmax.\n",
554 : warn_suffix,
555 : "First element affected:\n",
556 : Moose::stringify(*elem)););
557 : }
558 : }
559 3921 : }
560 :
561 : void
562 7957 : RayTracingStudy::registeredRaySetup()
563 : {
564 : // First, clear the objects associated with each Ray on each thread
565 7957 : const auto num_rays = _registered_ray_map.size();
566 18252 : for (auto & entry : _threaded_ray_object_registration)
567 : {
568 10295 : entry.clear();
569 10295 : entry.resize(num_rays);
570 : }
571 :
572 7957 : const auto rtos = getRayTracingObjects();
573 :
574 7957 : if (_use_ray_registration)
575 : {
576 : // All of the registered ray names - used when a RayTracingObject did not specify
577 : // any Rays so it should be associated with all Rays.
578 : std::vector<std::string> all_ray_names;
579 5004 : all_ray_names.reserve(_registered_ray_map.size());
580 16562 : for (const auto & pair : _registered_ray_map)
581 11558 : all_ray_names.push_back(pair.first);
582 :
583 13930 : for (auto & rto : rtos)
584 : {
585 : // The Ray names associated with this RayTracingObject
586 8928 : const auto & ray_names = rto->parameters().get<std::vector<std::string>>("rays");
587 : // The registration for RayTracingObjects for the thread rto is on
588 8928 : const auto tid = rto->parameters().get<THREAD_ID>("_tid");
589 8928 : auto & registration = _threaded_ray_object_registration[tid];
590 :
591 : // Register each Ray for this object in the registration
592 28400 : for (const auto & ray_name : (ray_names.empty() ? all_ray_names : ray_names))
593 : {
594 17025 : const auto id = registeredRayID(ray_name, /* graceful = */ true);
595 17025 : if (ray_names.size() && id == Ray::INVALID_RAY_ID)
596 2 : rto->paramError(
597 2 : "rays", "Supplied ray '", ray_name, "' is not a registered Ray in ", typeAndName());
598 17023 : registration[id].insert(rto);
599 : }
600 : }
601 5002 : }
602 : // Not using Ray registration
603 : else
604 : {
605 9489 : for (const auto & rto : rtos)
606 6538 : if (rto->parameters().get<std::vector<std::string>>("rays").size())
607 2 : rto->paramError(
608 : "rays",
609 : "Rays cannot be supplied when the study does not require Ray registration.\n\n",
610 : type(),
611 : " does not require Ray registration.");
612 : }
613 7953 : }
614 :
615 : void
616 8023 : RayTracingStudy::zeroAuxVariables()
617 : {
618 : std::set<std::string> vars_to_be_zeroed;
619 : std::vector<RayKernelBase *> ray_kernels;
620 8023 : getRayKernels(ray_kernels, 0);
621 16431 : for (auto & rk : ray_kernels)
622 : {
623 8408 : AuxRayKernel * aux_rk = dynamic_cast<AuxRayKernel *>(rk);
624 8408 : if (aux_rk)
625 70 : vars_to_be_zeroed.insert(aux_rk->variable().name());
626 : }
627 :
628 : std::vector<std::string> vars_to_be_zeroed_vec(vars_to_be_zeroed.begin(),
629 8023 : vars_to_be_zeroed.end());
630 8023 : _fe_problem.getAuxiliarySystem().zeroVariables(vars_to_be_zeroed_vec);
631 16046 : }
632 :
633 : void
634 4955206 : RayTracingStudy::segmentSubdomainSetup(const SubdomainID subdomain,
635 : const THREAD_ID tid,
636 : const RayID ray_id)
637 : {
638 : mooseAssert(currentlyPropagating(), "Should not call while not propagating");
639 :
640 : // Call subdomain setup on FE
641 4955206 : _fe_problem.subdomainSetup(subdomain, tid);
642 :
643 : std::set<MooseVariableFEBase *> needed_moose_vars;
644 : std::unordered_set<unsigned int> needed_mat_props;
645 :
646 : // Get RayKernels and their dependencies and call subdomain setup
647 4955206 : getRayKernels(_threaded_current_ray_kernels[tid], subdomain, tid, ray_id);
648 9917397 : for (auto & rkb : _threaded_current_ray_kernels[tid])
649 : {
650 4962191 : rkb->subdomainSetup();
651 :
652 4962191 : const auto & mv_deps = rkb->getMooseVariableDependencies();
653 4962191 : needed_moose_vars.insert(mv_deps.begin(), mv_deps.end());
654 :
655 4962191 : const auto & mp_deps = rkb->getMatPropDependencies();
656 4962191 : needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
657 : }
658 :
659 : // Prepare aux vars
660 4992976 : for (auto & var : needed_moose_vars)
661 37770 : if (var->kind() == Moose::VarKindType::VAR_AUXILIARY)
662 8306 : var->prepareAux();
663 :
664 4955206 : _fe_problem.setActiveElementalMooseVariables(needed_moose_vars, tid);
665 4955206 : _fe_problem.prepareMaterials(needed_mat_props, subdomain, tid);
666 4955206 : }
667 :
668 : void
669 33831036 : RayTracingStudy::reinitSegment(
670 : const Elem * elem, const Point & start, const Point & end, const Real length, THREAD_ID tid)
671 : {
672 : mooseAssert(MooseUtils::absoluteFuzzyEqual((start - end).norm(), length), "Invalid length");
673 : mooseAssert(currentlyPropagating(), "Should not call while not propagating");
674 :
675 33831036 : _fe_problem.setCurrentSubdomainID(elem, tid);
676 :
677 : // If we have any variables or material properties that are active, we definitely need to reinit
678 67551159 : bool reinit = _fe_problem.hasActiveElementalMooseVariables(tid) ||
679 33720123 : _fe_problem.hasActiveMaterialProperties(tid);
680 : // If not, make sure that the RayKernels have not requested a reinit (this could happen when a
681 : // RayKernel doesn't have variables or materials but still does an integration and needs qps)
682 : if (!reinit)
683 67439199 : for (const RayKernelBase * rk : currentRayKernels(tid))
684 33719796 : if (rk->needSegmentReinit())
685 : {
686 : reinit = true;
687 : break;
688 : }
689 :
690 33831036 : if (reinit)
691 : {
692 111633 : _fe_problem.prepare(elem, tid);
693 :
694 : std::vector<Point> points;
695 : std::vector<Real> weights;
696 111633 : buildSegmentQuadrature(start, end, length, points, weights);
697 111633 : _fe_problem.reinitElemPhys(elem, points, tid);
698 111633 : _fe_problem.assembly(tid, _sys.number()).modifyArbitraryWeights(weights);
699 :
700 111633 : _fe_problem.reinitMaterials(elem->subdomain_id(), tid);
701 111633 : }
702 33831036 : }
703 :
704 : void
705 111633 : RayTracingStudy::buildSegmentQuadrature(const Point & start,
706 : const Point & end,
707 : const Real length,
708 : std::vector<Point> & points,
709 : std::vector<Real> & weights) const
710 : {
711 111633 : points.resize(_segment_qrule->n_points());
712 111633 : weights.resize(_segment_qrule->n_points());
713 :
714 : const Point diff = end - start;
715 : const Point sum = end + start;
716 : mooseAssert(MooseUtils::absoluteFuzzyEqual(length, diff.norm()), "Invalid length");
717 :
718 : // The standard quadrature rule should be on x = [-1, 1]
719 : // To scale the points, you...
720 : // - Scale to size of the segment in 3D
721 : // initial_scaled_qp = x_qp * 0.5 * (end - start) = 0.5 * x_qp * diff
722 : // - Shift quadrature midpoint to segment midpoint
723 : // final_qp = initial_scaled_qp + 0.5 * (end - start) = initial_scaled_qp + 0.5 * sum
724 : // = 0.5 * (x_qp * diff + sum)
725 312383 : for (unsigned int qp = 0; qp < _segment_qrule->n_points(); ++qp)
726 : {
727 200750 : points[qp] = 0.5 * (_segment_qrule->qp(qp)(0) * diff + sum);
728 200750 : weights[qp] = 0.5 * _segment_qrule->w(qp) * length;
729 : }
730 111633 : }
731 :
732 : void
733 35293895 : RayTracingStudy::postOnSegment(const THREAD_ID tid, const std::shared_ptr<Ray> & /* ray */)
734 : {
735 : mooseAssert(currentlyPropagating(), "Should not call while not propagating");
736 35293895 : if (!_fe_problem.currentlyComputingJacobian() && !_fe_problem.currentlyComputingResidual())
737 : mooseAssert(_num_cached[tid] == 0,
738 : "Values should only be cached when computing Jacobian/residual");
739 :
740 : // Fill into cached Jacobian/residuals if necessary
741 35293895 : if (_fe_problem.currentlyComputingJacobian())
742 : {
743 9078 : _fe_problem.cacheJacobian(tid);
744 :
745 9078 : if (++_num_cached[tid] == 20)
746 : {
747 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
748 372 : _fe_problem.addCachedJacobian(tid);
749 372 : _num_cached[tid] = 0;
750 : }
751 : }
752 35284817 : else if (_fe_problem.currentlyComputingResidual())
753 : {
754 74087 : _fe_problem.cacheResidual(tid);
755 :
756 74087 : if (++_num_cached[tid] == 20)
757 : {
758 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
759 2212 : _fe_problem.addCachedResidual(tid);
760 2212 : _num_cached[tid] = 0;
761 : }
762 : }
763 35293895 : }
764 :
765 : void
766 8023 : RayTracingStudy::executeStudy()
767 : {
768 16046 : TIME_SECTION("executeStudy", 2, "Executing Study");
769 :
770 : mooseAssert(_called_initial_setup, "Initial setup not called");
771 :
772 : // Reset ray start/complete timers
773 8023 : _total_intersections = 0;
774 8023 : _max_intersections = 0;
775 8023 : _max_trajectory_changes = 0;
776 :
777 : // Reset physical tracing stats
778 120345 : for (auto & val : _local_trace_ray_results)
779 112322 : val = 0;
780 :
781 : // Reset crossing and intersection
782 8023 : _ending_processor_crossings = 0;
783 8023 : _total_processor_crossings = 0;
784 8023 : _ending_max_processor_crossings = 0;
785 8023 : _ending_intersections = 0;
786 8023 : _ending_max_intersections = 0;
787 8023 : _ending_max_trajectory_changes = 0;
788 8023 : _ending_distance = 0;
789 8023 : _total_distance = 0;
790 :
791 : // Zero the AuxVariables that our AuxRayKernels contribute to before they accumulate
792 8023 : zeroAuxVariables();
793 :
794 8023 : preExecuteStudy();
795 23491 : for (auto & rto : getRayTracingObjects())
796 23491 : rto->preExecuteStudy();
797 :
798 8023 : _ray_bank.clear();
799 :
800 18417 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
801 : {
802 10394 : _threaded_trace_ray[tid]->preExecute();
803 : _threaded_cached_normals[tid].clear();
804 : }
805 :
806 8023 : _communicator.barrier();
807 8023 : _execution_start_time = std::chrono::steady_clock::now();
808 :
809 8023 : _parallel_ray_study->preExecute();
810 :
811 : {
812 : {
813 8023 : auto generation_start_time = std::chrono::steady_clock::now();
814 :
815 16046 : TIME_SECTION("generateRays", 2, "Generating Rays");
816 :
817 8023 : generateRays();
818 :
819 7961 : _generation_time = std::chrono::steady_clock::now() - generation_start_time;
820 : }
821 :
822 : // At this point, nobody is working so this is good time to make sure
823 : // Rays are unique across all processors in the working buffer
824 7961 : if (verifyRays())
825 : {
826 7961 : verifyUniqueRays(_parallel_ray_study->workBuffer().begin(),
827 : _parallel_ray_study->workBuffer().end(),
828 : /* error_suffix = */ "after generateRays()");
829 :
830 15916 : verifyUniqueRayIDs(_parallel_ray_study->workBuffer().begin(),
831 : _parallel_ray_study->workBuffer().end(),
832 : /* global = */ true,
833 : /* error_suffix = */ "after generateRays()");
834 : }
835 :
836 7957 : registeredRaySetup();
837 :
838 : {
839 15906 : TIME_SECTION("propagateRays", 2, "Propagating Rays");
840 :
841 7953 : const auto propagation_start_time = std::chrono::steady_clock::now();
842 :
843 7953 : _parallel_ray_study->execute();
844 :
845 7927 : _propagation_time = std::chrono::steady_clock::now() - propagation_start_time;
846 : }
847 : }
848 :
849 7927 : _execution_time = std::chrono::steady_clock::now() - _execution_start_time;
850 :
851 7927 : if (verifyRays())
852 : {
853 15854 : verifyUniqueRays(_parallel_ray_study->workBuffer().begin(),
854 : _parallel_ray_study->workBuffer().end(),
855 : /* error_suffix = */ "after tracing completed");
856 :
857 : #ifndef NDEBUG
858 : // Outside of debug, _ray_bank always holds all of the Rays that have ended on this processor
859 : // We can use this as a global point to check for unique IDs for every Ray that has traced
860 : verifyUniqueRayIDs(_ray_bank.begin(),
861 : _ray_bank.end(),
862 : /* global = */ true,
863 : /* error_suffix = */ "after tracing completed");
864 : #endif
865 : }
866 :
867 : // Update counters from the threaded trace objects
868 18177 : for (const auto & tr : _threaded_trace_ray)
869 153750 : for (std::size_t i = 0; i < _local_trace_ray_results.size(); ++i)
870 143500 : _local_trace_ray_results[i] += tr->results()[i];
871 :
872 : // Update local ending counters
873 7927 : _total_processor_crossings = _ending_processor_crossings;
874 7927 : _max_processor_crossings = _ending_max_processor_crossings;
875 7927 : _total_intersections = _ending_intersections;
876 7927 : _max_intersections = _ending_max_intersections;
877 7927 : _max_trajectory_changes = _ending_max_trajectory_changes;
878 7927 : _total_distance = _ending_distance;
879 : // ...and communicate the global values
880 7927 : _communicator.sum(_total_processor_crossings);
881 7927 : _communicator.max(_max_processor_crossings);
882 7927 : _communicator.sum(_total_intersections);
883 7927 : _communicator.max(_max_intersections);
884 7927 : _communicator.max(_max_trajectory_changes);
885 7927 : _communicator.sum(_total_distance);
886 :
887 : // Throw a warning with the number of failed (tolerated) traces
888 7927 : if (_tolerate_failure)
889 : {
890 8 : auto failures = _local_trace_ray_results[TraceRay::FAILED_TRACES];
891 8 : _communicator.sum(failures);
892 8 : if (failures)
893 8 : mooseWarning(
894 : type(), " '", name(), "': ", failures, " ray tracing failures were tolerated.\n");
895 : }
896 :
897 : // Clear the current RayKernels
898 18177 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
899 10250 : _threaded_current_ray_kernels[tid].clear();
900 :
901 : // Move the threaded cache trace information into the full cached trace vector
902 : // Here, we only clear the cached vectors so that we might not have to
903 : // reallocate on future traces
904 : std::size_t num_entries = 0;
905 18177 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
906 10250 : num_entries += _threaded_cached_traces[tid].size();
907 7927 : _cached_traces.clear();
908 7927 : _cached_traces.reserve(num_entries);
909 18177 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
910 : {
911 24037 : for (const auto & entry : _threaded_cached_traces[tid])
912 13787 : _cached_traces.emplace_back(std::move(entry));
913 10250 : _threaded_cached_traces[tid].clear();
914 : }
915 :
916 : // Add any stragglers that contribute to the Jacobian or residual
917 18177 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
918 10250 : if (_num_cached[tid] != 0)
919 : {
920 : mooseAssert(_fe_problem.currentlyComputingJacobian() ||
921 : _fe_problem.currentlyComputingResidual(),
922 : "Should not have cached values without Jacobian/residual computation");
923 :
924 4623 : if (_fe_problem.currentlyComputingJacobian())
925 240 : _fe_problem.addCachedJacobian(tid);
926 : else
927 4383 : _fe_problem.addCachedResidual(tid);
928 :
929 4623 : _num_cached[tid] = 0;
930 : }
931 :
932 : // AuxRayKernels may have modified AuxVariables
933 7927 : _fe_problem.getAuxiliarySystem().solution().close();
934 7927 : _fe_problem.getAuxiliarySystem().update();
935 :
936 : // Clear FE
937 18177 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
938 : {
939 10250 : _fe_problem.clearActiveElementalMooseVariables(tid);
940 10250 : _fe_problem.clearActiveMaterialProperties(tid);
941 : }
942 :
943 7927 : postExecuteStudy();
944 23322 : for (auto & rto : getRayTracingObjects())
945 23322 : rto->postExecuteStudy();
946 7923 : }
947 :
948 : void
949 4120844 : RayTracingStudy::onCompleteRay(const std::shared_ptr<Ray> & ray)
950 : {
951 : mooseAssert(currentlyPropagating(), "Should only be called during Ray propagation");
952 :
953 4120844 : _ending_processor_crossings += ray->processorCrossings();
954 4120844 : _ending_max_processor_crossings =
955 4126897 : std::max(_ending_max_processor_crossings, ray->processorCrossings());
956 4120844 : _ending_intersections += ray->intersections();
957 4138202 : _ending_max_intersections = std::max(_ending_max_intersections, ray->intersections());
958 4120844 : _ending_max_trajectory_changes =
959 4121259 : std::max(_ending_max_trajectory_changes, ray->trajectoryChanges());
960 4120844 : _ending_distance += ray->distance();
961 :
962 : #ifdef NDEBUG
963 : // In non-opt modes, we will always bank the Rays for debugging
964 4120844 : if (_bank_rays_on_completion)
965 : #endif
966 4120842 : _ray_bank.emplace_back(ray);
967 4120844 : }
968 :
969 : RayDataIndex
970 2555 : RayTracingStudy::registerRayDataInternal(const std::string & name, const bool aux)
971 : {
972 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
973 :
974 2555 : if (_called_initial_setup)
975 4 : mooseError("Cannot register Ray ", (aux ? "aux " : ""), "data after initialSetup()");
976 :
977 2553 : auto & map = aux ? _ray_aux_data_map : _ray_data_map;
978 : const auto find = map.find(name);
979 2553 : if (find != map.end())
980 73 : return find->second;
981 :
982 2480 : auto & other_map = aux ? _ray_data_map : _ray_aux_data_map;
983 2480 : if (other_map.find(name) != other_map.end())
984 4 : mooseError("Cannot register Ray aux data with name ",
985 : name,
986 : " because Ray ",
987 2 : (aux ? "(non-aux)" : "aux"),
988 : " data already exists with said name.");
989 :
990 : // Add into the name -> index map
991 2478 : map.emplace(name, map.size());
992 :
993 : // Add into the index -> names vector
994 2478 : auto & vector = aux ? _ray_aux_data_names : _ray_data_names;
995 2478 : vector.push_back(name);
996 :
997 2478 : return map.size() - 1;
998 : }
999 :
1000 : std::vector<RayDataIndex>
1001 266 : RayTracingStudy::registerRayDataInternal(const std::vector<std::string> & names, const bool aux)
1002 : {
1003 266 : std::vector<RayDataIndex> indices(names.size());
1004 589 : for (std::size_t i = 0; i < names.size(); ++i)
1005 323 : indices[i] = registerRayDataInternal(names[i], aux);
1006 266 : return indices;
1007 0 : }
1008 :
1009 : RayDataIndex
1010 1394 : RayTracingStudy::getRayDataIndexInternal(const std::string & name,
1011 : const bool aux,
1012 : const bool graceful) const
1013 : {
1014 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1015 :
1016 1394 : const auto & map = aux ? _ray_aux_data_map : _ray_data_map;
1017 : const auto find = map.find(name);
1018 1394 : if (find != map.end())
1019 1380 : return find->second;
1020 :
1021 14 : if (graceful)
1022 : return Ray::INVALID_RAY_DATA_INDEX;
1023 :
1024 6 : const auto & other_map = aux ? _ray_data_map : _ray_aux_data_map;
1025 6 : if (other_map.find(name) != other_map.end())
1026 8 : mooseError("Ray data with name '",
1027 : name,
1028 : "' was not found.\n\n",
1029 : "However, Ray ",
1030 4 : (aux ? "non-aux" : "aux"),
1031 : " data with said name was found.\n",
1032 : "Did you mean to use ",
1033 6 : (aux ? "getRayDataIndex()/getRayDataIndices()?"
1034 : : "getRayAuxDataIndex()/getRayAuxDataIndices()"),
1035 : "?");
1036 :
1037 4 : mooseError("Unknown Ray ", (aux ? "aux " : ""), "data with name ", name);
1038 : }
1039 :
1040 : std::vector<RayDataIndex>
1041 710 : RayTracingStudy::getRayDataIndicesInternal(const std::vector<std::string> & names,
1042 : const bool aux,
1043 : const bool graceful) const
1044 : {
1045 710 : std::vector<RayDataIndex> indices(names.size());
1046 842 : for (std::size_t i = 0; i < names.size(); ++i)
1047 132 : indices[i] = getRayDataIndexInternal(names[i], aux, graceful);
1048 710 : return indices;
1049 0 : }
1050 :
1051 : const std::string &
1052 7346 : RayTracingStudy::getRayDataNameInternal(const RayDataIndex index, const bool aux) const
1053 : {
1054 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1055 :
1056 14692 : if ((aux ? rayAuxDataSize() : rayDataSize()) < index)
1057 4 : mooseError("Unknown Ray ", aux ? "aux " : "", "data with index ", index);
1058 14688 : return aux ? _ray_aux_data_names[index] : _ray_data_names[index];
1059 : }
1060 :
1061 : RayDataIndex
1062 978 : RayTracingStudy::registerRayData(const std::string & name)
1063 : {
1064 978 : return registerRayDataInternal(name, /* aux = */ false);
1065 : }
1066 :
1067 : std::vector<RayDataIndex>
1068 136 : RayTracingStudy::registerRayData(const std::vector<std::string> & names)
1069 : {
1070 136 : return registerRayDataInternal(names, /* aux = */ false);
1071 : }
1072 :
1073 : RayDataIndex
1074 1104 : RayTracingStudy::getRayDataIndex(const std::string & name, const bool graceful /* = false */) const
1075 : {
1076 1104 : return getRayDataIndexInternal(name, /* aux = */ false, graceful);
1077 : }
1078 :
1079 : std::vector<RayDataIndex>
1080 355 : RayTracingStudy::getRayDataIndices(const std::vector<std::string> & names,
1081 : const bool graceful /* = false */) const
1082 : {
1083 355 : return getRayDataIndicesInternal(names, /* aux = */ false, graceful);
1084 : }
1085 :
1086 : const std::string &
1087 3674 : RayTracingStudy::getRayDataName(const RayDataIndex index) const
1088 : {
1089 3674 : return getRayDataNameInternal(index, /* aux = */ false);
1090 : }
1091 :
1092 : RayDataIndex
1093 1254 : RayTracingStudy::registerRayAuxData(const std::string & name)
1094 : {
1095 1254 : return registerRayDataInternal(name, /* aux = */ true);
1096 : }
1097 :
1098 : std::vector<RayDataIndex>
1099 130 : RayTracingStudy::registerRayAuxData(const std::vector<std::string> & names)
1100 : {
1101 130 : return registerRayDataInternal(names, /* aux = */ true);
1102 : }
1103 :
1104 : RayDataIndex
1105 158 : RayTracingStudy::getRayAuxDataIndex(const std::string & name,
1106 : const bool graceful /* = false */) const
1107 : {
1108 158 : return getRayDataIndexInternal(name, /* aux = */ true, graceful);
1109 : }
1110 :
1111 : std::vector<RayDataIndex>
1112 355 : RayTracingStudy::getRayAuxDataIndices(const std::vector<std::string> & names,
1113 : const bool graceful /* = false */) const
1114 : {
1115 355 : return getRayDataIndicesInternal(names, /* aux = */ true, graceful);
1116 : }
1117 :
1118 : const std::string &
1119 3672 : RayTracingStudy::getRayAuxDataName(const RayDataIndex index) const
1120 : {
1121 3672 : return getRayDataNameInternal(index, /* aux = */ true);
1122 : }
1123 :
1124 : bool
1125 10394 : RayTracingStudy::hasRayKernels(const THREAD_ID tid)
1126 : {
1127 : std::vector<RayKernelBase *> result;
1128 10394 : getRayKernels(result, tid);
1129 10394 : return result.size();
1130 10394 : }
1131 :
1132 : void
1133 4955208 : RayTracingStudy::getRayKernels(std::vector<RayKernelBase *> & result, SubdomainID id, THREAD_ID tid)
1134 : {
1135 : // If the cache doesn't have any attributes yet, it means that we haven't set
1136 : // the conditions yet. We do this so that it can be generated on the fly on first use.
1137 4955208 : if (!_threaded_cache_ray_kernel[tid].numAttribs())
1138 : {
1139 2562 : if (!_called_initial_setup)
1140 2 : mooseError("Should not call getRayKernels() before initialSetup()");
1141 :
1142 2560 : auto query = _fe_problem.theWarehouse()
1143 2560 : .query()
1144 5120 : .condition<AttribRayTracingStudy>(this)
1145 2560 : .condition<AttribSystem>("RayKernel")
1146 2560 : .condition<AttribThread>(tid);
1147 2560 : _threaded_cache_ray_kernel[tid] = query.clone();
1148 2560 : }
1149 :
1150 : _threaded_cache_ray_kernel[tid].queryInto(result, id);
1151 4955206 : }
1152 :
1153 : void
1154 4955206 : RayTracingStudy::getRayKernels(std::vector<RayKernelBase *> & result,
1155 : SubdomainID id,
1156 : THREAD_ID tid,
1157 : RayID ray_id)
1158 : {
1159 : // No Ray registration: no need to sift through objects
1160 4955206 : if (!_use_ray_registration)
1161 : {
1162 4945234 : getRayKernels(result, id, tid);
1163 : }
1164 : // Has Ray registration: only pick the objects associated with ray_id
1165 : else
1166 : {
1167 : // Get all of the kernels on this block
1168 : std::vector<RayKernelBase *> rkbs;
1169 9972 : getRayKernels(rkbs, id, tid);
1170 :
1171 : // The RayTracingObjects associated with this ray
1172 9972 : const auto & ray_id_rtos = _threaded_ray_object_registration[tid][ray_id];
1173 :
1174 : // The result is the union of all of the kernels and the objects associated with this Ray
1175 9972 : result.clear();
1176 24689 : for (auto rkb : rkbs)
1177 14717 : if (ray_id_rtos.count(rkb))
1178 10117 : result.push_back(rkb);
1179 9972 : }
1180 4955206 : }
1181 :
1182 : void
1183 1332369 : RayTracingStudy::getRayBCs(std::vector<RayBoundaryConditionBase *> & result,
1184 : BoundaryID id,
1185 : THREAD_ID tid)
1186 : {
1187 : // If the cache doesn't have any attributes yet, it means that we haven't set
1188 : // the conditions yet. We do this so that it can be generated on the fly on first use.
1189 1332369 : if (!_threaded_cache_ray_bc[tid].numAttribs())
1190 : {
1191 2408 : if (!_called_initial_setup)
1192 2 : mooseError("Should not call getRayBCs() before initialSetup()");
1193 :
1194 2406 : auto query = _fe_problem.theWarehouse()
1195 2406 : .query()
1196 4812 : .condition<AttribRayTracingStudy>(this)
1197 2406 : .condition<AttribSystem>("RayBoundaryCondition")
1198 2406 : .condition<AttribThread>(tid);
1199 2406 : _threaded_cache_ray_bc[tid] = query.clone();
1200 2406 : }
1201 :
1202 1332367 : _threaded_cache_ray_bc[tid].queryInto(result, std::make_tuple(id, false));
1203 1332367 : }
1204 :
1205 : void
1206 1411579 : RayTracingStudy::getRayBCs(std::vector<RayBoundaryConditionBase *> & result,
1207 : const std::vector<TraceRayBndElement> & bnd_elems,
1208 : THREAD_ID tid,
1209 : RayID ray_id)
1210 : {
1211 : // No Ray registration: no need to sift through objects
1212 1411579 : if (!_use_ray_registration)
1213 : {
1214 1409568 : if (bnd_elems.size() == 1)
1215 1323548 : getRayBCs(result, bnd_elems[0].bnd_id, tid);
1216 : else
1217 : {
1218 86020 : std::vector<BoundaryID> bnd_ids(bnd_elems.size());
1219 265212 : for (MooseIndex(bnd_elems.size()) i = 0; i < bnd_elems.size(); ++i)
1220 179192 : bnd_ids[i] = bnd_elems[i].bnd_id;
1221 86020 : getRayBCs(result, bnd_ids, tid);
1222 86020 : }
1223 : }
1224 : // Has Ray registration: only pick the objects associated with ray_id
1225 : else
1226 : {
1227 : // Get all of the RayBCs on these boundaries
1228 : std::vector<RayBoundaryConditionBase *> rbcs;
1229 2011 : if (bnd_elems.size() == 1)
1230 1656 : getRayBCs(rbcs, bnd_elems[0].bnd_id, tid);
1231 : else
1232 : {
1233 355 : std::vector<BoundaryID> bnd_ids(bnd_elems.size());
1234 1227 : for (MooseIndex(bnd_elems.size()) i = 0; i < bnd_elems.size(); ++i)
1235 872 : bnd_ids[i] = bnd_elems[i].bnd_id;
1236 355 : getRayBCs(rbcs, bnd_ids, tid);
1237 355 : }
1238 :
1239 : // The RayTracingObjects associated with this ray
1240 : mooseAssert(ray_id < _threaded_ray_object_registration[tid].size(), "Not in registration");
1241 2011 : const auto & ray_id_rtos = _threaded_ray_object_registration[tid][ray_id];
1242 :
1243 : // The result is the union of all of the kernels and the objects associated with this Ray
1244 2011 : result.clear();
1245 5834 : for (auto rbc : rbcs)
1246 3823 : if (ray_id_rtos.count(rbc))
1247 2049 : result.push_back(rbc);
1248 2011 : }
1249 1411579 : }
1250 :
1251 : std::vector<RayTracingObject *>
1252 35850 : RayTracingStudy::getRayTracingObjects()
1253 : {
1254 : std::vector<RayTracingObject *> result;
1255 71700 : _fe_problem.theWarehouse().query().condition<AttribRayTracingStudy>(this).queryInto(result);
1256 35850 : return result;
1257 0 : }
1258 :
1259 : const std::vector<std::shared_ptr<Ray>> &
1260 1108 : RayTracingStudy::rayBank() const
1261 : {
1262 1108 : if (!_bank_rays_on_completion)
1263 2 : mooseError("The Ray bank is not available because the private parameter "
1264 : "'_bank_rays_on_completion' is set to false.");
1265 1106 : if (currentlyGenerating() || currentlyPropagating())
1266 2 : mooseError("Cannot get the Ray bank during generation or propagation.");
1267 :
1268 1104 : return _ray_bank;
1269 : }
1270 :
1271 : std::shared_ptr<Ray>
1272 744 : RayTracingStudy::getBankedRay(const RayID ray_id) const
1273 : {
1274 : // This is only a linear search - can be improved on with a map in the future
1275 : // if this is used on a larger scale
1276 744 : std::shared_ptr<Ray> ray;
1277 1279 : for (const std::shared_ptr<Ray> & possible_ray : rayBank())
1278 1012 : if (possible_ray->id() == ray_id)
1279 : {
1280 : ray = possible_ray;
1281 : break;
1282 : }
1283 :
1284 : // Make sure one and only one processor has the Ray
1285 744 : unsigned int have_ray = ray ? 1 : 0;
1286 744 : _communicator.sum(have_ray);
1287 744 : if (have_ray == 0)
1288 2 : mooseError("Could not find a Ray with the ID ", ray_id, " in the Ray banks.");
1289 :
1290 : // This should never happen... but let's make sure
1291 : mooseAssert(have_ray == 1, "Multiple rays with the same ID were found in the Ray banks");
1292 :
1293 742 : return ray;
1294 : }
1295 :
1296 : RayData
1297 744 : RayTracingStudy::getBankedRayDataInternal(const RayID ray_id,
1298 : const RayDataIndex index,
1299 : const bool aux) const
1300 : {
1301 : // Will be a nullptr shared_ptr if this processor doesn't own the Ray
1302 744 : const std::shared_ptr<Ray> ray = getBankedRay(ray_id);
1303 :
1304 742 : Real value = ray ? (aux ? ray->auxData(index) : ray->data(index)) : 0;
1305 742 : _communicator.sum(value);
1306 1219 : return value;
1307 : }
1308 :
1309 : RayData
1310 688 : RayTracingStudy::getBankedRayData(const RayID ray_id, const RayDataIndex index) const
1311 : {
1312 688 : return getBankedRayDataInternal(ray_id, index, /* aux = */ false);
1313 : }
1314 :
1315 : RayData
1316 56 : RayTracingStudy::getBankedRayAuxData(const RayID ray_id, const RayDataIndex index) const
1317 : {
1318 56 : return getBankedRayDataInternal(ray_id, index, /* aux = */ true);
1319 : }
1320 :
1321 : RayID
1322 2519 : RayTracingStudy::registerRay(const std::string & name)
1323 : {
1324 : libmesh_parallel_only(comm());
1325 :
1326 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1327 :
1328 2519 : if (!_use_ray_registration)
1329 2 : mooseError("Cannot use registerRay() with Ray registration disabled");
1330 :
1331 : // This is parallel only for now. We could likely stagger the ID building like we do with
1332 : // the unique IDs, but it would require a sync point which isn't there right now
1333 : libmesh_parallel_only(comm());
1334 :
1335 2517 : const auto & it = _registered_ray_map.find(name);
1336 2517 : if (it != _registered_ray_map.end())
1337 0 : return it->second;
1338 :
1339 2517 : const auto id = _reverse_registered_ray_map.size();
1340 2517 : _registered_ray_map.emplace(name, id);
1341 2517 : _reverse_registered_ray_map.push_back(name);
1342 2517 : return id;
1343 : }
1344 :
1345 : RayID
1346 17719 : RayTracingStudy::registeredRayID(const std::string & name, const bool graceful /* = false */) const
1347 : {
1348 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1349 :
1350 17719 : if (!_use_ray_registration)
1351 2 : mooseError("Should not use registeredRayID() with Ray registration disabled");
1352 :
1353 17717 : const auto search = _registered_ray_map.find(name);
1354 17717 : if (search != _registered_ray_map.end())
1355 17709 : return search->second;
1356 :
1357 8 : if (graceful)
1358 : return Ray::INVALID_RAY_ID;
1359 :
1360 2 : mooseError("Attempted to obtain ID of registered Ray ",
1361 : name,
1362 : ", but a Ray with said name is not registered.");
1363 : }
1364 :
1365 : const std::string &
1366 41 : RayTracingStudy::registeredRayName(const RayID ray_id) const
1367 : {
1368 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1369 :
1370 41 : if (!_use_ray_registration)
1371 2 : mooseError("Should not use registeredRayName() with Ray registration disabled");
1372 :
1373 39 : if (_reverse_registered_ray_map.size() > ray_id)
1374 37 : return _reverse_registered_ray_map[ray_id];
1375 :
1376 2 : mooseError("Attempted to obtain name of registered Ray with ID ",
1377 : ray_id,
1378 : ", but a Ray with said ID is not registered.");
1379 : }
1380 :
1381 : Real
1382 3827 : RayTracingStudy::computeTotalVolume()
1383 : {
1384 3827 : Real volume = 0;
1385 466527 : for (const auto & elem : *_mesh.getActiveLocalElementRange())
1386 462700 : volume += elem->volume();
1387 3827 : _communicator.sum(volume);
1388 3827 : return volume;
1389 : }
1390 :
1391 : const std::vector<std::vector<BoundaryID>> &
1392 15182 : RayTracingStudy::getInternalSidesets(const Elem * elem) const
1393 : {
1394 : mooseAssert(_use_internal_sidesets, "Not using internal sidesets");
1395 : mooseAssert(hasInternalSidesets(), "Processor does not have internal sidesets");
1396 : mooseAssert(_internal_sidesets_map.size() > _elem_index_helper.getIndex(elem),
1397 : "Internal sideset map not initialized");
1398 :
1399 : const auto index = _elem_index_helper.getIndex(elem);
1400 15182 : return _internal_sidesets_map[index];
1401 : }
1402 :
1403 : TraceData &
1404 13787 : RayTracingStudy::initThreadedCachedTrace(const std::shared_ptr<Ray> & ray, THREAD_ID tid)
1405 : {
1406 : mooseAssert(shouldCacheTrace(ray), "Not caching trace");
1407 : mooseAssert(currentlyPropagating(), "Should only use while tracing");
1408 :
1409 13787 : _threaded_cached_traces[tid].emplace_back(ray);
1410 13787 : return _threaded_cached_traces[tid].back();
1411 : }
1412 :
1413 : void
1414 8630 : RayTracingStudy::verifyUniqueRayIDs(const std::vector<std::shared_ptr<Ray>>::const_iterator begin,
1415 : const std::vector<std::shared_ptr<Ray>>::const_iterator end,
1416 : const bool global,
1417 : const std::string & error_suffix) const
1418 : {
1419 : // Determine the unique set of Ray IDs on this processor,
1420 : // and if not locally unique throw an error. Once we build this set,
1421 : // we will send it to rank 0 to verify globally
1422 : std::set<RayID> local_rays;
1423 4050625 : for (const std::shared_ptr<Ray> & ray : as_range(begin, end))
1424 : {
1425 : mooseAssert(ray, "Null ray");
1426 :
1427 : // Try to insert into the set; the second entry in the pair
1428 : // will be false if it was not inserted
1429 4041999 : if (!local_rays.insert(ray->id()).second)
1430 : {
1431 4 : for (const std::shared_ptr<Ray> & other_ray : as_range(begin, end))
1432 4 : if (ray.get() != other_ray.get() && ray->id() == other_ray->id())
1433 8 : mooseError("Multiple Rays exist with ID ",
1434 4 : ray->id(),
1435 : " on processor ",
1436 4 : _pid,
1437 : " ",
1438 : error_suffix,
1439 : "\n\nOffending Ray information:\n\n",
1440 4 : ray->getInfo(),
1441 : "\n",
1442 4 : other_ray->getInfo());
1443 : }
1444 : }
1445 :
1446 : // Send IDs from all procs to rank 0 and verify on rank 0
1447 8626 : if (global)
1448 : {
1449 : // Package our local IDs and send to rank 0
1450 : std::map<processor_id_type, std::vector<RayID>> send_ids;
1451 7957 : if (local_rays.size())
1452 : send_ids.emplace(std::piecewise_construct,
1453 6080 : std::forward_as_tuple(0),
1454 6080 : std::forward_as_tuple(local_rays.begin(), local_rays.end()));
1455 : local_rays.clear();
1456 :
1457 : // Mapping on rank 0 from ID -> processor ID
1458 : std::map<RayID, processor_id_type> global_map;
1459 :
1460 : // Verify another processor's IDs against the global map on rank 0
1461 : const auto check_ids =
1462 6080 : [this, &global_map, &error_suffix](processor_id_type pid, const std::vector<RayID> & ids)
1463 : {
1464 4044512 : for (const RayID id : ids)
1465 : {
1466 4038432 : const auto emplace_pair = global_map.emplace(id, pid);
1467 :
1468 : // Means that this ID already exists in the map
1469 4038432 : if (!emplace_pair.second)
1470 0 : mooseError("Ray with ID ",
1471 : id,
1472 : " exists on ranks ",
1473 0 : emplace_pair.first->second,
1474 : " and ",
1475 : pid,
1476 : "\n",
1477 : error_suffix);
1478 : }
1479 14037 : };
1480 :
1481 7957 : Parallel::push_parallel_vector_data(_communicator, send_ids, check_ids);
1482 : }
1483 8626 : }
1484 :
1485 : void
1486 15888 : RayTracingStudy::verifyUniqueRays(const std::vector<std::shared_ptr<Ray>>::const_iterator begin,
1487 : const std::vector<std::shared_ptr<Ray>>::const_iterator end,
1488 : const std::string & error_suffix)
1489 : {
1490 : std::set<const Ray *> rays;
1491 4054326 : for (const std::shared_ptr<Ray> & ray : as_range(begin, end))
1492 4038440 : if (!rays.insert(ray.get()).second) // false if not inserted into rays
1493 2 : mooseError("Multiple shared_ptrs were found that point to the same Ray ",
1494 : error_suffix,
1495 : "\n\nOffending Ray:\n",
1496 2 : ray->getInfo());
1497 15886 : }
1498 :
1499 : void
1500 4037450 : RayTracingStudy::moveRayToBuffer(std::shared_ptr<Ray> & ray)
1501 : {
1502 : mooseAssert(currentlyGenerating(), "Can only use while generating");
1503 : mooseAssert(ray, "Null ray");
1504 : mooseAssert(ray->shouldContinue(), "Ray is not continuing");
1505 :
1506 4037450 : _parallel_ray_study->moveWorkToBuffer(ray, /* tid = */ 0);
1507 4037450 : }
1508 :
1509 : void
1510 282 : RayTracingStudy::moveRaysToBuffer(std::vector<std::shared_ptr<Ray>> & rays)
1511 : {
1512 : mooseAssert(currentlyGenerating(), "Can only use while generating");
1513 : #ifndef NDEBUG
1514 : for (const std::shared_ptr<Ray> & ray : rays)
1515 : {
1516 : mooseAssert(ray, "Null ray");
1517 : mooseAssert(ray->shouldContinue(), "Ray is not continuing");
1518 : }
1519 : #endif
1520 :
1521 282 : _parallel_ray_study->moveWorkToBuffer(rays, /* tid = */ 0);
1522 282 : }
1523 :
1524 : void
1525 82440 : RayTracingStudy::moveRayToBufferDuringTrace(std::shared_ptr<Ray> & ray,
1526 : const THREAD_ID tid,
1527 : const AcquireMoveDuringTraceKey &)
1528 : {
1529 : mooseAssert(ray, "Null ray");
1530 : mooseAssert(currentlyPropagating(), "Can only use while tracing");
1531 :
1532 82440 : _parallel_ray_study->moveWorkToBuffer(ray, tid);
1533 82440 : }
1534 :
1535 : void
1536 7563 : RayTracingStudy::reserveRayBuffer(const std::size_t size)
1537 : {
1538 7563 : if (!currentlyGenerating())
1539 2 : mooseError("Can only reserve in Ray buffer during generateRays()");
1540 :
1541 7561 : _parallel_ray_study->reserveBuffer(size);
1542 7561 : }
1543 :
1544 : const Point &
1545 7343592 : RayTracingStudy::getSideNormal(const Elem * elem, unsigned short side, const THREAD_ID tid)
1546 : {
1547 : std::unordered_map<std::pair<const Elem *, unsigned short>, Point> & cache =
1548 7343592 : _threaded_cached_normals[tid];
1549 :
1550 : // See if we've already cached this side normal
1551 7343592 : const auto elem_side_pair = std::make_pair(elem, side);
1552 : const auto search = cache.find(elem_side_pair);
1553 :
1554 : // Haven't cached this side normal: compute it and then cache it
1555 7343592 : if (search == cache.end())
1556 : {
1557 1553301 : _threaded_fe_face[tid]->reinit(elem, side);
1558 : const auto & normal = _threaded_fe_face[tid]->get_normals()[0];
1559 : cache.emplace(elem_side_pair, normal);
1560 1553301 : return normal;
1561 : }
1562 :
1563 : // Have cached this side normal: simply return it
1564 5790291 : return search->second;
1565 : }
1566 :
1567 : bool
1568 4055 : RayTracingStudy::sameLevelActiveElems() const
1569 : {
1570 4055 : unsigned int min_level = std::numeric_limits<unsigned int>::max();
1571 4055 : unsigned int max_level = std::numeric_limits<unsigned int>::min();
1572 :
1573 474807 : for (const auto & elem : *_mesh.getActiveLocalElementRange())
1574 : {
1575 470752 : const auto level = elem->level();
1576 470752 : min_level = std::min(level, min_level);
1577 470752 : max_level = std::max(level, max_level);
1578 : }
1579 :
1580 4055 : _communicator.min(min_level);
1581 4055 : _communicator.max(max_level);
1582 :
1583 4055 : return min_level == max_level;
1584 : }
1585 :
1586 : Real
1587 5855227 : RayTracingStudy::subdomainHmax(const SubdomainID subdomain_id) const
1588 : {
1589 : const auto find = _subdomain_hmax.find(subdomain_id);
1590 5855227 : if (find == _subdomain_hmax.end())
1591 2 : mooseError("Subdomain ", subdomain_id, " not found in subdomain hmax map");
1592 5855225 : return find->second;
1593 : }
1594 :
1595 : bool
1596 12485 : RayTracingStudy::isRectangularDomain() const
1597 : {
1598 : Real bbox_volume = 1;
1599 39980 : for (unsigned int d = 0; d < _mesh.dimension(); ++d)
1600 27495 : bbox_volume *= std::abs(_b_box.max()(d) - _b_box.min()(d));
1601 :
1602 12485 : return MooseUtils::absoluteFuzzyEqual(bbox_volume, totalVolume(), TOLERANCE);
1603 : }
1604 :
1605 : void
1606 3823 : RayTracingStudy::resetUniqueRayIDs()
1607 : {
1608 : libmesh_parallel_only(comm());
1609 :
1610 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1611 :
1612 : mooseAssert(!currentlyGenerating() && !currentlyPropagating(),
1613 : "Cannot be reset during generation or propagation");
1614 :
1615 8368 : for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1616 4545 : _threaded_next_ray_id[tid] = (RayID)_pid * (RayID)libMesh::n_threads() + (RayID)tid;
1617 3823 : }
1618 :
1619 : RayID
1620 4053853 : RayTracingStudy::generateUniqueRayID(const THREAD_ID tid)
1621 : {
1622 : // Get the current ID to return
1623 4053853 : const auto id = _threaded_next_ray_id[tid];
1624 :
1625 : // Advance so that the next call has the correct ID
1626 4053853 : _threaded_next_ray_id[tid] += (RayID)n_processors() * (RayID)libMesh::n_threads();
1627 :
1628 4053853 : return id;
1629 : }
1630 :
1631 : void
1632 3823 : RayTracingStudy::resetReplicatedRayIDs()
1633 : {
1634 : libmesh_parallel_only(comm());
1635 :
1636 : Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1637 :
1638 : mooseAssert(!currentlyGenerating() && !currentlyPropagating(),
1639 : "Cannot be reset during generation or propagation");
1640 :
1641 3823 : _replicated_next_ray_id = 0;
1642 3823 : }
1643 :
1644 : RayID
1645 1106 : RayTracingStudy::generateReplicatedRayID()
1646 : {
1647 1106 : return _replicated_next_ray_id++;
1648 : }
1649 :
1650 : bool
1651 3501880 : RayTracingStudy::sideIsIncoming(const Elem * const elem,
1652 : const unsigned short side,
1653 : const Point & direction,
1654 : const THREAD_ID tid)
1655 : {
1656 3501880 : const auto & normal = getSideNormal(elem, side, tid);
1657 : const auto dot = normal * direction;
1658 3501880 : return dot < TraceRayTools::TRACE_TOLERANCE;
1659 : }
1660 :
1661 : std::shared_ptr<Ray>
1662 3955573 : RayTracingStudy::acquireRay()
1663 : {
1664 : mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1665 :
1666 3955573 : return _parallel_ray_study->acquireParallelData(
1667 : /* tid = */ 0,
1668 7911146 : this,
1669 3955573 : generateUniqueRayID(/* tid = */ 0),
1670 7911146 : rayDataSize(),
1671 3955573 : rayAuxDataSize(),
1672 3955573 : /* reset = */ true,
1673 3955573 : Ray::ConstructRayKey());
1674 : }
1675 :
1676 : std::shared_ptr<Ray>
1677 15840 : RayTracingStudy::acquireUnsizedRay()
1678 : {
1679 : mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1680 :
1681 15840 : return _parallel_ray_study->acquireParallelData(/* tid = */ 0,
1682 31680 : this,
1683 15840 : generateUniqueRayID(/* tid = */ 0),
1684 31680 : /* data_size = */ 0,
1685 31680 : /* aux_data_size = */ 0,
1686 15840 : /* reset = */ true,
1687 15840 : Ray::ConstructRayKey());
1688 : }
1689 :
1690 : std::shared_ptr<Ray>
1691 1106 : RayTracingStudy::acquireReplicatedRay()
1692 : {
1693 : mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1694 : libmesh_parallel_only(comm());
1695 :
1696 1106 : return _parallel_ray_study->acquireParallelData(
1697 : /* tid = */ 0,
1698 2212 : this,
1699 1106 : generateReplicatedRayID(),
1700 2212 : rayDataSize(),
1701 1106 : rayAuxDataSize(),
1702 1106 : /* reset = */ true,
1703 1106 : Ray::ConstructRayKey());
1704 : }
1705 :
1706 : std::shared_ptr<Ray>
1707 2519 : RayTracingStudy::acquireRegisteredRay(const std::string & name)
1708 : {
1709 : mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1710 :
1711 : // Either register a Ray or get an already registered Ray id
1712 2519 : const RayID id = registerRay(name);
1713 :
1714 : // Acquire a Ray with the properly sized data initialized to zero
1715 2517 : return _parallel_ray_study->acquireParallelData(
1716 : /* tid = */ 0,
1717 5034 : this,
1718 : id,
1719 5034 : rayDataSize(),
1720 2517 : rayAuxDataSize(),
1721 2517 : /* reset = */ true,
1722 2517 : Ray::ConstructRayKey());
1723 : }
1724 :
1725 : std::shared_ptr<Ray>
1726 4035627 : RayTracingStudy::acquireCopiedRay(const Ray & ray)
1727 : {
1728 : mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1729 4035627 : return _parallel_ray_study->acquireParallelData(
1730 8071254 : /* tid = */ 0, &ray, Ray::ConstructRayKey());
1731 : }
1732 :
1733 : std::shared_ptr<Ray>
1734 82440 : RayTracingStudy::acquireRayDuringTrace(const THREAD_ID tid, const AcquireMoveDuringTraceKey &)
1735 : {
1736 : mooseAssert(currentlyPropagating(), "Can only use during propagation");
1737 82440 : return _parallel_ray_study->acquireParallelData(tid,
1738 164880 : this,
1739 82440 : generateUniqueRayID(tid),
1740 164880 : rayDataSize(),
1741 82440 : rayAuxDataSize(),
1742 82440 : /* reset = */ true,
1743 82440 : Ray::ConstructRayKey());
1744 : }
|