20#include "libmesh/cell_tet4.h"
21#include "libmesh/cell_tet10.h"
22#include "libmesh/cell_tet14.h"
23#include "libmesh/cell_hex8.h"
24#include "libmesh/cell_hex20.h"
25#include "libmesh/cell_hex27.h"
26#include "libmesh/cell_prism6.h"
27#include "libmesh/cell_prism15.h"
28#include "libmesh/cell_prism18.h"
29#include "libmesh/cell_pyramid5.h"
30#include "libmesh/cell_pyramid13.h"
31#include "libmesh/cell_pyramid14.h"
32#include "libmesh/edge_edge2.h"
33#include "libmesh/edge_edge3.h"
34#include "libmesh/edge_edge4.h"
35#include "libmesh/face_quad4.h"
36#include "libmesh/face_quad8.h"
37#include "libmesh/face_quad9.h"
38#include "libmesh/face_tri3.h"
39#include "libmesh/face_tri6.h"
40#include "libmesh/face_tri7.h"
41#include "libmesh/enum_to_string.h"
42#include "libmesh/mesh.h"
48 _mesh(study.getSubProblem().
mesh()),
49 _dim(_mesh.dimension()),
50 _boundary_info(_mesh.getMesh().get_boundary_info()),
51 _pid(_study.comm().rank()),
53 _backface_culling(false),
54 _current_normals(nullptr),
55 _results(ENDED_STATIONARY + 1)
83 const ElemType elem_type,
84 const unsigned short incoming_side,
85 Point & intersection_point,
86 unsigned short & intersected_side,
88 Real & intersection_distance,
89 const Point * normals)
91 debugRay(
"Called exitsElem()");
93 traceAssert(elem_type == elem->type(),
"elem_type incorrect");
96 traceAssert(intersected_extrema.
isInvalid(),
"Extrema should be invalid");
98 "Distance should be invalid");
102 "Incoming side is non-entrant");
108 intersected = exitsElem<Hex8, Hex8>(elem,
113 intersection_distance,
117 intersected = exitsElem<Tet4, Tet4>(elem,
122 intersection_distance,
126 intersected = exitsElem<Pyramid5, Pyramid5>(elem,
131 intersection_distance,
135 intersected = exitsElem<Prism6, Prism6>(elem,
140 intersection_distance,
144 intersected = exitsElem<Quad4, Quad4>(elem,
149 intersection_distance,
153 intersected = exitsElem<Tri3, Tri3>(elem,
158 intersection_distance,
162 intersected = exitsElem<Hex20, Hex8>(elem,
167 intersection_distance,
171 intersected = exitsElem<Hex27, Hex8>(elem,
176 intersection_distance,
180 intersected = exitsElem<Quad8, Quad4>(elem,
185 intersection_distance,
189 intersected = exitsElem<Quad9, Quad4>(elem,
194 intersection_distance,
198 intersected = exitsElem<Tri6, Tri3>(elem,
203 intersection_distance,
207 intersected = exitsElem<Tri7, Tri3>(elem,
212 intersection_distance,
216 intersected = exitsElem<Tet10, Tet4>(elem,
221 intersection_distance,
225 intersected = exitsElem<Tet14, Tet4>(elem,
230 intersection_distance,
234 intersected = exitsElem<Pyramid13, Pyramid5>(elem,
239 intersection_distance,
243 intersected = exitsElem<Pyramid14, Pyramid5>(elem,
248 intersection_distance,
252 intersected = exitsElem<Prism15, Prism6>(elem,
257 intersection_distance,
261 intersected = exitsElem<Prism18, Prism6>(elem,
266 intersection_distance,
270 intersected = exitsElem<Edge2, Edge2>(elem,
275 intersection_distance,
279 intersected = exitsElem<Edge3, Edge2>(elem,
284 intersection_distance,
288 intersected = exitsElem<Edge4, Edge2>(elem,
293 intersection_distance,
298 "Element type ", Utility::enum_to_string(elem->type()),
" not supported by TraceRay");
311template <
typename T,
typename FirstOrderT>
312typename std::enable_if<!std::is_base_of<Edge, T>::value,
bool>::type
314 const unsigned short incoming_side,
315 Point & intersection_point,
316 unsigned short & intersected_side,
318 Real & intersection_distance,
319 const Point * normals)
323 debugRay(
"Called exitsElem() in 2D or 3D");
328 Point current_intersection_point;
329 Real current_intersection_distance;
339 bool try_nonplanar_incoming_side =
false;
341 const auto & direction = (*_current_ray)->direction();
343 unsigned short s = 0;
352 debugRay(
" use_backface_culling = ", use_backface_culling);
353 debugRay(
" try_nonplanar_incoming_side = ", try_nonplanar_incoming_side);
357 debugRay(
" Side ", s,
" with centroid ",
_elem_side_builder(*elem, s).vertex_average());
363 if (!try_nonplanar_incoming_side)
367 if (s == incoming_side)
369 debugRay(
" Skipping due to incoming side");
370 if (++s == T::num_sides)
378 if (use_backface_culling)
383 debugRay(
" Skipping due to backface culling dot = ", normals[s] * direction);
385 if (++s == T::num_sides)
402 debugRay(
" Skipping because we already checked this side with culling enabled");
403 if (++s == T::num_sides)
409 debugRay(
" Side that was skipped due to culling");
418 const bool intersected = sideIntersectedByLine<FirstOrderT>(elem,
423 current_intersection_point,
424 current_intersection_distance,
425 current_intersected_extrema,
427#ifdef DEBUG_RAY_INTERSECTIONS
437 debugRay(
" Intersected at point ",
438 current_intersection_point,
440 current_intersection_distance);
441 debugRay(
" Best intersection distance = ", best_intersection_distance);
447 failTrace(
"Intersected side does not contain intersection point",
454 if (current_intersection_distance > best_intersection_distance)
456 debugRay(
" Best intersection so far");
458 intersected_side = s;
459 intersection_distance = current_intersection_distance;
460 intersection_point = current_intersection_point;
461 intersected_extrema = current_intersected_extrema;
462 best_intersection_distance = current_intersection_distance;
466 if (++s == T::num_sides || try_nonplanar_incoming_side)
475 debugRay(
" Exiting with intersection");
476 debugRay(
" intersected_side = ", intersected_side);
477 debugRay(
" intersection_distance = ", intersection_distance);
478 debugRay(
" intersection_point = ", intersection_point);
479 debugRay(
" intersected_extrema = ", intersected_extrema);
485 if (try_nonplanar_incoming_side)
490 if (use_backface_culling)
492 debugRay(
" Didn't find an intersection, retrying without backface culling");
493 use_backface_culling =
false;
503 debugRay(
" Didn't find an intersection, trying non-planar incoming_side");
504 try_nonplanar_incoming_side =
true;
514template <
typename T,
typename FirstOrderT>
515typename std::enable_if<std::is_base_of<Edge, T>::value,
bool>::type
517 const unsigned short incoming_side,
518 Point & intersection_point,
519 unsigned short & intersected_side,
521 Real & intersection_distance,
526 debugRay(
"Called exitsElem() in 1D");
535 intersected_side = (incoming_side == 1 ? 0 : 1);
536 intersected_extrema.
setVertex(intersected_side);
537 intersection_point = elem->point(intersected_side);
540 debugRay(
" Incoming side is set to ", incoming_side,
" so setting to other side");
541 debugRay(
" Intersected side ", intersected_side,
" at ", intersection_point);
547 const Point extended_end_point =
552 for (MooseIndex(elem->n_sides()) side = 0; side < elem->n_sides(); ++side)
554 const Point side_point = elem->point(side);
555 debugRay(
" Checking side ", side,
" at ", side_point);
558 if (incoming_to_side <
tol)
560 debugRay(
" Continuing because at side");
565 const Real side_to_end = (extended_end_point - side_point).
norm();
566 const Real sum = incoming_to_side + side_to_end - incoming_to_end;
567 debugRay(
" Sum = ", sum);
569 if (std::abs(sum) <
tol)
571 intersected_side = side;
573 intersection_point = side_point;
574 intersection_distance = incoming_to_side;
575 debugRay(
" Intersected at ", intersection_point);
585 const Elem * last_elem,
586 const Elem *& best_elem,
587 unsigned short & best_elem_incoming_side)
591 debugRay(
"Called moveThroughNeighbors() with ", neighbors.size(),
" neighbors, and:");
592 debugRay(
" last_elem->id() = ", last_elem ? last_elem->id() : DofObject::invalid_id);
595 traceAssert(!best_elem,
"Best elem should be null");
597 "Best elem side should be invalid");
602 "Distance should be invalid");
606 Real longest_distance = 1.0e-12;
608 unsigned short current_incoming_side;
609 Point current_intersection_point;
610 unsigned short current_intersected_side;
612 Real current_intersection_distance;
623 if (neighbor_info._elem == last_elem)
625 debugRay(
"Skipping last elem ", last_elem->id());
626 last_elem_info = &neighbor_info;
631 current_incoming_side,
632 current_intersection_point,
633 current_intersected_side,
634 current_intersected_extrema,
635 current_intersection_distance);
640 debugRay(
"Ray can exit through neighbor ", neighbor_info._elem->id());
642 if (current_intersection_distance > longest_distance)
644 best_elem = neighbor_info._elem;
645 best_elem_incoming_side = current_incoming_side;
650 longest_distance = current_intersection_distance;
651 best_exit_result = exit_result;
657 if (!best_elem && last_elem_info)
660 current_incoming_side,
661 current_intersection_point,
662 current_intersected_side,
663 current_intersected_extrema,
664 current_intersection_distance);
666 if (exit_result !=
NO_EXIT && current_intersection_distance > longest_distance)
668 debugRay(
"Ray can exit through last_elem ", last_elem->id());
670 best_elem = last_elem;
671 best_elem_incoming_side = current_incoming_side;
676 best_exit_result = exit_result;
680 debugRay(
"moveThroughNeighbors() best result:");
681 debugRay(
" best_elem = ", best_elem ? best_elem->id() : DofObject::invalid_id);
682 debugRay(
" best_elem_incoming_side = ", best_elem_incoming_side);
689 debugRay(
"moveThroughNeighbors() next neighbor elem info:");
690 debugRay(best_elem->get_info());
693 return best_exit_result;
698 unsigned short & incoming_side,
699 Point & intersection_point,
700 unsigned short & intersected_side,
702 Real & intersection_distance)
704 if (!neighbor_info.
_valid)
707 const Elem * neighbor = neighbor_info.
_elem;
708 debugRay(
"Checking neighbor ", neighbor->id(),
" with centroid ", neighbor->vertex_average());
712 for (MooseIndex(neighbor_info.
_sides.size()) i = 0; i < neighbor_info.
_sides.size(); ++i)
715 incoming_side = neighbor_info.
_sides[i];
729 debugRay(
"Called exitsElem() from moveThroughNeighbor()");
730 const auto exit_result =
737 intersection_distance,
739 debugRay(
"Done with exitsElem() from moveThroughNeighbor()");
747 debugRay(
"Called applyOnExternalBoundary() with");
761 debugRay(
" Found ", neighbors.size(),
" vertex/edge neighbors (including self)");
762 traceAssert(std::count_if(neighbors.begin(),
765 { return ni._elem == _current_elem; }),
766 "_current_elem not in neighbors");
768 for (
const auto & neighbor_info : neighbors)
770 if (!neighbor_info._valid)
773 const Elem * elem = neighbor_info._elem;
774 const auto &
sides = neighbor_info._sides;
775 const auto & side_normals = neighbor_info._side_normals;
777 for (MooseIndex(side_normals.size()) i = 0; i < side_normals.size(); ++i)
778 if (!elem->neighbor_ptr(
sides[i])
799 debugRay(
"Calling external onBoundary() with ",
_boundary_elems.size(),
" boundaries");
808 debugRay(
"Called applyOnInternalBoundary() with");
812 debugRay(
" _last_elem->id() = ",
_last_elem->id());
817 "Intersection and incoming points should be the same");
828 debugRay(
"Checking point neighbors for internal sidesets");
832 debugRay(
" Found ", neighbors.size(),
" vertex/edge neighbors");
833 traceAssert(std::count_if(neighbors.begin(),
836 { return ni._elem == _current_elem || ni._elem == _last_elem; }) == 2,
837 "_current_elem/_last_elem not in neighbors");
839 for (
const auto & neighbor_info : neighbors)
841 if (!neighbor_info._valid)
844 const Elem * elem = neighbor_info._elem;
849 if (sidesets.empty())
851 debugRay(
" Elem ", elem->id(),
" has no internal sidesets");
856 const auto &
sides = neighbor_info._sides;
857 const auto & side_normals = neighbor_info._side_normals;
860 for (std::size_t i = 0; i <
sides.size(); ++i)
862 const auto side =
sides[i];
864 if (sidesets[side].size() && std::abs(side_normals[i] * ray->direction()) >
TRACE_TOLERANCE)
880 if (current_elem_sidesets.size() && current_elem_sidesets[
_incoming_side].size())
888 mooseError(
"Internal sidesets are not currently supported with adaptivity in tracing");
910 debugRay(
" Calling internal onBoundary() with ",
_boundary_elems.size(),
" boundaries");
917 const unsigned short side,
918 const std::vector<BoundaryID> & bnd_ids,
924 for (
const auto bnd_id : bnd_ids)
928 if (bnd_elem.bnd_id == bnd_id)
936 debugRay(
" Need to apply boundary on elem ",
951 const Elem *& boundary_elem)
955 traceAssert(boundary_extrema.
isInvalid(),
"Extrema should be invalid");
956 traceAssert(!boundary_elem,
"Elem should be invalid");
957 traceAssert(
_current_elem->dim() != 1,
"1D traces shouldn't make it here");
964 const auto & direction = (*_current_ray)->direction();
975 debugRay(
" Side ", s,
" is a boundary side and the Ray exits");
985 debugRay(
"Checking current element failed, now checking neighbors");
987 debugRay(
"Found ", neighbors.size(),
" candidate neighbors (including self)");
988 for (
const auto & neighbor_info : neighbors)
992 if (!neighbor_info._valid)
995 const Elem * neighbor = neighbor_info._elem;
1000 debugRay(
"Checking neighbor ", neighbor->id());
1003 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
1005 !neighbor->neighbor_ptr(neighbor_info._sides[i]))
1009 traceAssert(boundary_extrema.
atExtrema(),
"Should be at extrema");
1010 boundary_side = neighbor_info._sides[i];
1011 boundary_elem = neighbor;
1032 traceAssert(
_current_elem->active(),
"Current element is not active");
1033 traceAssert(!ray->invalidCurrentPoint(),
"Current point is invalid");
1034 traceAssert(ray->shouldContinue(),
"Ray should not continue");
1035 if (
_study.
verifyRays() && !ray->invalidCurrentIncomingSide() && ray->maxDistance() > 0 &&
1038 failTrace(
"Ray incoming side is not incoming",
false, __LINE__);
1044 debugRay(
"At top of trace for Ray");
1045 debugRay(
"Top of trace loop Ray info\n", ray->getInfo());
1046 debugRay(
"Top of trace loop starting elem info\n", ray->currentElem()->get_info());
1051#ifdef DEBUG_RAY_MESH_IF
1054 if (DEBUG_RAY_MESH_IF)
1064 debugRay(
"Trying to init threaded cached trace");
1092 debugRay(
"At top of ray tracing loop");
1093 debugRay(
" ray->id() = ", ray->id());
1097 debugRay(
" _current_elem->subdomain_id() = ",
_current_elem->subdomain_id());
1100 debugRay(
"Top of ray tracing loop Ray info\n", ray->getInfo());
1101 debugRay(
"Top of ray tracing loop current elem info\n",
_current_elem->get_info());
1103 traceAssert(
_current_ray == &ray,
"Current ray mismatch");
1115 if (ray->stationary())
1117 mooseAssert(ray->invalidDirection(),
"Should have an invalid direction");
1132 traceAssert(
_current_elem->processor_id() ==
_pid,
"Trace elem not on processor");
1133 debugRay(
"Didn't hit vertex or edge: doing normal exits elem check");
1147 if (exits_elem_result !=
NO_EXIT)
1156 debugRay(
"Will not do normal exits elem check because at a vertex/edge");
1164 debugRay(
"Moving through neighbors");
1171 const Elem * move_through_neighbors_last =
nullptr;
1174 const std::vector<NeighborInfo> * neighbors =
nullptr;
1188 debugRay(
" Searching for vertex/edge hit with incoming side ",
1219 if (!neighbors || neighbors->empty())
1223 if (neighbors->empty())
1231 const Elem * best_neighbor =
nullptr;
1234 *neighbors, move_through_neighbors_last, best_neighbor, best_neighbor_side);
1237 if (exits_elem_result ==
NO_EXIT)
1239 failTrace(
"Could not find intersection after trying to move through point neighbors",
1251 ray->setCurrentElem(best_neighbor);
1252 ray->setCurrentIncomingSide(best_neighbor_side);
1256 if (best_neighbor->processor_id() !=
_pid)
1276 debugRay(
"Done with trace");
1280 debugRay(
" _intersected_side centroid: ",
1290 debugRay(
"Incrementing ray intersections by 1 to ", ray->intersections() + 1);
1291 ray->addIntersection();
1301 debugRay(
"Max distance checks");
1303 debugRay(
" ray->maxDistance() = ", ray->maxDistance());
1304 debugRay(
" max_distance (effective) = ", max_distance);
1309 if (MooseUtils::absoluteFuzzyEqual(ray->distance(), max_distance))
1311 debugRay(
"At max distance");
1313 ray->setShouldContinue(
false);
1318 else if (ray->distance() > max_distance)
1320 debugRay(
"Past max distance");
1323 const auto difference = ray->distance() - max_distance;
1324 traceAssert(difference > 0,
"Negative distance change after past_max_distance");
1326 debugRay(
"Removing distance ", difference);
1327 ray->addDistance(-difference);
1328 debugRay(
" New ray->distance() = ", ray->distance());
1336 ray->setShouldContinue(
false);
1342 failTrace(
"Does not contain point after past max distance",
1350 debugRay(
"Calling onSegment() with");
1363 traceAssert(
_should_continue == ray->shouldContinue(),
"Should be the same");
1366 debugRay(
"RayKernel killed the ray or past max distance");
1367 traceAssert(!ray->trajectoryChanged(),
1368 "RayKernels should not change trajectories of Rays at end");
1375 if (ray->trajectoryChanged())
1377 debugRay(
"RayKernel changed the Ray's trajectory");
1378 debugRay(
" new direction = ", ray->direction());
1380 debugRay(
" new incoming point = ", ray->currentPoint());
1388 const auto new_intersection_distance = (ray->currentPoint() -
_incoming_point).norm();
1405 debugRay(
"Killing due to at end without RayKernels");
1406 traceAssert(!ray->shouldContinue(),
"Ray shouldn't continue");
1428 const Elem * boundary_elem =
nullptr;
1444 debugRay(
"Found a neighbor boundary side with:");
1452 const Elem * neighbor =
nullptr;
1471 traceAssert(neighbor->active(),
"Inactive neighbor");
1473 "_current_subdomain_id invalid");
1484 : neighbor->n_sides();
1485 traceAssert(n_sides == neighbor->n_sides(),
"n_sides incorrect");
1496 ray->setCurrentElem(neighbor);
1499 debugRay(
"Next elem: ", neighbor->id(),
" with centroid ", neighbor->vertex_average());
1500 debugRay(
"Next _incoming_side: ",
1505 "_current_subdomain_id invalid");
1521 traceAssert(!ray->shouldContinue(),
"Should be the same");
1522 debugRay(
"Internal RayBC killed the ray");
1529 if (ray->trajectoryChanged())
1531 debugRay(
"Internal RayBC changed the trajectory:");
1532 debugRay(
" new direction = ", ray->direction());
1536 const auto dot = normal * ray->direction();
1537 debugRay(
"Dot product with new direction and side = ", dot);
1545 debugRay(
" Dot > 0 (Ray turned around): Setting _current_elem = ",
1547 " and _incoming_side = ",
1555 "Internal RayBC changed the Ray point");
1561 if (neighbor->processor_id() !=
_pid)
1565 debugRay(
"Neighbor is off processor but continuing to move through neighbors");
1575 if (subdomain_changed)
1581 debugRay(
"No neighbor found - on the boundary");
1588 "RayBC changed the Ray point");
1593 traceAssert(!ray->shouldContinue(),
"Should be the same");
1594 debugRay(
"Exiting due to death by BC");
1600 if (ray->trajectoryChanged())
1608 debugRay(
"RayBC reflected the ray");
1609 debugRay(
" new direction = ", ray->direction());
1610 traceAssert(ray->direction() *
1613 "Reflected ray is not incoming");
1623 debugRay(
"RayBC moved the ray");
1624 debugRay(
" new point = ", ray->currentPoint());
1625 debugRay(
" new pid = ", ray->currentElem()->processor_id());
1626 debugRay(
" new elem id = ", ray->currentElem()->id());
1627 debugRay(
" new side = ", ray->currentIncomingSide());
1658 debugRay(
"Called onCompleteTrace()\n", (*_current_ray)->getInfo());
1661 possiblySaveDebugRayMesh();
1683 traceAssert(ray->shouldContinue(),
"Ray must continue");
1698 traceAssert(ray->currentElem() ==
_current_elem,
"Ray currentElem() invalid");
1699 traceAssert(ray->currentIncomingSide() ==
_incoming_side,
"Ray currentIncomingSide() invalid");
1700 traceAssert(ray->currentPoint() ==
_incoming_point,
"Ray currentPoint() invalid");
1701 traceAssert(
_current_elem->processor_id() !=
_pid,
"Off processor trace is not off processor");
1702 debugRay(
"Ray going off processor to ",
_current_elem->processor_id());
1704 ray->addProcessorCrossing();
1717 possiblySaveDebugRayMesh();
1728 failTrace(
"Elem does not contain point after trajectory change",
1733 traceAssert(ray->shouldContinue(),
"Ray should continue when trajectory is being changed");
1735 ray->setTrajectoryChanged(
false);
1736 ray->addTrajectoryChange();
1752 debugRay(
"Calling onSubdomainChanged() on subdomain ",
_current_elem->subdomain_id());
1767 _old_ray_kernels.insert(current_ray_kernels.begin(), current_ray_kernels.end());
1786 std::stringstream oss;
1787 oss <<
"Ray on processor " <<
_pid <<
" and thread " <<
_tid <<
" failed to trace";
1789 oss <<
" at line " << line;
1790 oss <<
"\n\n" << reason <<
"\n\n";
1791 oss << ((*_current_ray))->getInfo() <<
"\n";
1792 oss <<
"Current trace information\n";
1793 oss <<
" _current_subdomain_id = ";
1795 oss <<
"invalid subdomain id\n";
1798 oss <<
" _current_elem_type = " << Utility::enum_to_string(
_current_elem_type) <<
"\n";
1800 oss <<
" _incoming_point = ";
1802 oss <<
"invalid point\n";
1805 oss <<
" _incoming_side = ";
1807 oss <<
"invalid side\n";
1810 oss <<
" _intersection_point = ";
1812 oss <<
"invalid point\n";
1815 oss <<
" _intersected_side = ";
1817 oss <<
"invalid side\n";
1825 oss <<
"_current_elem = invalid\n";
1827 possiblySaveDebugRayMesh();
1840 (*_current_ray)->setShouldContinue(
false);
1847const std::vector<NeighborInfo> &
1850 traceAssert(elem,
"Elem must be valid");
1851 traceAssert(vertex,
"Vertex must be valid");
1853 debugRay(
"Called getVertexNeighbors() with:");
1854 debugRay(
" elem->id() = ", elem->id(),
" with centroid ", elem->vertex_average());
1855 debugRay(
" vertex->id() = ", vertex->id(),
", at ", (Point)*vertex);
1858 traceAssert(elem->is_vertex(elem->get_node_index(vertex)),
"Node is not a vertex");
1865 return search->second;
1870 debugRay(
"Building vertex neighbors");
1871 std::vector<NeighborInfo> & entry =
1883 for (
auto & neighbor_info : entry)
1884 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
1885 neighbor_info._side_normals[i] =
1891const std::vector<NeighborInfo> &
1894 traceAssert(vertex < elem->n_vertices(),
"Invalid vertex");
1899const std::vector<NeighborInfo> &
1901 const std::pair<const Node *, const Node *> & vertices,
1902 const Point & point)
1904 traceAssert(elem,
"Invalid elem");
1905 traceAssert(vertices.first,
"Must be valid");
1906 traceAssert(vertices.second,
"Must be valid");
1908 debugRay(
"Called getEdgeNeighbors() with:");
1909 debugRay(
" elem->id() = ", elem->id(),
" with centroid ", elem->vertex_average());
1910 debugRay(
" vertices.first = ", vertices.first->id(),
" at ", (Point)*vertices.first);
1911 debugRay(
" vertices.second = ", vertices.second->id(),
" at ", (Point)*vertices.second);
1912 debugRay(
" point = ", point);
1915 "Doesn't contain vertex");
1917 "Doesn't contain vertex");
1920 "Point not within edge");
1924 const auto ordered_vertices = vertices.first->id() < vertices.second->id()
1926 : std::make_pair(vertices.second, vertices.first);
1929 std::pair<bool, std::vector<NeighborInfo>> * entry;
1932 entry = &search->second;
1935 debugRay(
"Building edge neighbors");
1938 .emplace(ordered_vertices, std::make_pair(
true, std::vector<NeighborInfo>()))
1941 ordered_vertices.first,
1942 ordered_vertices.second,
1949 bool all_same_edge =
true;
1950 for (
auto & neighbor_info : entry->second)
1952 traceAssert(neighbor_info._lower_bound <= neighbor_info._upper_bound,
1953 "Bound order incorrect");
1956 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
1957 neighbor_info._side_normals[i] =
1961 if (neighbor_info._lower_bound != 0 || neighbor_info._upper_bound != 1)
1962 all_same_edge =
false;
1964 entry->first = all_same_edge;
1971 const auto edge_length =
1972 ((Point)*ordered_vertices.first - (Point)*ordered_vertices.second).norm();
1973 const auto point_location = ((Point)*ordered_vertices.first - point).norm() / edge_length;
1974 for (
auto & info : entry->second)
1975 info._valid = (info._lower_bound -
TRACE_TOLERANCE) < point_location &&
1979 return entry->second;
1982const std::vector<NeighborInfo> &
1984 const std::pair<unsigned short, unsigned short> & vertices,
1985 const Point & point)
1987 debugRay(
"Called getEdgeNeighbors(), local index version with:");
1988 debugRay(
" vertices.first = ", vertices.first);
1989 debugRay(
" vertices.second = ", vertices.second);
1990 traceAssert(vertices.first < elem->n_vertices(),
1991 "Invalid vertex with ray " + std::to_string((*_current_ray)->id()));
1992 traceAssert(vertices.second < elem->n_vertices(),
"Invalid vertex");
1995 elem, std::make_pair(elem->node_ptr(vertices.first), elem->node_ptr(vertices.second)), point);
1998const std::vector<NeighborInfo> &
2008const std::vector<NeighborInfo> &
2011 traceAssert(elem,
"Invalid elem");
2013 debugRay(
"Called getPointNeighbors()");
2014 debugRay(
" elem = ", elem->id());
2015 debugRay(
" point = ", point);
2030 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
2031 neighbor_info._side_normals[i] =
2047 mooseError(
"Should not call storeExitsElemResult() with result ", result);
2053 traceAssert((*_current_ray)->currentElem() ==
_current_elem,
"Ray currentElem() incorrect");
2055 "Ray currentPoint() incorrect");
2056 traceAssert((*_current_ray)->currentIncomingSide() ==
_incoming_side,
2057 "Ray currentIncomingSide() incorrect");
2063 "_current_elem does not contain incoming point");
2070 "Intersected point is not on intersected side");
2073 "Intersected side is not outgoing");
2080 "Incoming point is not on incoming side");
2081 if (ray->intersections() != 0 && ray->maxDistance() != 0)
2084 "Incoming side is not incoming");
2090 "_intersection_distance is incorrect");
2094 "Invalid intersection distance");
2100 for (
auto & rk : rks)
2111 "Ray currentPoint() not set before onBoundary()");
2144 debugRay(
"Calling ",
2146 "::onBoundary for \"",
2149 bnd_elem.elem->id(),
2176 if (external && !ray->trajectoryChanged() && ray->shouldContinue())
2178 std::stringstream oss;
2179 oss <<
"Don't know what to do with a Ray after it hit an external\n";
2181 oss <<
"When hitting an external RayBC, a Ray must either:\n";
2182 oss <<
" Be killed by a RayBC\n";
2183 oss <<
" Have its trajectory changed by the RayBC\n";
2184 oss <<
"by at least one of the executed RayBCs.\n\n";
2185 oss <<
"You need to either:\n";
2186 oss <<
" Kill/change the Ray sooner with RayKernels, internal RayBCs, or a max distance\n";
2187 oss <<
" Kill/change the Ray on the boundary with a RayBC\n\n";
2190 oss <<
"RayBCs executed that did not kill or change the Ray:\n";
2193 if (rbc->hasBoundary(bnd_elem.bnd_id))
2194 oss <<
" " << rbc->typeAndName() <<
" on boundary " << bnd_elem.bnd_id <<
" ("
2198 bool output_header =
false;
2204 if (rbc->hasBoundary(bnd_id))
2214 oss <<
"Boundaries that did not have any RayBCs:\n";
2215 output_header =
true;
2228 const auto subdomain_id = elem->subdomain_id();
2236 if (!ray->shouldContinue())
2243 " set a Ray to continue that was previously set to not continue.\n\n" +
2244 "Once a Ray has been set to not continue, its continue status cannot change.",
2250 " changed the trajectory of a Ray that was set to not continue,\n" +
2251 "or set a Ray whose trajectory was changed to not continue.",
void mooseWarning(Args &&... args)
void mooseError(Args &&... args)
std::string typeAndName() const
const std::string & getBoundaryName(const BoundaryID boundary_id) const
Base class for the RayBC syntax.
Base object for the RayKernel syntax.
Base class for a MooseObject used in ray tracing.
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...
bool sideIsNonPlanar(const Elem *elem, const unsigned short s) const
Whether or not the side \s on elem elem is non-planar.
const std::vector< RayKernelBase * > & currentRayKernels(THREAD_ID tid) const
Gets the current RayKernels for a thread, which are set in segmentSubdomainSetup()
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.
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.
virtual const Point * getElemNormals(const Elem *, const THREAD_ID)
Gets the outward normals for a given element.
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 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 postOnSegment(const THREAD_ID tid, const std::shared_ptr< Ray > &ray)
Called at the end of a Ray segment.
bool isRectangularDomain() const
Whether or not the domain is rectangular (if it is prefectly encompassed by its bounding box)
bool segmentsOnCacheTraces() const
Whether or not to cache individual element segments when _cache_traces = true.
Real domainMaxLength() const
Get the inflated maximum length across the domain.
bool verifyRays() const
Whether or not to verify if Rays have valid information before being traced.
virtual const Point & getSideNormal(const Elem *elem, const unsigned short side, const THREAD_ID tid)
Get the outward normal for a given element side.
Real rayMaxDistance() const
Max distance any Ray can travel.
bool rayDependentSubdomainSetup() const
Whether or not to use Ray dependent subdomain setup.
bool auxDataOnCacheTraces() const
Whether or not to store the Ray aux data on the cached Ray traces.
const std::vector< std::vector< BoundaryID > > & getInternalSidesets(const Elem *elem) const
Get the internal sidesets (that have RayBC(s)) for each side for a given element.
bool hasSameLevelActiveElems() const
Whether or not the mesh has active elements of the same level.
virtual void preTrace(const THREAD_ID, const std::shared_ptr< Ray > &)
Called at the beginning of a trace for a ray.
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.
bool hasInternalSidesets() const
Whether or not the local mesh has internal sidesets that have RayBCs on them.
bool verifyTraceIntersections() const
Whether or not trace verification is enabled in devel/dbg modes.
void getRayBCs(std::vector< RayBoundaryConditionBase * > &result, BoundaryID id, THREAD_ID tid)
Fills the active RayBCs associated with this study and a boundary into result.
const BoundingBox & boundingBox() const
Get the nodal bounding box for the domain.
bool tolerateFailure() const
Whether or not to tolerate failure.
bool hasRayKernels(const THREAD_ID tid)
Whether or not there are currently any active RayKernel objects.
bool currentlyPropagating() const
Whether or not the study is propagating (tracing Rays)
bool dataOnCacheTraces() const
Whether or not to store the Ray data on the cached Ray traces.
std::vector< TraceRayBndElement > _boundary_elems
Boundary elements that need RayBCs to be applied.
std::unordered_map< std::pair< const Node *, const Node * >, std::pair< bool, std::vector< NeighborInfo > > > _edge_neighbors
The cached edge neighbors.
std::vector< unsigned long long int > _results
Results over all of the local traces, indexed by TraceRayResult.
MooseMesh & _mesh
The MooseMesh.
const std::vector< NeighborInfo > & getVertexNeighbors(const Elem *elem, const Node *vertex)
Gets the neighbors at a vertex.
unsigned short _intersected_side
The work point for the intersected side of the current Ray.
std::vector< const Elem * > _neighbor_active_neighbor_children
const Elem * _current_elem
The element the current Ray is being traced in.
MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > _neighbor_untested_set
TraceRay(RayTracingStudy &study, const THREAD_ID tid)
TraceData * _current_cached_trace
The TraceData for the current cached trace (if any)
void meshChanged()
Called on mesh change.
Real _current_subdomain_hmax
The current subdomain hmax.
void failTrace(const std::string &reason, const bool warning, const int line=-1)
Specialized mooseError for a failed Ray trace with detailed information regarding the trace.
const Point * _current_normals
The normals for the current element for backface culling (pointer to the first normal - optional)
void findExternalBoundarySide(unsigned short &boundary_side, ElemExtrema &boundary_extrema, const Elem *&boundary_elem)
Finds (if any) an element side that is on the boundary and is outgoing at _intersection_point that is...
ExitsElemResult moveThroughNeighbor(const NeighborInfo &neighbor_info, unsigned short &incoming_side, Point &intersection_point, unsigned short &intersected_side, ElemExtrema &intersected_extrema, Real &intersection_distance)
Sees if a Ray can move through a neighbor (vertex/edge/point)
const std::vector< NeighborInfo > & getNeighbors(const Elem *elem, const ElemExtrema &extrema, const Point &point)
Get the point/vertex/edge neighbors depending on extrema.
bool _has_ray_kernels
Whether or not the RayTracingStudy has any RayKernels.
std::set< RayKernelBase * > _old_ray_kernels
Helper for avoiding calling preTrace() on the same RayKernel multiple times.
Real _intersection_distance
The work point for the intersection distance of the current Ray.
bool _is_rectangular_domain
Whether or not the domain is rectangular (defined perfectly by its bounding box)
ElemExtrema _intersected_extrema
The work point for the intersected vertex/edge vertices of the current Ray, if any.
Point _incoming_point
The incoming point of the current Ray.
unsigned int _debug_node_count
const std::vector< NeighborInfo > & getPointNeighbors(const Elem *elem, const Point &point)
Get the point neighbors.
bool _exits_elem
Whether or not the current trace exits an element.
void onBoundary(const std::shared_ptr< Ray > &ray, const bool external)
Called when a Ray hits a boundary.
void postRayTracingObject(const std::shared_ptr< Ray > &ray, const RayTracingObject *rto)
Called after executing a RayTracingObject (RayBCs and RayKernels)
std::vector< BoundaryID > _boundary_ids
Reusable vector for calling _boundary_info.boundary_ids()
const processor_id_type _pid
The processor id.
unsigned short _current_elem_n_sides
The number of sides on the current elem, used to avoid elem->n_sides() virtual calls.
std::unordered_map< const Node *, std::vector< NeighborInfo > > _vertex_neighbors
The cached vertex neighbors.
ExitsElemResult exitsElem(const Elem *elem, const ElemType elem_type, const unsigned short incoming_side, Point &intersection_point, unsigned short &intersected_side, ElemExtrema &intersected_extrema, Real &intersection_distance, const Point *normals)
Determines if _current_ray moving in direction _direction exits elem.
void possiblyAddToBoundaryElems(const Elem *elem, const unsigned short side, const std::vector< BoundaryID > &bnd_ids, const ElemExtrema &extrema)
Helper for possibly storing boundary information in _boundary_elems, which is storage for boundary el...
BoundaryID _current_bnd_id
The current BoundaryID (used when calling RayBoundaryConditionBase::onBoundary())
void preExecute()
Should be called immediately before calling any traces.
bool _should_continue
Whether or not the current Ray should continue.
const Elem * _last_elem
The last element the current Ray was traced in.
std::vector< RayBoundaryConditionBase * > _on_boundary_ray_bcs
Reusable for getting the RayBCs in onBoundary()
libMesh::ElemType _current_elem_type
The current elem type (constant on subdomain), used to avoid elem->type() calls.
@ BACKFACE_CULLING_FAILURES
@ VERTEX_NEIGHBOR_LOOKUPS
@ BACKFACE_CULLING_SUCCESSES
@ MOVED_THROUGH_NEIGHBORS
std::vector< NeighborInfo > _point_neighbor_helper
Reusable for building neighbors.
void trace(const std::shared_ptr< Ray > &ray)
Traces a ray.
bool _backface_culling
Whether or not to use element normals for backface culling.
void onTrajectoryChanged(const std::shared_ptr< Ray > &ray)
Called when a Ray's trajectory changes.
Parallel::Communicator _debug_comm
const unsigned int _dim
The mesh dimension.
ExitsElemResult
Enum for the different exit results for exitElem()
RayTracingStudy & _study
The RayTracingStudy.
MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > _neighbor_set
const std::shared_ptr< Ray > * _current_ray
The current ray being traced.
void storeExitsElemResult(const ExitsElemResult result)
Stores the result given by an intersection in _results as necessary.
libMesh::ElemSideBuilder _elem_side_builder
Helper for building element sides without excessive allocation.
void onSegment(const std::shared_ptr< Ray > &ray)
Called on a single segment traced by a Ray.
unsigned short _incoming_side
The incoming side of the current Ray.
ExitsElemResult moveThroughNeighbors(const std::vector< NeighborInfo > &neighbors, const Elem *last_elem, const Elem *&best_elem, unsigned short &best_elem_incoming_side)
Moves the Ray though neighbors (vertex/edge/point)
void continueTraceOffProcessor(const std::shared_ptr< Ray > &ray)
Sets up a ray to continue tracing off processor.
void applyOnInternalBoundary(const std::shared_ptr< Ray > &ray)
Gets and applies internal boundary conditions (if any) from _current_elem, _last_elem,...
SubdomainID _current_subdomain_id
The current SubdomainID.
std::vector< std::size_t > _on_boundary_apply_index
Reusable for which boundary elements to apply for a specific RayBC in onBoundary()
MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > _neighbor_next_untested_set
const BoundaryInfo & _boundary_info
The BoundaryInfo for the mesh.
void onSubdomainChanged(const std::shared_ptr< Ray > &ray, const bool same_ray)
Called when the subdomain changes.
ElemExtrema _last_intersected_extrema
The intersected vertex/edge vertices for the previous intersection, if any.
const THREAD_ID _tid
The thread id.
void onCompleteTrace(const std::shared_ptr< Ray > &ray)
Called when a Ray is finished tracing (whenever !ray->shouldContinue())
Real subdomainHmax(const Elem *elem) const
Get the approximate subdomain hmax for an element.
Point _intersection_point
The work point for the intersection of the current Ray.
void onContinueTrace(const std::shared_ptr< Ray > &)
Called when a Ray is continuing to trace after segment.
std::string failTraceMessage(const std::string &reason, const int line=-1)
Creates a useful error string with current tracing information.
void applyOnExternalBoundary(const std::shared_ptr< Ray > &ray)
Gets and applies external boundary conditions in _current_elem on side _intersected_side at _intersec...
const std::vector< NeighborInfo > & getEdgeNeighbors(const Elem *elem, const std::pair< const Node *, const Node * > &vertices, const Point &point)
Get the neighbors at an edge.
static const unsigned short invalid_side
Identifier for an invalid side index.
static const libMesh::Real invalid_distance
Identifier for an invalid distance.
static const libMesh::Point invalid_point(invalid_distance, invalid_distance, invalid_distance)
Identifier for an invalid point.
static const unsigned short invalid_vertex
Identifier for an invalid vertex index.
const unsigned int invalid_uint
OStreamProxy err(std::cerr)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Helper for defining if at an element's edge, vertex, or neither.
unsigned short vertex() const
bool isValid(const Elem *const elem, const Point &point) const
void invalidate()
Invalidates the current state.
void setVertex(const unsigned short vertex)
Sets the "at vertex" state.
const std::pair< unsigned short, unsigned short > & edgeVertices() const
Struct for containing the necessary information about a cached neighbor for ray tracing.
const std::vector< unsigned short > _sides
The sides on the element that the neighboring portion is contained in.
bool _valid
Whether or not this neighbor is valid (needed for neighbors that span an edge)
const Elem *const _elem
The element.
std::vector< Point > _side_normals
The normals of each side in _sides.
TracePointData & lastPoint()
bool _last
Whether or not this was the last set of segments for this Ray.
void addPoint(const libMesh::Point &point)
std::vector< RayData > _aux_data
The aux data on the Ray after this segment is traced (optional)
std::vector< RayData > _data
The data on the Ray after this segment is traced (optional)