https://mooseframework.inl.gov
Loading...
Searching...
No Matches
RayTracingStudy.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 "RayTracingStudy.h"
11
12#include "AuxRayKernel.h"
14#include "RayKernel.h"
15#include "TraceRay.h"
16#include "TraceRayTools.h"
17#include "PeriodicRayBC.h"
18
19#include "AuxiliarySystem.h"
20#include "Assembly.h"
21#include "NonlinearSystemBase.h"
22
23#include "libmesh/enum_to_string.h"
24#include "libmesh/mesh_tools.h"
25#include "libmesh/parallel_sync.h"
26#include "libmesh/remote_elem.h"
27#include "libmesh/periodic_boundary.h"
28#include "libmesh/periodic_boundaries.h"
29
32{
33 auto params = GeneralUserObject::validParams();
34
35 // Parameters for the execution of the rays
37
38 params.addRangeCheckedParam<Real>("ray_distance",
39 std::numeric_limits<Real>::max(),
40 "ray_distance > 0",
41 "The maximum distance all Rays can travel");
42
43 params.addParam<bool>(
44 "tolerate_failure", false, "Whether or not to tolerate a ray tracing failure");
45
46 MooseEnum work_buffers("lifo circular", "circular");
47 params.addParam<MooseEnum>("work_buffer_type", work_buffers, "The work buffer type to use");
48
49 params.addParam<bool>(
50 "ray_kernel_coverage_check", true, "Whether or not to perform coverage checks on RayKernels");
51 params.addParam<bool>("warn_non_planar",
52 true,
53 "Whether or not to produce a warning if any element faces are non-planar.");
54
55 params.addParam<bool>(
56 "always_cache_traces",
57 false,
58 "Whether or not to cache the Ray traces on every execution, primarily for use in output. "
59 "Warning: this can get expensive very quick with a large number of rays!");
60 params.addParam<bool>("data_on_cache_traces",
61 false,
62 "Whether or not to also cache the Ray's data when caching its traces");
63 params.addParam<bool>("aux_data_on_cache_traces",
64 false,
65 "Whether or not to also cache the Ray's aux data when caching its traces");
66 params.addParam<bool>(
67 "segments_on_cache_traces",
68 true,
69 "Whether or not to cache individual segments when trace caching is enabled. If false, we "
70 "will instead cache a segment for each part of the trace where the direction is the same. "
71 "This minimizes the number of segments requied to represent the Ray's path, but removes the "
72 "ability to show Ray field data on each segment through an element.");
73
74 params.addParam<bool>("use_internal_sidesets",
75 false,
76 "Whether or not to use internal sidesets for RayBCs in ray tracing");
77
78 params.addParam<bool>("warn_subdomain_hmax",
79 true,
80 "Whether or not to warn if the approximated hmax (constant on subdomain) "
81 "varies significantly for an element");
82
83 params.addParam<bool>(
84 "verify_rays",
85 true,
86 "Whether or not to verify the generated Rays. This includes checking their "
87 "starting information and the uniqueness of Rays before and after execution. This is also "
88 "used by derived studies for more specific verification.");
89 params.addParam<bool>("verify_trace_intersections",
90 true,
91 "Whether or not to verify the trace intersections in devel and dbg modes. "
92 "Trace intersections are not verified regardless of this parameter in "
93 "optimized modes (opt, oprof).");
94
95 params.addParam<bool>("allow_other_flags_with_prekernels",
96 false,
97 "Whether or not to allow the list of execution flags to have PRE_KERNELS "
98 "mixed with other flags. If this parameter is not set then if PRE_KERNELS "
99 "is provided it must be the only execution flag.");
100
101 ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
103
104 params.addParamNamesToGroup(
105 "always_cache_traces data_on_cache_traces aux_data_on_cache_traces segments_on_cache_traces",
106 "Trace cache");
107 params.addParamNamesToGroup("warn_non_planar warn_subdomain_hmax", "Tracing Warnings");
108 params.addParamNamesToGroup("ray_kernel_coverage_check verify_rays verify_trace_intersections",
109 "Checks and verifications");
110
111 // Whether or not each Ray must be registered using the registerRay() API
112 params.addPrivateParam<bool>("_use_ray_registration", true);
113 // Whether or not to bank Rays on completion
114 params.addPrivateParam<bool>("_bank_rays_on_completion", true);
116 params.addPrivateParam<bool>("_ray_dependent_subdomain_setup", true);
117
118 // Add a point neighbor relationship manager
119 params.addRelationshipManager("ElementPointNeighborLayers",
120 Moose::RelationshipManagerType::GEOMETRIC |
121 Moose::RelationshipManagerType::ALGEBRAIC,
122 [](const InputParameters &, InputParameters & rm_params)
123 { rm_params.set<unsigned short>("layers") = 1; });
124
125 return params;
126}
127
129 : GeneralUserObject(parameters),
130 _mesh(_fe_problem.mesh()),
131 _comm(_mesh.comm()),
132 _pid(_comm.rank()),
133
134 _ray_kernel_coverage_check(getParam<bool>("ray_kernel_coverage_check")),
135 _warn_non_planar(getParam<bool>("warn_non_planar")),
136 _use_ray_registration(getParam<bool>("_use_ray_registration")),
137 _use_internal_sidesets(getParam<bool>("use_internal_sidesets")),
138 _tolerate_failure(getParam<bool>("tolerate_failure")),
139 _bank_rays_on_completion(getParam<bool>("_bank_rays_on_completion")),
140 _ray_dependent_subdomain_setup(getParam<bool>("_ray_dependent_subdomain_setup")),
141
142 _always_cache_traces(getParam<bool>("always_cache_traces")),
143 _data_on_cache_traces(getParam<bool>("data_on_cache_traces")),
144 _aux_data_on_cache_traces(getParam<bool>("aux_data_on_cache_traces")),
145 _segments_on_cache_traces(getParam<bool>("segments_on_cache_traces")),
146 _ray_max_distance(getParam<Real>("ray_distance")),
147 _verify_rays(getParam<bool>("verify_rays")),
148#ifndef NDEBUG
149 _verify_trace_intersections(getParam<bool>("verify_trace_intersections")),
150#endif
151
152 _threaded_elem_side_builders(libMesh::n_threads()),
153
154 _registered_ray_map(
155 declareRestartableData<std::unordered_map<std::string, RayID>>("registered_ray_map")),
156 _reverse_registered_ray_map(
157 declareRestartableData<std::vector<std::string>>("reverse_registered_ray_map")),
158
159 _threaded_cached_traces(libMesh::n_threads()),
160
161 _num_cached(libMesh::n_threads(), 0),
162
163 _has_non_planar_sides(true),
164 _has_same_level_active_elems(sameLevelActiveElems()),
165
166 _b_box(MeshTools::create_nodal_bounding_box(_mesh.getMesh())),
167 _domain_max_length(1.01 * (_b_box.max() - _b_box.min()).norm()),
168 _total_volume(computeTotalVolume()),
169
170 _threaded_cache_ray_kernel(libMesh::n_threads()),
171 _threaded_cache_ray_bc(libMesh::n_threads()),
172 _threaded_ray_object_registration(libMesh::n_threads()),
173 _threaded_current_ray_kernels(libMesh::n_threads()),
174 _threaded_trace_ray(libMesh::n_threads()),
175 _threaded_fe_face(libMesh::n_threads()),
176 _threaded_q_face(libMesh::n_threads()),
177 _threaded_cached_normals(libMesh::n_threads()),
178 _threaded_next_ray_id(libMesh::n_threads()),
179
180 _parallel_ray_study(std::make_unique<ParallelRayStudy>(*this, _threaded_trace_ray)),
181
182 _local_trace_ray_results(TraceRay::FAILED_TRACES + 1, 0),
183
184 _called_initial_setup(false),
185
186 _elem_index_helper(_mesh.getMesh(), name() + "_elem_index")
187{
188 // Initialize a tracing object for each thread
189 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
190 {
191 // Initialize a tracing object for each thread
192 _threaded_trace_ray[tid] = std::make_shared<TraceRay>(*this, tid);
193
194 // Setup the face FEs for normal computation on the fly
195 _threaded_fe_face[tid] = FEBase::build(_mesh.dimension(), FEType(CONSTANT, MONOMIAL));
196 _threaded_q_face[tid] = QBase::build(libMesh::QGAUSS, _mesh.dimension() - 1, CONSTANT);
197 _threaded_fe_face[tid]->attach_quadrature_rule(_threaded_q_face[tid].get());
198 _threaded_fe_face[tid]->get_normals();
199 }
200
201 // Evaluating on residual and Jacobian evaluation
203 {
204 if (!getParam<bool>("allow_other_flags_with_prekernels") && _execute_enum.size() > 1)
205 paramError("execute_on",
206 "PRE_KERNELS cannot be mixed with any other execution flag.\nThat is, you cannot "
207 "currently "
208 "mix RayKernels that contribute to the Jacobian/residual with those that do not.");
209
210 if (_app.useEigenvalue())
211 mooseError("Execution on residual and Jacobian evaluation (execute_on = PRE_KERNELS)\n",
212 "is not supported for an eigenvalue solve.");
213 }
214
217
218 // Scale the bounding box for loose checking
220 _loose_b_box.scale(TOLERANCE * TOLERANCE);
221}
222
223void
225{
226 // Keep track of initialSetup call to avoid registration of various things
228
229 // Sets up a local index for each elem this proc knows about
231
232 // Check for RayKernel coverage
234
235 // Make sure the dependencies exist, if any
237
238 // Check for traceable element types
240
241 // Check for sane periodic boundaries
243
244 // Setup for internal sidesets
246
248
249 // Setup approximate hmax for each subdomain
251
252 // Call initial setup on all of the objects
253 for (auto & rto : getRayTracingObjects())
254 rto->initialSetup();
255
256 // Check for proper exec flags with RayKernels
257 std::vector<RayKernelBase *> ray_kernels;
258 getRayKernels(ray_kernels, 0);
259 for (const auto & rkb : ray_kernels)
260 if (dynamic_cast<RayKernel *>(rkb) && !_execute_enum.isValueSet(EXEC_PRE_KERNELS))
261 mooseError("This study has RayKernel objects that contribute to residuals and Jacobians.",
262 "\nIn this case, the study must use the execute_on = PRE_KERNELS");
263
264 // Build 1D quadrature rule for along a segment
265 _segment_qrule = QBase::build(
267}
268
269void
271{
272 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
273 mooseAssert(_num_cached[tid] == 0, "Cached residuals/Jacobians not empty");
274
275 for (auto & rto : getRayTracingObjects())
276 rto->residualSetup();
277}
278
279void
281{
282 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
283 mooseAssert(_num_cached[tid] == 0, "Cached residuals/Jacobians not empty");
284
285 for (auto & rto : getRayTracingObjects())
286 rto->jacobianSetup();
287}
288
289void
291{
292 for (auto & rto : getRayTracingObjects())
293 rto->timestepSetup();
294}
295
296void
298{
303
305
306 for (const auto & trace_ray : _threaded_trace_ray)
307 trace_ray->meshChanged();
308}
309
310void
315
316void
318{
319 // Check for coverage of RayKernels on domain
321 {
322 std::vector<RayKernelBase *> ray_kernels;
323 getRayKernels(ray_kernels, 0);
324
325 std::set<SubdomainID> ray_kernel_blocks;
326 for (const auto & rk : ray_kernels)
327 ray_kernel_blocks.insert(rk->blockIDs().begin(), rk->blockIDs().end());
328
329 std::set<SubdomainID> missing;
330 std::set_difference(_mesh.meshSubdomains().begin(),
331 _mesh.meshSubdomains().end(),
332 ray_kernel_blocks.begin(),
333 ray_kernel_blocks.end(),
334 std::inserter(missing, missing.begin()));
335
336 if (!missing.empty() && !ray_kernel_blocks.count(Moose::ANY_BLOCK_ID))
337 {
338 std::ostringstream error;
339 error << "Subdomains { ";
340 std::copy(missing.begin(), missing.end(), std::ostream_iterator<SubdomainID>(error, " "));
341 error << "} do not have RayKernels defined!";
342
343 mooseError(error.str());
344 }
345 }
346}
347
348void
350{
351 std::vector<RayTracingObject *> ray_tracing_objects;
352
353 getRayKernels(ray_tracing_objects, 0);
354 verifyDependenciesExist(ray_tracing_objects);
355
356 getRayBCs(ray_tracing_objects, 0);
357 verifyDependenciesExist(ray_tracing_objects);
358}
359
360void
361RayTracingStudy::verifyDependenciesExist(const std::vector<RayTracingObject *> & rtos)
362{
363 for (const auto & rto : rtos)
364 for (const auto & dep_name : rto->getRequestedItems())
365 {
366 bool found = false;
367 for (const auto & rto_search : rtos)
368 if (rto_search->name() == dep_name)
369 {
370 found = true;
371 break;
372 }
373
374 if (!found)
375 rto->paramError("depends_on", "The ", rto->getBase(), " '", dep_name, "' does not exist");
376 }
377}
378
379void
381{
382 for (const auto & elem : *_mesh.getActiveLocalElementRange())
383 {
385 {
387 mooseError("Element type ",
388 Utility::enum_to_string(elem->type()),
389 " is not supported in ray tracing with adaptivity");
390 }
391 else if (!TraceRayTools::isTraceableElem(elem))
392 mooseError("Element type ",
393 Utility::enum_to_string(elem->type()),
394 " is not supported in ray tracing");
395 }
396}
397
398void
400{
401 // Collect the PeriodicRayBCs
402 std::vector<const RayBoundaryConditionBase *> rbc_ptrs;
403 getRayBCs(rbc_ptrs, 0);
404 std::vector<const PeriodicRayBC *> prbc_ptrs;
405 for (const auto rbc_ptr : rbc_ptrs)
406 if (const auto prbc_ptr = dynamic_cast<const PeriodicRayBC *>(rbc_ptr))
407 prbc_ptrs.push_back(prbc_ptr);
408 if (prbc_ptrs.empty())
409 return;
410
411 // Collect each of the periodic boundaries
412 std::map<boundary_id_type,
413 std::tuple<const PeriodicRayBC *,
415 std::unordered_set<dof_id_type>>>
416 boundary_map;
417 for (const auto prbc_ptr : prbc_ptrs)
418 {
419 for (const auto & [bid, pb] : prbc_ptr->getPeriodicBoundaries())
420 {
421 const auto [it, inserted] = boundary_map.emplace(
422 std::piecewise_construct,
423 std::tuple{bid},
424 std::forward_as_tuple(prbc_ptr, pb.get(), std::unordered_set<dof_id_type>()));
425 if (!inserted)
426 prbc_ptr->mooseError("The periodic boundary '",
428 "' has been defined in both ",
429 prbc_ptr->typeAndName(),
430 " and ",
431 std::get<0>(it->second)->typeAndName());
432 }
433 }
434
435 // Because we don't have ghosting setup correctly yet, we need to check if any
436 // of the periodic boundaries are neighbors with distributed mesh. If the
437 // mesh is replicated, we don't need to check this. See #31280.
438 if (comm().size() == 1 || !_mesh.isDistributedMesh())
439 return;
440
441 // Collect all of the nodes that are on each periodic boundary
442 const auto & sideset_map = _mesh.getMesh().get_boundary_info().get_sideset_map();
443 for (const auto & [elem, side_bid_pair] : sideset_map)
444 {
445 const auto [side, bid] = side_bid_pair;
446 if (auto it = boundary_map.find(bid); it != boundary_map.end())
447 for (const auto n : elem->nodes_on_side(side))
448 std::get<2>(it->second).insert(elem->node_ref(n).id());
449 }
450
451 // Distributed meshes have distributed boundary information, so sync
452 for (auto & bid_tuple_pair : boundary_map)
453 comm().set_union(std::get<2>(bid_tuple_pair.second));
454
455 // Check for periodic boundaries that share nodes
456 std::map<std::pair<boundary_id_type, boundary_id_type>,
457 std::pair<const PeriodicRayBC *, const PeriodicRayBC *>>
458 warn_boundaries;
459 for (auto it = boundary_map.begin(); it != boundary_map.end(); ++it)
460 {
461 const auto & [bid, tup] = *it;
462 const auto [prbc_ptr, pb, node_ids] = tup;
463
464 for (auto other_it = std::next(it); other_it != boundary_map.end(); ++other_it)
465 {
466 const auto & [other_bid, other_tup] = *other_it;
467
468 // Don't check against boundaries that are paried together
469 if (pb->pairedboundary == other_bid)
470 continue;
471
472 const auto other_prbc_ptr = std::get<0>(other_tup);
473 const auto & other_node_ids = std::get<2>(other_tup);
474 for (const auto node_id : node_ids)
475 if (other_node_ids.count(node_id))
476 {
477 if (!warn_boundaries.count(std::make_pair(other_bid, bid)))
478 warn_boundaries.emplace(std::make_pair(bid, other_bid),
479 std::make_pair(prbc_ptr, other_prbc_ptr));
480 break;
481 }
482 }
483 }
484
485 if (warn_boundaries.size())
486 {
487 std::ostringstream oss;
488 oss << warn_boundaries.size()
489 << " ray tracing periodic boundaries were found to be neighbors:\n\n";
490 for (const auto & [bids_pair, prbc_ptrs_pair] : warn_boundaries)
491 {
492 const auto [bid, paired_bid] = bids_pair;
493 const auto [prbc_ptr, paired_prbc_ptr] = prbc_ptrs_pair;
494 oss << " '" << _mesh.getBoundaryString(bid) << "' (in " << prbc_ptr->typeAndName()
495 << ") <-> '" << _mesh.getBoundaryString(paired_bid) << "' (in "
496 << paired_prbc_ptr->typeAndName() << ")\n";
497 }
498 oss << "\nThe periodic propagation of rays at points where two or more periodic"
499 << "\nboundaries meet is not fully supported with a distributed mesh."
500 << "\n\nIf you encounter trace failures, you should use a replicated mesh.";
501 mooseWarning(oss.str());
502 }
503}
504
505void
507{
508 // TODO: We could probably minimize this to local active elements followed by
509 // boundary point neighbors, but if using distibuted mesh it really shouldn't matter
510 _elem_index_helper.initialize(_mesh.getMesh().active_element_ptr_range());
511}
512
513void
515{
516 // Even if we have _use_internal_sidesets == false, we will make sure the user didn't add RayBCs
517 // on internal boundaries
518
519 // Clear the data structures and size the map based on the elements that we know about
520 _internal_sidesets.clear();
523
524 // First, we are going to store all elements with internal sidesets (if any) that have active
525 // RayBCs on them as elem -> vector of (side, vector of boundary ids)
526 for (const auto & bnd_elem : *_mesh.getBoundaryElementRange())
527 {
528 Elem * elem = bnd_elem->_elem;
529 const unsigned int side = bnd_elem->_side;
530 const auto bnd_id = bnd_elem->_bnd_id;
531
532 // Not internal
533 const Elem * const neighbor = elem->neighbor_ptr(side);
534 if (!neighbor || neighbor == remote_elem)
535 continue;
536
537 // No RayBCs on this sideset
538 std::vector<RayBoundaryConditionBase *> result;
539 getRayBCs(result, bnd_id, 0);
540 if (result.empty())
541 continue;
542
543 if (neighbor->subdomain_id() == elem->subdomain_id())
544 mooseError("RayBCs exist on internal sidesets that are not bounded by a different",
545 "\nsubdomain on each side.",
546 "\n\nIn order to use RayBCs on internal sidesets, said sidesets must have",
547 "\na different subdomain on each side.");
548
549 // Mark that this boundary is an internal sideset with RayBC(s)
550 _internal_sidesets.insert(bnd_id);
551
552 // Get elem's entry in the internal sidset data structure
553 const auto index = _elem_index_helper.getIndex(elem);
554 auto & entry = _internal_sidesets_map[index];
555
556 // Initialize this elem's sides if they have not been already
557 if (entry.empty())
558 entry.resize(elem->n_sides(), std::vector<BoundaryID>());
559
560 // Add the internal boundary to the side entry
561 entry[side].push_back(bnd_id);
562 }
563
565 mooseError("RayBCs are defined on internal sidesets, but the study is not set to use ",
566 "internal sidesets during tracing.",
567 "\n\nSet the parameter use_internal_sidesets = true to enable this capability.");
568}
569
570void
572{
573 _has_non_planar_sides = false;
574 bool warned = !_warn_non_planar;
575
576 // Nothing to do here for 2D or 1D
577 if (_mesh.dimension() != 3)
578 return;
579
580 // Clear the data structure and size it based on the elements that we know about
581 _non_planar_sides.clear();
583
584 for (const Elem * elem : _mesh.getMesh().active_element_ptr_range())
585 {
586 const auto index = _elem_index_helper.getIndex(elem);
587 auto & entry = _non_planar_sides[index];
588 entry.resize(elem->n_sides(), 0);
589
590 for (const auto s : elem->side_index_range())
591 {
592 const auto & side = elemSide(*elem, s);
593 if (side.n_vertices() < 4)
594 continue;
595
596 if (!side.has_affine_map())
597 {
598 entry[s] = 1;
600
601 if (!warned)
602 {
603 mooseWarning("The mesh contains non-planar faces.\n\n",
604 "Ray tracing on non-planar faces is an approximation and may fail.\n\n",
605 "Use at your own risk! You can disable this warning by setting the\n",
606 "parameter 'warn_non_planar' to false.");
607 warned = true;
608 }
609 }
610 }
611 }
612}
613
614void
616{
617 // Setup map with subdomain keys
618 _subdomain_hmax.clear();
619 for (const auto subdomain_id : _mesh.meshSubdomains())
620 _subdomain_hmax[subdomain_id] = std::numeric_limits<Real>::min();
621
622 // Set local max for each subdomain
623 for (const auto & elem : *_mesh.getActiveLocalElementRange())
624 {
625 auto & entry = _subdomain_hmax.at(elem->subdomain_id());
626 entry = std::max(entry, elem->hmax());
627 }
628
629 // Accumulate global max for each subdomain
631
632 if (getParam<bool>("warn_subdomain_hmax"))
633 {
634 const auto warn_prefix = type() + " '" + name() + "': ";
635 const auto warn_suffix =
636 "\n\nRay tracing uses an approximate element size for each subdomain to scale the\n"
637 "tolerances used in computing ray intersections. This warning suggests that the\n"
638 "approximate element size is not a good approximation. This is likely due to poor\n"
639 "element aspect ratios.\n\n"
640 "This warning is only output for the first element affected.\n"
641 "To disable this warning, set warn_subdomain_hmax = false.\n";
642
643 for (const auto & elem : *_mesh.getActiveLocalElementRange())
644 {
645 const auto hmin = elem->hmin();
646 const auto hmax = elem->hmax();
647 const auto max_hmax = subdomainHmax(elem->subdomain_id());
648
649 const auto hmax_rel = hmax / max_hmax;
650 if (hmax_rel < 1.e-2 || hmax_rel > 1.e2)
651 mooseDoOnce(mooseWarning(warn_prefix,
652 "Element hmax varies significantly from subdomain hmax.\n",
653 warn_suffix,
654 "First element affected:\n",
655 Moose::stringify(*elem)););
656
657 const auto h_rel = max_hmax / hmin;
658 if (h_rel > 1.e2)
659 mooseDoOnce(mooseWarning(warn_prefix,
660 "Element hmin varies significantly from subdomain hmax.\n",
661 warn_suffix,
662 "First element affected:\n",
663 Moose::stringify(*elem)););
664 }
665 }
666}
667
668void
670{
671 // First, clear the objects associated with each Ray on each thread
672 const auto num_rays = _registered_ray_map.size();
673 for (auto & entry : _threaded_ray_object_registration)
674 {
675 entry.clear();
676 entry.resize(num_rays);
677 }
678
679 const auto rtos = getRayTracingObjects();
680
682 {
683 // All of the registered ray names - used when a RayTracingObject did not specify
684 // any Rays so it should be associated with all Rays.
685 std::vector<std::string> all_ray_names;
686 all_ray_names.reserve(_registered_ray_map.size());
687 for (const auto & pair : _registered_ray_map)
688 all_ray_names.push_back(pair.first);
689
690 for (auto & rto : rtos)
691 {
692 // The Ray names associated with this RayTracingObject
693 const auto & ray_names = rto->parameters().get<std::vector<std::string>>("rays");
694 // The registration for RayTracingObjects for the thread rto is on
695 const auto tid = rto->parameters().get<THREAD_ID>("_tid");
696 auto & registration = _threaded_ray_object_registration[tid];
697
698 // Register each Ray for this object in the registration
699 for (const auto & ray_name : (ray_names.empty() ? all_ray_names : ray_names))
700 {
701 const auto id = registeredRayID(ray_name, /* graceful = */ true);
702 if (ray_names.size() && id == Ray::INVALID_RAY_ID)
703 rto->paramError(
704 "rays", "Supplied ray '", ray_name, "' is not a registered Ray in ", typeAndName());
705 registration[id].insert(rto);
706 }
707 }
708 }
709 // Not using Ray registration
710 else
711 {
712 for (const auto & rto : rtos)
713 if (rto->parameters().get<std::vector<std::string>>("rays").size())
714 rto->paramError(
715 "rays",
716 "Rays cannot be supplied when the study does not require Ray registration.\n\n",
717 type(),
718 " does not require Ray registration.");
719 }
720}
721
722void
724{
725 std::set<std::string> vars_to_be_zeroed;
726 std::vector<RayKernelBase *> ray_kernels;
727 getRayKernels(ray_kernels, 0);
728 for (auto & rk : ray_kernels)
729 {
730 AuxRayKernel * aux_rk = dynamic_cast<AuxRayKernel *>(rk);
731 if (aux_rk)
732 vars_to_be_zeroed.insert(aux_rk->variable().name());
733 }
734
735 std::vector<std::string> vars_to_be_zeroed_vec(vars_to_be_zeroed.begin(),
736 vars_to_be_zeroed.end());
737 _fe_problem.getAuxiliarySystem().zeroVariables(vars_to_be_zeroed_vec);
738}
739
740void
742 const THREAD_ID tid,
743 const RayID ray_id)
744{
745 mooseAssert(currentlyPropagating(), "Should not call while not propagating");
746
747 // Call subdomain setup on FE
748 _fe_problem.subdomainSetup(subdomain, tid);
749
750 std::set<MooseVariableFEBase *> needed_moose_vars;
751 std::unordered_set<unsigned int> needed_mat_props;
752
753 // Get RayKernels and their dependencies and call subdomain setup
754 getRayKernels(_threaded_current_ray_kernels[tid], subdomain, tid, ray_id);
755 for (auto & rkb : _threaded_current_ray_kernels[tid])
756 {
757 rkb->subdomainSetup();
758
759 const auto & mv_deps = rkb->getMooseVariableDependencies();
760 needed_moose_vars.insert(mv_deps.begin(), mv_deps.end());
761
762 const auto & mp_deps = rkb->getMatPropDependencies();
763 needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
764 }
765
766 // Prepare aux vars
767 for (auto & var : needed_moose_vars)
768 if (var->kind() == Moose::VarKindType::VAR_AUXILIARY)
769 var->prepareAux();
770
771 _fe_problem.setActiveElementalMooseVariables(needed_moose_vars, tid);
772 _fe_problem.prepareMaterials(needed_mat_props, subdomain, tid);
773}
774
775void
777 const Elem * elem, const Point & start, const Point & end, const Real length, THREAD_ID tid)
778{
779 mooseAssert(MooseUtils::absoluteFuzzyEqual((start - end).norm(), length), "Invalid length");
780 mooseAssert(currentlyPropagating(), "Should not call while not propagating");
781
783
784 // If we have any variables or material properties that are active, we definitely need to reinit
787 // If not, make sure that the RayKernels have not requested a reinit (this could happen when a
788 // RayKernel doesn't have variables or materials but still does an integration and needs qps)
789 if (!reinit)
790 for (const RayKernelBase * rk : currentRayKernels(tid))
791 if (rk->needSegmentReinit())
792 {
793 reinit = true;
794 break;
795 }
796
797 if (reinit)
798 {
799 _fe_problem.prepare(elem, tid);
800
801 std::vector<Point> points;
802 std::vector<Real> weights;
803 buildSegmentQuadrature(start, end, length, points, weights);
804 _fe_problem.reinitElemPhys(elem, points, tid);
806
807 _fe_problem.reinitMaterials(elem->subdomain_id(), tid);
808 }
809}
810
811void
813 const Point & end,
814 const Real length,
815 std::vector<Point> & points,
816 std::vector<Real> & weights) const
817{
818 points.resize(_segment_qrule->n_points());
819 weights.resize(_segment_qrule->n_points());
820
821 const Point diff = end - start;
822 const Point sum = end + start;
823 mooseAssert(MooseUtils::absoluteFuzzyEqual(length, diff.norm()), "Invalid length");
824
825 // The standard quadrature rule should be on x = [-1, 1]
826 // To scale the points, you...
827 // - Scale to size of the segment in 3D
828 // initial_scaled_qp = x_qp * 0.5 * (end - start) = 0.5 * x_qp * diff
829 // - Shift quadrature midpoint to segment midpoint
830 // final_qp = initial_scaled_qp + 0.5 * (end - start) = initial_scaled_qp + 0.5 * sum
831 // = 0.5 * (x_qp * diff + sum)
832 for (unsigned int qp = 0; qp < _segment_qrule->n_points(); ++qp)
833 {
834 points[qp] = 0.5 * (_segment_qrule->qp(qp)(0) * diff + sum);
835 weights[qp] = 0.5 * _segment_qrule->w(qp) * length;
836 }
837}
838
839void
840RayTracingStudy::postOnSegment(const THREAD_ID tid, const std::shared_ptr<Ray> & /* ray */)
841{
842 mooseAssert(currentlyPropagating(), "Should not call while not propagating");
844 mooseAssert(_num_cached[tid] == 0,
845 "Values should only be cached when computing Jacobian/residual");
846
847 // Fill into cached Jacobian/residuals if necessary
849 {
851
852 if (++_num_cached[tid] == 20)
853 {
854 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
856 _num_cached[tid] = 0;
857 }
858 }
860 {
862
863 if (++_num_cached[tid] == 20)
864 {
865 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
867 _num_cached[tid] = 0;
868 }
869 }
870}
871
872void
874{
875 TIME_SECTION("executeStudy", 2, "Executing Study");
876
877 mooseAssert(_called_initial_setup, "Initial setup not called");
878
879 // Reset ray start/complete timers
883
884 // Reset physical tracing stats
885 for (auto & val : _local_trace_ray_results)
886 val = 0;
887
888 // Reset crossing and intersection
896 _total_distance = 0;
897
898 // Zero the AuxVariables that our AuxRayKernels contribute to before they accumulate
900
902 for (auto & rto : getRayTracingObjects())
903 rto->preExecuteStudy();
904
905 _ray_bank.clear();
906
907 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
908 {
909 _threaded_trace_ray[tid]->preExecute();
910 _threaded_cached_normals[tid].clear();
911 }
912
914 _execution_start_time = std::chrono::steady_clock::now();
915
916 _parallel_ray_study->preExecute();
917
918 {
919 {
920 auto generation_start_time = std::chrono::steady_clock::now();
921
922 TIME_SECTION("generateRays", 2, "Generating Rays");
923
924 generateRays();
925
926 _generation_time = std::chrono::steady_clock::now() - generation_start_time;
927 }
928
929 // At this point, nobody is working so this is good time to make sure
930 // Rays are unique across all processors in the working buffer
931 if (verifyRays())
932 {
933 verifyUniqueRays(_parallel_ray_study->workBuffer().begin(),
934 _parallel_ray_study->workBuffer().end(),
935 /* error_suffix = */ "after generateRays()");
936
937 verifyUniqueRayIDs(_parallel_ray_study->workBuffer().begin(),
938 _parallel_ray_study->workBuffer().end(),
939 /* global = */ true,
940 /* error_suffix = */ "after generateRays()");
941 }
942
944
945 {
946 TIME_SECTION("propagateRays", 2, "Propagating Rays");
947
948 const auto propagation_start_time = std::chrono::steady_clock::now();
949
950 _parallel_ray_study->execute();
951
952 _propagation_time = std::chrono::steady_clock::now() - propagation_start_time;
953 }
954 }
955
956 _execution_time = std::chrono::steady_clock::now() - _execution_start_time;
957
958 if (verifyRays())
959 {
960 verifyUniqueRays(_parallel_ray_study->workBuffer().begin(),
961 _parallel_ray_study->workBuffer().end(),
962 /* error_suffix = */ "after tracing completed");
963
964#ifndef NDEBUG
965 // Outside of debug, _ray_bank always holds all of the Rays that have ended on this processor
966 // We can use this as a global point to check for unique IDs for every Ray that has traced
968 _ray_bank.end(),
969 /* global = */ true,
970 /* error_suffix = */ "after tracing completed");
971#endif
972 }
973
974 // Update counters from the threaded trace objects
975 for (const auto & tr : _threaded_trace_ray)
976 for (std::size_t i = 0; i < _local_trace_ray_results.size(); ++i)
977 _local_trace_ray_results[i] += tr->results()[i];
978
979 // Update local ending counters
986 // ...and communicate the global values
993
994 // Throw a warning with the number of failed (tolerated) traces
996 {
998 _communicator.sum(failures);
999 if (failures)
1001 type(), " '", name(), "': ", failures, " ray tracing failures were tolerated.\n");
1002 }
1003
1004 // Clear the current RayKernels
1005 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1007
1008 // Move the threaded cache trace information into the full cached trace vector
1009 // Here, we only clear the cached vectors so that we might not have to
1010 // reallocate on future traces
1011 std::size_t num_entries = 0;
1012 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1013 num_entries += _threaded_cached_traces[tid].size();
1014 _cached_traces.clear();
1015 _cached_traces.reserve(num_entries);
1016 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1017 {
1018 for (const auto & entry : _threaded_cached_traces[tid])
1019 _cached_traces.emplace_back(std::move(entry));
1020 _threaded_cached_traces[tid].clear();
1021 }
1022
1023 // Add any stragglers that contribute to the Jacobian or residual
1024 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1025 if (_num_cached[tid] != 0)
1026 {
1029 "Should not have cached values without Jacobian/residual computation");
1030
1033 else
1035
1036 _num_cached[tid] = 0;
1037 }
1038
1039 // AuxRayKernels may have modified AuxVariables
1042
1043 // Clear FE
1044 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1045 {
1048 }
1049
1051 for (auto & rto : getRayTracingObjects())
1052 rto->postExecuteStudy();
1053}
1054
1055void
1056RayTracingStudy::onCompleteRay(const std::shared_ptr<Ray> & ray)
1057{
1058 mooseAssert(currentlyPropagating(), "Should only be called during Ray propagation");
1059
1060 _ending_processor_crossings += ray->processorCrossings();
1062 std::max(_ending_max_processor_crossings, ray->processorCrossings());
1063 _ending_intersections += ray->intersections();
1064 _ending_max_intersections = std::max(_ending_max_intersections, ray->intersections());
1066 std::max(_ending_max_trajectory_changes, ray->trajectoryChanges());
1067 _ending_distance += ray->distance();
1068
1069#ifdef NDEBUG
1070 // In non-opt modes, we will always bank the Rays for debugging
1072#endif
1073 _ray_bank.emplace_back(ray);
1074}
1075
1077RayTracingStudy::registerRayDataInternal(const std::string & name, const bool aux)
1078{
1079 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1080
1082 mooseError("Cannot register Ray ", (aux ? "aux " : ""), "data after initialSetup()");
1083
1084 auto & map = aux ? _ray_aux_data_map : _ray_data_map;
1085 const auto find = map.find(name);
1086 if (find != map.end())
1087 return find->second;
1088
1089 auto & other_map = aux ? _ray_data_map : _ray_aux_data_map;
1090 if (other_map.find(name) != other_map.end())
1091 mooseError("Cannot register Ray aux data with name ",
1092 name,
1093 " because Ray ",
1094 (aux ? "(non-aux)" : "aux"),
1095 " data already exists with said name.");
1096
1097 // Add into the name -> index map
1098 map.emplace(name, map.size());
1099
1100 // Add into the index -> names vector
1101 auto & vector = aux ? _ray_aux_data_names : _ray_data_names;
1102 vector.push_back(name);
1103
1104 return map.size() - 1;
1105}
1106
1107std::vector<RayDataIndex>
1108RayTracingStudy::registerRayDataInternal(const std::vector<std::string> & names, const bool aux)
1109{
1110 std::vector<RayDataIndex> indices(names.size());
1111 for (std::size_t i = 0; i < names.size(); ++i)
1112 indices[i] = registerRayDataInternal(names[i], aux);
1113 return indices;
1114}
1115
1118 const bool aux,
1119 const bool graceful) const
1120{
1121 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1122
1123 const auto & map = aux ? _ray_aux_data_map : _ray_data_map;
1124 const auto find = map.find(name);
1125 if (find != map.end())
1126 return find->second;
1127
1128 if (graceful)
1130
1131 const auto & other_map = aux ? _ray_data_map : _ray_aux_data_map;
1132 if (other_map.find(name) != other_map.end())
1133 mooseError("Ray data with name '",
1134 name,
1135 "' was not found.\n\n",
1136 "However, Ray ",
1137 (aux ? "non-aux" : "aux"),
1138 " data with said name was found.\n",
1139 "Did you mean to use ",
1140 (aux ? "getRayDataIndex()/getRayDataIndices()?"
1141 : "getRayAuxDataIndex()/getRayAuxDataIndices()"),
1142 "?");
1143
1144 mooseError("Unknown Ray ", (aux ? "aux " : ""), "data with name ", name);
1145}
1146
1147std::vector<RayDataIndex>
1148RayTracingStudy::getRayDataIndicesInternal(const std::vector<std::string> & names,
1149 const bool aux,
1150 const bool graceful) const
1151{
1152 std::vector<RayDataIndex> indices(names.size());
1153 for (std::size_t i = 0; i < names.size(); ++i)
1154 indices[i] = getRayDataIndexInternal(names[i], aux, graceful);
1155 return indices;
1156}
1157
1158const std::string &
1160{
1161 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1162
1163 if ((aux ? rayAuxDataSize() : rayDataSize()) < index)
1164 mooseError("Unknown Ray ", aux ? "aux " : "", "data with index ", index);
1165 return aux ? _ray_aux_data_names[index] : _ray_data_names[index];
1166}
1167
1170{
1171 return registerRayDataInternal(name, /* aux = */ false);
1172}
1173
1174std::vector<RayDataIndex>
1175RayTracingStudy::registerRayData(const std::vector<std::string> & names)
1176{
1177 return registerRayDataInternal(names, /* aux = */ false);
1178}
1179
1181RayTracingStudy::getRayDataIndex(const std::string & name, const bool graceful /* = false */) const
1182{
1183 return getRayDataIndexInternal(name, /* aux = */ false, graceful);
1184}
1185
1186std::vector<RayDataIndex>
1187RayTracingStudy::getRayDataIndices(const std::vector<std::string> & names,
1188 const bool graceful /* = false */) const
1189{
1190 return getRayDataIndicesInternal(names, /* aux = */ false, graceful);
1191}
1192
1193const std::string &
1195{
1196 return getRayDataNameInternal(index, /* aux = */ false);
1197}
1198
1201{
1202 return registerRayDataInternal(name, /* aux = */ true);
1203}
1204
1205std::vector<RayDataIndex>
1206RayTracingStudy::registerRayAuxData(const std::vector<std::string> & names)
1207{
1208 return registerRayDataInternal(names, /* aux = */ true);
1209}
1210
1213 const bool graceful /* = false */) const
1214{
1215 return getRayDataIndexInternal(name, /* aux = */ true, graceful);
1216}
1217
1218std::vector<RayDataIndex>
1219RayTracingStudy::getRayAuxDataIndices(const std::vector<std::string> & names,
1220 const bool graceful /* = false */) const
1221{
1222 return getRayDataIndicesInternal(names, /* aux = */ true, graceful);
1223}
1224
1225const std::string &
1227{
1228 return getRayDataNameInternal(index, /* aux = */ true);
1229}
1230
1231bool
1233{
1234 std::vector<RayKernelBase *> result;
1235 getRayKernels(result, tid);
1236 return result.size();
1237}
1238
1239void
1240RayTracingStudy::getRayKernels(std::vector<RayKernelBase *> & result, SubdomainID id, THREAD_ID tid)
1241{
1242 // If the cache doesn't have any attributes yet, it means that we haven't set
1243 // the conditions yet. We do this so that it can be generated on the fly on first use.
1244 if (!_threaded_cache_ray_kernel[tid].numAttribs())
1245 {
1247 mooseError("Should not call getRayKernels() before initialSetup()");
1248
1250 .query()
1251 .condition<AttribRayTracingStudy>(this)
1252 .condition<AttribSystem>("RayKernel")
1253 .condition<AttribThread>(tid);
1254 _threaded_cache_ray_kernel[tid] = query.clone();
1255 }
1256
1257 _threaded_cache_ray_kernel[tid].queryInto(result, id);
1258}
1259
1260void
1261RayTracingStudy::getRayKernels(std::vector<RayKernelBase *> & result,
1262 SubdomainID id,
1263 THREAD_ID tid,
1264 RayID ray_id)
1265{
1266 // No Ray registration: no need to sift through objects
1268 {
1269 getRayKernels(result, id, tid);
1270 }
1271 // Has Ray registration: only pick the objects associated with ray_id
1272 else
1273 {
1274 // Get all of the kernels on this block
1275 std::vector<RayKernelBase *> rkbs;
1276 getRayKernels(rkbs, id, tid);
1277
1278 // The RayTracingObjects associated with this ray
1279 const auto & ray_id_rtos = _threaded_ray_object_registration[tid][ray_id];
1280
1281 // The result is the union of all of the kernels and the objects associated with this Ray
1282 result.clear();
1283 for (auto rkb : rkbs)
1284 if (ray_id_rtos.count(rkb))
1285 result.push_back(rkb);
1286 }
1287}
1288
1289void
1290RayTracingStudy::getRayBCs(std::vector<RayBoundaryConditionBase *> & result,
1291 BoundaryID id,
1292 THREAD_ID tid)
1293{
1294 // If the cache doesn't have any attributes yet, it means that we haven't set
1295 // the conditions yet. We do this so that it can be generated on the fly on first use.
1296 if (!_threaded_cache_ray_bc[tid].numAttribs())
1297 {
1299 mooseError("Should not call getRayBCs() before initialSetup()");
1300
1302 .query()
1303 .condition<AttribRayTracingStudy>(this)
1304 .condition<AttribSystem>("RayBoundaryCondition")
1305 .condition<AttribThread>(tid);
1306 _threaded_cache_ray_bc[tid] = query.clone();
1307 }
1308
1309 _threaded_cache_ray_bc[tid].queryInto(result, std::make_tuple(id, false));
1310}
1311
1312void
1313RayTracingStudy::getRayBCs(std::vector<RayBoundaryConditionBase *> & result,
1314 const std::vector<TraceRayBndElement> & bnd_elems,
1315 THREAD_ID tid,
1316 RayID ray_id)
1317{
1318 // No Ray registration: no need to sift through objects
1320 {
1321 if (bnd_elems.size() == 1)
1322 getRayBCs(result, bnd_elems[0].bnd_id, tid);
1323 else
1324 {
1325 std::vector<BoundaryID> bnd_ids(bnd_elems.size());
1326 for (MooseIndex(bnd_elems.size()) i = 0; i < bnd_elems.size(); ++i)
1327 bnd_ids[i] = bnd_elems[i].bnd_id;
1328 getRayBCs(result, bnd_ids, tid);
1329 }
1330 }
1331 // Has Ray registration: only pick the objects associated with ray_id
1332 else
1333 {
1334 // Get all of the RayBCs on these boundaries
1335 std::vector<RayBoundaryConditionBase *> rbcs;
1336 if (bnd_elems.size() == 1)
1337 getRayBCs(rbcs, bnd_elems[0].bnd_id, tid);
1338 else
1339 {
1340 std::vector<BoundaryID> bnd_ids(bnd_elems.size());
1341 for (MooseIndex(bnd_elems.size()) i = 0; i < bnd_elems.size(); ++i)
1342 bnd_ids[i] = bnd_elems[i].bnd_id;
1343 getRayBCs(rbcs, bnd_ids, tid);
1344 }
1345
1346 // The RayTracingObjects associated with this ray
1347 mooseAssert(ray_id < _threaded_ray_object_registration[tid].size(), "Not in registration");
1348 const auto & ray_id_rtos = _threaded_ray_object_registration[tid][ray_id];
1349
1350 // The result is the union of all of the kernels and the objects associated with this Ray
1351 result.clear();
1352 for (auto rbc : rbcs)
1353 if (ray_id_rtos.count(rbc))
1354 result.push_back(rbc);
1355 }
1356}
1357
1358std::vector<RayTracingObject *>
1360{
1361 std::vector<RayTracingObject *> result;
1362 _fe_problem.theWarehouse().query().condition<AttribRayTracingStudy>(this).queryInto(result);
1363 return result;
1364}
1365
1366const std::vector<std::shared_ptr<Ray>> &
1368{
1370 mooseError("The Ray bank is not available because the private parameter "
1371 "'_bank_rays_on_completion' is set to false.");
1373 mooseError("Cannot get the Ray bank during generation or propagation.");
1374
1375 return _ray_bank;
1376}
1377
1378std::shared_ptr<Ray>
1380{
1381 // This is only a linear search - can be improved on with a map in the future
1382 // if this is used on a larger scale
1383 std::shared_ptr<Ray> ray;
1384 for (const std::shared_ptr<Ray> & possible_ray : rayBank())
1385 if (possible_ray->id() == ray_id)
1386 {
1387 ray = possible_ray;
1388 break;
1389 }
1390
1391 // Make sure one and only one processor has the Ray
1392 unsigned int have_ray = ray ? 1 : 0;
1393 _communicator.sum(have_ray);
1394 if (have_ray == 0)
1395 mooseError("Could not find a Ray with the ID ", ray_id, " in the Ray banks.");
1396
1397 // This should never happen... but let's make sure
1398 mooseAssert(have_ray == 1, "Multiple rays with the same ID were found in the Ray banks");
1399
1400 return ray;
1401}
1402
1403RayData
1405 const RayDataIndex index,
1406 const bool aux) const
1407{
1408 // Will be a nullptr shared_ptr if this processor doesn't own the Ray
1409 const std::shared_ptr<Ray> ray = getBankedRay(ray_id);
1410
1411 Real value = ray ? (aux ? ray->auxData(index) : ray->data(index)) : 0;
1412 _communicator.sum(value);
1413 return value;
1414}
1415
1416RayData
1418{
1419 return getBankedRayDataInternal(ray_id, index, /* aux = */ false);
1420}
1421
1422RayData
1424{
1425 return getBankedRayDataInternal(ray_id, index, /* aux = */ true);
1426}
1427
1428RayID
1430{
1431 libmesh_parallel_only(comm());
1432
1433 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1434
1436 mooseError("Cannot use registerRay() with Ray registration disabled");
1437
1438 // This is parallel only for now. We could likely stagger the ID building like we do with
1439 // the unique IDs, but it would require a sync point which isn't there right now
1440 libmesh_parallel_only(comm());
1441
1442 const auto & it = _registered_ray_map.find(name);
1443 if (it != _registered_ray_map.end())
1444 return it->second;
1445
1446 const auto id = _reverse_registered_ray_map.size();
1447 _registered_ray_map.emplace(name, id);
1449 return id;
1450}
1451
1452RayID
1453RayTracingStudy::registeredRayID(const std::string & name, const bool graceful /* = false */) const
1454{
1455 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1456
1458 mooseError("Should not use registeredRayID() with Ray registration disabled");
1459
1460 const auto search = _registered_ray_map.find(name);
1461 if (search != _registered_ray_map.end())
1462 return search->second;
1463
1464 if (graceful)
1465 return Ray::INVALID_RAY_ID;
1466
1467 mooseError("Attempted to obtain ID of registered Ray ",
1468 name,
1469 ", but a Ray with said name is not registered.");
1470}
1471
1472const std::string &
1474{
1475 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1476
1478 mooseError("Should not use registeredRayName() with Ray registration disabled");
1479
1480 if (_reverse_registered_ray_map.size() > ray_id)
1481 return _reverse_registered_ray_map[ray_id];
1482
1483 mooseError("Attempted to obtain name of registered Ray with ID ",
1484 ray_id,
1485 ", but a Ray with said ID is not registered.");
1486}
1487
1488Real
1490{
1491 Real volume = 0;
1492 for (const auto & elem : *_mesh.getActiveLocalElementRange())
1493 volume += elem->volume();
1494 _communicator.sum(volume);
1495 return volume;
1496}
1497
1498const std::vector<std::vector<BoundaryID>> &
1500{
1501 mooseAssert(_use_internal_sidesets, "Not using internal sidesets");
1502 mooseAssert(hasInternalSidesets(), "Processor does not have internal sidesets");
1503 mooseAssert(_internal_sidesets_map.size() > _elem_index_helper.getIndex(elem),
1504 "Internal sideset map not initialized");
1505
1506 const auto index = _elem_index_helper.getIndex(elem);
1507 return _internal_sidesets_map[index];
1508}
1509
1510TraceData &
1511RayTracingStudy::initThreadedCachedTrace(const std::shared_ptr<Ray> & ray, THREAD_ID tid)
1512{
1513 mooseAssert(shouldCacheTrace(ray), "Not caching trace");
1514 mooseAssert(currentlyPropagating(), "Should only use while tracing");
1515
1516 _threaded_cached_traces[tid].emplace_back(ray);
1517 return _threaded_cached_traces[tid].back();
1518}
1519
1520void
1521RayTracingStudy::verifyUniqueRayIDs(const std::vector<std::shared_ptr<Ray>>::const_iterator begin,
1522 const std::vector<std::shared_ptr<Ray>>::const_iterator end,
1523 const bool global,
1524 const std::string & error_suffix) const
1525{
1526 // Determine the unique set of Ray IDs on this processor,
1527 // and if not locally unique throw an error. Once we build this set,
1528 // we will send it to rank 0 to verify globally
1529 std::set<RayID> local_rays;
1530 for (const std::shared_ptr<Ray> & ray : as_range(begin, end))
1531 {
1532 mooseAssert(ray, "Null ray");
1533
1534 // Try to insert into the set; the second entry in the pair
1535 // will be false if it was not inserted
1536 if (!local_rays.insert(ray->id()).second)
1537 {
1538 for (const std::shared_ptr<Ray> & other_ray : as_range(begin, end))
1539 if (ray.get() != other_ray.get() && ray->id() == other_ray->id())
1540 mooseError("Multiple Rays exist with ID ",
1541 ray->id(),
1542 " on processor ",
1543 _pid,
1544 " ",
1545 error_suffix,
1546 "\n\nOffending Ray information:\n\n",
1547 ray->getInfo(),
1548 "\n",
1549 other_ray->getInfo());
1550 }
1551 }
1552
1553 // Send IDs from all procs to rank 0 and verify on rank 0
1554 if (global)
1555 {
1556 // Package our local IDs and send to rank 0
1557 std::map<processor_id_type, std::vector<RayID>> send_ids;
1558 if (local_rays.size())
1559 send_ids.emplace(std::piecewise_construct,
1560 std::forward_as_tuple(0),
1561 std::forward_as_tuple(local_rays.begin(), local_rays.end()));
1562 local_rays.clear();
1563
1564 // Mapping on rank 0 from ID -> processor ID
1565 std::map<RayID, processor_id_type> global_map;
1566
1567 // Verify another processor's IDs against the global map on rank 0
1568 const auto check_ids =
1569 [this, &global_map, &error_suffix](processor_id_type pid, const std::vector<RayID> & ids)
1570 {
1571 for (const RayID id : ids)
1572 {
1573 const auto emplace_pair = global_map.emplace(id, pid);
1574
1575 // Means that this ID already exists in the map
1576 if (!emplace_pair.second)
1577 mooseError("Ray with ID ",
1578 id,
1579 " exists on ranks ",
1580 emplace_pair.first->second,
1581 " and ",
1582 pid,
1583 "\n",
1584 error_suffix);
1585 }
1586 };
1587
1588 Parallel::push_parallel_vector_data(_communicator, send_ids, check_ids);
1589 }
1590}
1591
1592void
1593RayTracingStudy::verifyUniqueRays(const std::vector<std::shared_ptr<Ray>>::const_iterator begin,
1594 const std::vector<std::shared_ptr<Ray>>::const_iterator end,
1595 const std::string & error_suffix)
1596{
1597 std::set<const Ray *> rays;
1598 for (const std::shared_ptr<Ray> & ray : as_range(begin, end))
1599 if (!rays.insert(ray.get()).second) // false if not inserted into rays
1600 mooseError("Multiple shared_ptrs were found that point to the same Ray ",
1601 error_suffix,
1602 "\n\nOffending Ray:\n",
1603 ray->getInfo());
1604}
1605
1606void
1607RayTracingStudy::moveRayToBuffer(std::shared_ptr<Ray> & ray)
1608{
1609 mooseAssert(currentlyGenerating(), "Can only use while generating");
1610 mooseAssert(ray, "Null ray");
1611 mooseAssert(ray->shouldContinue(), "Ray is not continuing");
1612
1613 _parallel_ray_study->moveWorkToBuffer(ray, /* tid = */ 0);
1614}
1615
1616void
1617RayTracingStudy::moveRaysToBuffer(std::vector<std::shared_ptr<Ray>> & rays)
1618{
1619 mooseAssert(currentlyGenerating(), "Can only use while generating");
1620#ifndef NDEBUG
1621 for (const std::shared_ptr<Ray> & ray : rays)
1622 {
1623 mooseAssert(ray, "Null ray");
1624 mooseAssert(ray->shouldContinue(), "Ray is not continuing");
1625 }
1626#endif
1627
1628 _parallel_ray_study->moveWorkToBuffer(rays, /* tid = */ 0);
1629}
1630
1631void
1633 const THREAD_ID tid,
1635{
1636 mooseAssert(ray, "Null ray");
1637 mooseAssert(currentlyPropagating(), "Can only use while tracing");
1638
1639 _parallel_ray_study->moveWorkToBuffer(ray, tid);
1640}
1641
1642void
1644{
1645 if (!currentlyGenerating())
1646 mooseError("Can only reserve in Ray buffer during generateRays()");
1647
1648 _parallel_ray_study->reserveBuffer(size);
1649}
1650
1651const Point &
1652RayTracingStudy::getSideNormal(const Elem * elem, unsigned short side, const THREAD_ID tid)
1653{
1654 std::unordered_map<std::pair<const Elem *, unsigned short>, Point> & cache =
1656
1657 // See if we've already cached this side normal
1658 const auto elem_side_pair = std::make_pair(elem, side);
1659 const auto search = cache.find(elem_side_pair);
1660
1661 // Haven't cached this side normal: compute it and then cache it
1662 if (search == cache.end())
1663 {
1664 _threaded_fe_face[tid]->reinit(elem, side);
1665 const auto & normal = _threaded_fe_face[tid]->get_normals()[0];
1666 cache.emplace(elem_side_pair, normal);
1667 return normal;
1668 }
1669
1670 // Have cached this side normal: simply return it
1671 return search->second;
1672}
1673
1674bool
1676{
1677 unsigned int min_level = std::numeric_limits<unsigned int>::max();
1678 unsigned int max_level = std::numeric_limits<unsigned int>::min();
1679
1680 for (const auto & elem : *_mesh.getActiveLocalElementRange())
1681 {
1682 const auto level = elem->level();
1683 min_level = std::min(level, min_level);
1684 max_level = std::max(level, max_level);
1685 }
1686
1687 _communicator.min(min_level);
1688 _communicator.max(max_level);
1689
1690 return min_level == max_level;
1691}
1692
1693Real
1695{
1696 const auto find = _subdomain_hmax.find(subdomain_id);
1697 if (find == _subdomain_hmax.end())
1698 mooseError("Subdomain ", subdomain_id, " not found in subdomain hmax map");
1699 return find->second;
1700}
1701
1702bool
1704{
1705 Real bbox_volume = 1;
1706 for (unsigned int d = 0; d < _mesh.dimension(); ++d)
1707 bbox_volume *= std::abs(_b_box.max()(d) - _b_box.min()(d));
1708
1709 return MooseUtils::absoluteFuzzyEqual(bbox_volume, totalVolume(), TOLERANCE);
1710}
1711
1712void
1714{
1715 libmesh_parallel_only(comm());
1716
1717 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1718
1719 mooseAssert(!currentlyGenerating() && !currentlyPropagating(),
1720 "Cannot be reset during generation or propagation");
1721
1722 for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
1724}
1725
1726RayID
1728{
1729 // Get the current ID to return
1730 const auto id = _threaded_next_ray_id[tid];
1731
1732 // Advance so that the next call has the correct ID
1734
1735 return id;
1736}
1737
1738void
1740{
1741 libmesh_parallel_only(comm());
1742
1743 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
1744
1745 mooseAssert(!currentlyGenerating() && !currentlyPropagating(),
1746 "Cannot be reset during generation or propagation");
1747
1749}
1750
1751RayID
1756
1757bool
1758RayTracingStudy::sideIsIncoming(const Elem * const elem,
1759 const unsigned short side,
1760 const Point & direction,
1761 const THREAD_ID tid)
1762{
1763 const auto & normal = getSideNormal(elem, side, tid);
1764 const auto dot = normal * direction;
1765 return dot < TraceRayTools::TRACE_TOLERANCE;
1766}
1767
1768std::shared_ptr<Ray>
1770{
1771 mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1772
1773 return _parallel_ray_study->acquireParallelData(
1774 /* tid = */ 0,
1775 this,
1776 generateUniqueRayID(/* tid = */ 0),
1777 rayDataSize(),
1779 /* reset = */ true,
1781}
1782
1783std::shared_ptr<Ray>
1785{
1786 mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1787
1788 return _parallel_ray_study->acquireParallelData(/* tid = */ 0,
1789 this,
1790 generateUniqueRayID(/* tid = */ 0),
1791 /* data_size = */ 0,
1792 /* aux_data_size = */ 0,
1793 /* reset = */ true,
1795}
1796
1797std::shared_ptr<Ray>
1799{
1800 mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1801 libmesh_parallel_only(comm());
1802
1803 return _parallel_ray_study->acquireParallelData(
1804 /* tid = */ 0,
1805 this,
1807 rayDataSize(),
1809 /* reset = */ true,
1811}
1812
1813std::shared_ptr<Ray>
1815{
1816 mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1817
1818 // Either register a Ray or get an already registered Ray id
1819 const RayID id = registerRay(name);
1820
1821 // Acquire a Ray with the properly sized data initialized to zero
1822 return _parallel_ray_study->acquireParallelData(
1823 /* tid = */ 0,
1824 this,
1825 id,
1826 rayDataSize(),
1828 /* reset = */ true,
1830}
1831
1832std::shared_ptr<Ray>
1834{
1835 mooseAssert(currentlyGenerating(), "Can only use during generateRays()");
1836 return _parallel_ray_study->acquireParallelData(
1837 /* tid = */ 0, &ray, Ray::ConstructRayKey());
1838}
1839
1840std::shared_ptr<Ray>
1842{
1843 mooseAssert(currentlyPropagating(), "Can only use during propagation");
1844 return _parallel_ray_study->acquireParallelData(tid,
1845 this,
1847 rayDataSize(),
1849 /* reset = */ true,
1851}
boundary_id_type BoundaryID
subdomain_id_type SubdomainID
unsigned int THREAD_ID
const ExecFlagType EXEC_PRE_KERNELS
sideset clear()
unsigned int RayDataIndex
Type for the index into the data and aux data on a Ray.
Definition Ray.h:52
unsigned long int RayID
Type for a Ray's ID.
Definition Ray.h:44
float RayData
Type for a Ray's data.
Definition Ray.h:47
const std::string name
Definition Setup.h:21
bool isOn()
void modifyArbitraryWeights(const std::vector< Real > &weights)
Attribute for the RayTracingStudy a RayTracingObject is associated with.
MooseVariableFE< Real > & variable()
Gets the variable this AuxRayKernel contributes to.
libMesh::dof_id_type getIndex(const libMesh::Elem *elem) const
Get the index associated with the element elem.
void initialize(const libMesh::SimpleRange< libMesh::MeshBase::element_iterator > elems)
Initializes the indices in a contiguous manner for the given element range.
libMesh::dof_id_type maxIndex() const
Gets the maximum index generated using this object.
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
virtual void reinitElemPhys(const Elem *elem, const std::vector< Point > &phys_points_in_elem, const THREAD_ID tid) override
virtual void cacheResidual(const THREAD_ID tid) override
virtual void addCachedResidual(const THREAD_ID tid) override
AuxiliarySystem & getAuxiliarySystem()
virtual void addCachedJacobian(const THREAD_ID tid) override
virtual void cacheJacobian(const THREAD_ID tid) override
virtual void setCurrentSubdomainID(const Elem *elem, const THREAD_ID tid) override
void reinitMaterials(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true)
virtual void prepare(const Elem *elem, const THREAD_ID tid) override
void clearActiveMaterialProperties(const THREAD_ID tid)
virtual void clearActiveElementalMooseVariables(const THREAD_ID tid) override
void prepareMaterials(const std::unordered_set< unsigned int > &consumer_needed_mat_props, const SubdomainID blk_id, const THREAD_ID tid)
virtual void setActiveElementalMooseVariables(const std::set< MooseVariableFEBase * > &moose_vars, const THREAD_ID tid) override
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num) override
TheWarehouse & theWarehouse() const
const bool & currentlyComputingResidual() const
virtual void subdomainSetup(SubdomainID subdomain, const THREAD_ID tid)
Adaptivity & adaptivity()
virtual const SystemBase & getSystemBase(const unsigned int sys_num) const
bool hasActiveMaterialProperties(const THREAD_ID tid) const
static InputParameters validParams()
T & set(const std::string &name, bool quiet_mode=false)
bool & useEigenvalue()
const std::string & type() const
std::string typeAndName() const
const std::string & name() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
virtual unsigned int dimension() const
MeshBase & getMesh()
virtual bool isDistributedMesh() const
const std::set< SubdomainID > & meshSubdomains() const
std::string getBoundaryString(const BoundaryID boundary_id) const
const libMesh::ConstElemRange * getActiveLocalElementRange()
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > * getBoundaryElementRange()
bool isValueSet(const std::string &value) const
unsigned int size() const
RayBC that enforces periodic boundaries.
Base object for the RayKernel syntax.
Base class for a ray kernel that contributes to the residual and/or Jacobian.
Definition RayKernel.h:34
Key that is used for restricting access to moveRayToBufferDuringTrace() and acquireRayDuringTrace().
unsigned int _ending_max_intersections
Max number of intersections for Rays that finished on this processor.
bool _has_same_level_active_elems
Whether or not the mesh has active elements of the same level.
void moveRayToBufferDuringTrace(std::shared_ptr< Ray > &ray, const THREAD_ID tid, const AcquireMoveDuringTraceKey &)
INTERNAL method for moving a Ray into the buffer during tracing.
void traceableMeshChecks()
Check for if all of the element types in the mesh are supported by ray tracing.
std::vector< TheWarehouse::QueryCache< AttribSubdomains > > _threaded_cache_ray_kernel
Threaded cached subdomain query for RayKernelBase objects pertaining to this study.
std::shared_ptr< Ray > acquireCopiedRay(const Ray &ray)
Acquires a Ray that that is copied from another Ray within generateRays().
std::vector< TheWarehouse::QueryCache< AttribBoundaries > > _threaded_cache_ray_bc
Threaded cached boundary query for RayBC objects pertaining to this study.
void verifyDependenciesExist(const std::vector< RayTracingObject * > &rtos)
Verifies that the dependencies exist for a set of RayTracingObjects.
const bool _use_internal_sidesets
Whether or not to use the internal sidesets in ray tracing.
std::vector< RayTracingObject * > getRayTracingObjects()
Gets all of the currently active RayTracingObjects.
std::unordered_map< std::string, RayDataIndex > _ray_aux_data_map
The map from Ray aux data names to index.
RayDataIndex registerRayAuxData(const std::string &name)
Register a value to be filled in the aux data on a Ray with a given name.
const std::vector< RayKernelBase * > & currentRayKernels(THREAD_ID tid) const
Gets the current RayKernels for a thread, which are set in segmentSubdomainSetup()
std::vector< unsigned long long int > _local_trace_ray_results
Cumulative results on this processor from the threaded TraceRay objects.
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.
void resetUniqueRayIDs()
Resets the generation of unique RayIDs via generateUniqueRayID() to the beginning of the range.
Real _ending_distance
Total distance traveled by Rays that end on this processor.
std::shared_ptr< Ray > acquireRegisteredRay(const std::string &name)
Acquires a Ray with a given name within generateRays().
const bool _tolerate_failure
Whether or not to tolerate a Ray Tracing failure.
std::chrono::steady_clock::duration _generation_time
Threads::spin_mutex _spin_mutex
Spin mutex object for locks.
std::vector< std::string > _ray_aux_data_names
The names for each Ray aux data entry.
void getRayKernels(std::vector< RayKernelBase * > &result, SubdomainID id, THREAD_ID tid)
Fills the active RayKernels associated with this study and a block into result.
void verifyUniqueRays(const std::vector< std::shared_ptr< Ray > >::const_iterator begin, const std::vector< std::shared_ptr< Ray > >::const_iterator end, const std::string &error_suffix)
Verifies that the Rays in the given range are unique.
std::size_t rayDataSize() const
The registered size of values in the Ray data.
RayDataIndex registerRayData(const std::string &name)
Register a value to be filled in the data on a Ray with a given name.
TraceData & initThreadedCachedTrace(const std::shared_ptr< Ray > &ray, THREAD_ID tid)
Initialize a Ray in the threaded cached trace map to be filled with segments.
std::vector< std::vector< std::vector< BoundaryID > > > _internal_sidesets_map
Internal sideset data, if internal sidesets exist (indexed with getLocalElemIndex())
std::vector< std::shared_ptr< Ray > > _ray_bank
Cumulative Ray bank - stored only when _bank_rays_on_completion.
void nonPlanarSideSetup()
Sets up the caching of whether or not each element side is non-planar, which is stored in _non_planar...
std::chrono::steady_clock::duration _propagation_time
virtual void initialSetup() override
bool sameLevelActiveElems() const
Determine whether or not the mesh currently has active elements that are all the same level.
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.
std::set< BoundaryID > _internal_sidesets
The BoundaryIDs on the local mesh that have internal RayBCs.
bool _has_non_planar_sides
Whether or not the local mesh has elements with non-planar sides.
unsigned int _ending_max_processor_crossings
Max number of total processor crossings for Rays that finished on this processor.
std::vector< std::unique_ptr< libMesh::QBase > > _threaded_q_face
Face quadrature used for computing face normals for each thread.
const bool _use_ray_registration
Whether or not to use Ray registration.
RayTracingStudy(const InputParameters &parameters)
static InputParameters validParams()
bool currentlyGenerating() const
Whether or not the study is generating.
MooseMesh & _mesh
The Mesh.
std::shared_ptr< Ray > getBankedRay(const RayID ray_id) const
Gets the Ray with the ID ray_id from the Ray bank.
void subdomainHMaxSetup()
Caches the hmax for all elements in each subdomain.
void localElemIndexSetup()
Sets up the _elem_index_helper, which is used for obtaining a contiguous index for all elements that ...
RayID registerRay(const std::string &name)
Registers a Ray with a given name.
std::vector< std::string > _ray_data_names
The names for each Ray data entry.
unsigned long long int _total_intersections
Total number of Ray/element intersections.
std::shared_ptr< Ray > acquireRayDuringTrace(const THREAD_ID tid, const AcquireMoveDuringTraceKey &)
INTERNAL methods for acquiring a Ray during a trace in RayKernels and RayBCs.
Real _total_distance
Total distance traveled by all Rays.
unsigned long long int _ending_processor_crossings
Total number of processor crossings for Rays that finished on this processor.
std::vector< std::unordered_map< std::pair< const Elem *, unsigned short >, Point > > _threaded_cached_normals
Threaded cache for side normals that have been computed already during tracing.
RayID _replicated_next_ray_id
Storage for the next available replicated RayID, obtained via generateReplicatedRayID()
void resetReplicatedRayIDs()
Resets the generation of unique replicated RayIDs accessed via generateReplicatedRayID().
const std::string & getRayAuxDataName(const RayDataIndex index) const
Gets the name associated with a registered value in the Ray aux data.
const std::string & getRayDataNameInternal(const RayDataIndex index, const bool aux) const
Internal method for getting the name of Ray data or Ray aux data.
virtual void segmentSubdomainSetup(const SubdomainID subdomain, const THREAD_ID tid, const RayID ray_id)
Setup for on subdomain change or subdomain AND ray change during ray tracing.
virtual void preExecuteStudy()
Entry point before study execution.
RayData getBankedRayData(const RayID ray_id, const RayDataIndex index) const
Gets the data value for a banked ray with a given ID.
virtual void residualSetup() override
std::vector< TraceData > _cached_traces
Storage for the cached traces.
unsigned int _max_trajectory_changes
Max number of trajectory changes for a single Ray.
virtual void reinitSegment(const Elem *elem, const Point &start, const Point &end, const Real length, THREAD_ID tid)
Reinitialize objects for a Ray segment for ray tracing.
virtual void generateRays()=0
Subclasses should override this to determine how to generate Rays.
std::vector< RayDataIndex > getRayAuxDataIndices(const std::vector< std::string > &names, const bool graceful=false) const
Gets the indices associated with registered values in the Ray aux data.
const bool _bank_rays_on_completion
Whether or not to bank rays on completion.
std::vector< std::vector< RayKernelBase * > > _threaded_current_ray_kernels
The current RayKernel objects for each thread.
std::vector< RayID > _threaded_next_ray_id
Storage for the next available unique RayID, obtained via generateUniqueRayID()
const std::unique_ptr< ParallelRayStudy > _parallel_ray_study
The study that used is to actually execute (trace) the Rays.
Real computeTotalVolume()
Helper function for computing the total domain volume.
std::unordered_map< std::string, RayID > & _registered_ray_map
Map from registered Ray name to ID.
RayDataIndex registerRayDataInternal(const std::string &name, const bool aux)
Internal method for registering Ray data or Ray aux data with a name.
virtual void postOnSegment(const THREAD_ID tid, const std::shared_ptr< Ray > &ray)
Called at the end of a Ray segment.
libMesh::BoundingBox _loose_b_box
Loose nodal bounding box for the domain.
void internalSidesetSetup()
Does the setup for internal sidesets.
virtual void buildSegmentQuadrature(const Point &start, const Point &end, const Real length, std::vector< Point > &points, std::vector< Real > &weights) const
Builds quadrature points for a given segment using the _segment_qrule.
unsigned long long int _ending_intersections
Total number of Ray/element intersections for Rays that finished on this processor.
std::shared_ptr< Ray > acquireReplicatedRay()
Acquire a Ray from the pool of Rays within generateRays() in a replicated fashion.
virtual void execute() override
Executes the study (generates and propagates Rays)
virtual void postExecuteStudy()
Entry point after study execution.
unsigned int _max_intersections
Max number of intersections for a single Ray.
bool isRectangularDomain() const
Whether or not the domain is rectangular (if it is prefectly encompassed by its bounding box)
std::shared_ptr< Ray > acquireUnsizedRay()
Acquire a Ray from the pool of Rays within generateRays(), without resizing the data (sizes the data ...
void registeredRaySetup()
Sets up the maps from Ray to associated RayTracingObjects if _use_ray_registration.
RayDataIndex getRayDataIndex(const std::string &name, const bool graceful=false) const
Gets the index associated with a registered value in the Ray data.
const bool _ray_kernel_coverage_check
Whether or not to perform coverage checks on RayKernels.
std::unique_ptr< libMesh::QBase > _segment_qrule
Quadrature rule for laying points across a 1D ray segment.
virtual void jacobianSetup() override
void moveRayToBuffer(std::shared_ptr< Ray > &ray)
Moves a ray to the buffer to be traced during generateRays().
const std::string & registeredRayName(const RayID ray_id) const
Gets the name of a registered ray.
void reserveRayBuffer(const std::size_t size)
Reserve size entires in the Ray buffer.
void verifyUniqueRayIDs(const std::vector< std::shared_ptr< Ray > >::const_iterator begin, const std::vector< std::shared_ptr< Ray > >::const_iterator end, const bool global, const std::string &error_suffix) const
Verifies that the Rays in the given range have unique Ray IDs.
std::unordered_map< SubdomainID, Real > _subdomain_hmax
The cached hmax for all elements in a subdomain.
bool verifyRays() const
Whether or not to verify if Rays have valid information before being traced.
RayID registeredRayID(const std::string &name, const bool graceful=false) const
Gets the ID of a registered ray.
virtual const Point & getSideNormal(const Elem *elem, const unsigned short side, const THREAD_ID tid)
Get the outward normal for a given element side.
virtual void meshChanged() override
unsigned long long int _total_processor_crossings
Total number of processor crossings.
std::vector< std::vector< TraceData > > _threaded_cached_traces
The threaded storage for cached traces.
std::vector< std::shared_ptr< TraceRay > > _threaded_trace_ray
The TraceRay objects for each thread (they do the physical tracing)
RayID generateReplicatedRayID()
Generates a Ray ID that is replicated across all processors.
ElemIndexHelper _elem_index_helper
Helper for defining a local contiguous index for each element.
std::shared_ptr< Ray > acquireRay()
User APIs for constructing Rays within the RayTracingStudy.
Real totalVolume() const
Get the current total volume of the domain.
const std::string & getRayDataName(const RayDataIndex index) const
Gets the name associated with a registered value in the Ray data.
std::chrono::steady_clock::duration _execution_time
std::size_t rayAuxDataSize() const
The registered size of values in the Ray aux data.
virtual void timestepSetup() override
RayData getBankedRayAuxData(const RayID ray_id, const RayDataIndex index) const
Gets the data value for a banked ray with a given ID.
std::unordered_map< std::string, RayDataIndex > _ray_data_map
The map from Ray data names to index.
const std::vector< std::shared_ptr< Ray > > & rayBank() const
Get the Ray bank.
std::vector< std::vector< std::set< const RayTracingObject * > > > _threaded_ray_object_registration
Threaded storage for all of the RayTracingObjects associated with a single Ray.
virtual RayID generateUniqueRayID(const THREAD_ID tid)
Generates a unique RayID to be used for a Ray.
std::vector< std::vector< unsigned short > > _non_planar_sides
Non planar side data, which is for quick checking if an elem side is non-planar We use unsigned short...
void coverageChecks()
Perform coverage checks (coverage of RayMaterials and RayKernels, if enabled)
const std::set< BoundaryID > & getInternalSidesets() const
Gets the internal sidesets (that have RayBCs) within the local domain.
virtual bool shouldCacheTrace(const std::shared_ptr< Ray > &) const
Virtual that allows for selection in if a Ray should be cached or not (only used when _cache_traces).
Real subdomainHmax(const SubdomainID subdomain_id) const
Get the cached hmax for all elements in a subdomain.
unsigned int _ending_max_trajectory_changes
Max number of trajectory changes for Rays that finished on this processor.
RayDataIndex getRayDataIndexInternal(const std::string &name, const bool aux, const bool graceful) const
Internal method for getting the index of Ray data or Ray aux data.
bool hasInternalSidesets() const
Whether or not the local mesh has internal sidesets that have RayBCs on them.
RayDataIndex getRayAuxDataIndex(const std::string &name, const bool graceful=false) const
Gets the index associated with a registered value in the Ray aux data.
libMesh::BoundingBox _b_box
Nodal bounding box for the domain.
void getRayBCs(std::vector< RayBoundaryConditionBase * > &result, BoundaryID id, THREAD_ID tid)
Fills the active RayBCs associated with this study and a boundary into result.
std::vector< RayDataIndex > getRayDataIndices(const std::vector< std::string > &names, const bool graceful=false) const
Gets the indices associated with registered values in the Ray data.
std::vector< RayDataIndex > getRayDataIndicesInternal(const std::vector< std::string > &names, const bool aux, const bool graceful) const
Internal method for getting the indicies of Ray data or Ray aux data.
void moveRaysToBuffer(std::vector< std::shared_ptr< Ray > > &rays)
Moves rays to the buffer to be traced during generateRays().
void dependencyChecks()
Perform checks to see if the listed dependencies in the RayTracingObjects exist.
const processor_id_type _pid
The rank of this processor (this actually takes time to lookup - so just do it once)
virtual void onCompleteRay(const std::shared_ptr< Ray > &ray)
Entry point for acting on a ray when it is completed (shouldContinue() == false)
std::vector< std::unique_ptr< libMesh::FEBase > > _threaded_fe_face
Face FE used for computing face normals for each thread.
bool _called_initial_setup
Whether or not we've called initial setup - used to stop from late registration.
RayData getBankedRayDataInternal(const RayID ray_id, const RayDataIndex index, const bool aux) const
Internal method for getting the value (replicated across all processors) in a Ray's data or aux data ...
std::vector< std::string > & _reverse_registered_ray_map
Map from registered Ray ID to name.
void periodicBoundaryChecks()
Check for overlapping PeriodicRayBC boundaries and check for cases in which ghosting may not be suffi...
bool hasRayKernels(const THREAD_ID tid)
Whether or not there are currently any active RayKernel objects.
void executeStudy()
Method for executing the study so that it can be called out of the standard UO execute()
unsigned int _max_processor_crossings
Max number of processor crossings for all Rays.
std::chrono::steady_clock::time_point _execution_start_time
Timing.
std::vector< std::size_t > _num_cached
Number of currently cached objects for Jacobian/residual for each thread.
bool currentlyPropagating() const
Whether or not the study is propagating (tracing Rays)
void zeroAuxVariables()
Zero the AuxVariables that the registered AuxRayKernels contribute to.
const bool _warn_non_planar
Whether not to warn if non-planar faces are found.
Class that is used as a parameter to the public constructors/reset methods.
Definition Ray.h:100
Basic datastructure for a ray that will traverse the mesh.
Definition Ray.h:58
static const RayDataIndex INVALID_RAY_DATA_INDEX
Invalid index into a Ray's data.
Definition Ray.h:212
static const RayID INVALID_RAY_ID
Invalid Ray ID.
Definition Ray.h:214
const ExecFlagEnum & _execute_enum
const bool & currentlyComputingJacobian() const
virtual bool hasActiveElementalMooseVariables(const THREAD_ID tid) const
virtual void zeroVariables(std::vector< std::string > &vars_to_be_zeroed)
unsigned int number() const
NumericVector< Number > & solution()
virtual libMesh::Order getMinQuadratureOrder()
void max(const T &r, T &o, Request &req) const
processor_id_type size() const
void min(const T &r, T &o, Request &req) const
void set_union(T &data, const unsigned int root_id) const
Query query()
Traces Rays through the mesh on a single processor.
Definition TraceRay.h:47
@ FAILED_TRACES
Definition TraceRay.h:71
FEProblemBase & _fe_problem
SystemBase & _sys
const Point & max() const
void scale(const Real factor)
const Point & min() const
virtual void close()=0
const Parallel::Communicator & _communicator
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
query_obj query
MeshBase & mesh
const SubdomainID ANY_BLOCK_ID
std::string stringify(const T &t)
const Real TRACE_TOLERANCE
The standard tolerance to use in tracing.
bool isAdaptivityTraceableElem(const Elem *elem)
bool isTraceableElem(const Elem *elem)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
unsigned int n_threads()
Data structure that stores information for output of a partial trace of a Ray on a processor.
Definition TraceData.h:43