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" 49 _mesh(study.getSubProblem().
mesh()),
50 _dim(_mesh.dimension()),
51 _boundary_info(_mesh.
getMesh().get_boundary_info()),
52 _pid(_study.comm().rank()),
54 _backface_culling(false),
55 _current_normals(nullptr),
56 _results(ENDED_STATIONARY + 1)
85 const unsigned short incoming_side,
86 Point & intersection_point,
87 unsigned short & intersected_side,
89 Real & intersection_distance,
90 const Point * normals)
92 debugRay(
"Called exitsElem()");
94 traceAssert(elem_type == elem->
type(),
"elem_type incorrect");
97 traceAssert(intersected_extrema.
isInvalid(),
"Extrema should be invalid");
99 "Distance should be invalid");
103 "Incoming side is non-entrant");
109 intersected = exitsElem<Hex8, Hex8>(elem,
114 intersection_distance,
118 intersected = exitsElem<Tet4, Tet4>(elem,
123 intersection_distance,
127 intersected = exitsElem<Pyramid5, Pyramid5>(elem,
132 intersection_distance,
136 intersected = exitsElem<Prism6, Prism6>(elem,
141 intersection_distance,
145 intersected = exitsElem<Quad4, Quad4>(elem,
150 intersection_distance,
154 intersected = exitsElem<Tri3, Tri3>(elem,
159 intersection_distance,
163 intersected = exitsElem<Hex20, Hex8>(elem,
168 intersection_distance,
172 intersected = exitsElem<Hex27, Hex8>(elem,
177 intersection_distance,
181 intersected = exitsElem<Quad8, Quad4>(elem,
186 intersection_distance,
190 intersected = exitsElem<Quad9, Quad4>(elem,
195 intersection_distance,
199 intersected = exitsElem<Tri6, Tri3>(elem,
204 intersection_distance,
208 intersected = exitsElem<Tri7, Tri3>(elem,
213 intersection_distance,
217 intersected = exitsElem<Tet10, Tet4>(elem,
222 intersection_distance,
226 intersected = exitsElem<Tet14, Tet4>(elem,
231 intersection_distance,
235 intersected = exitsElem<Pyramid13, Pyramid5>(elem,
240 intersection_distance,
244 intersected = exitsElem<Pyramid14, Pyramid5>(elem,
249 intersection_distance,
253 intersected = exitsElem<Prism15, Prism6>(elem,
258 intersection_distance,
262 intersected = exitsElem<Prism18, Prism6>(elem,
267 intersection_distance,
271 intersected = exitsElem<Edge2, Edge2>(elem,
276 intersection_distance,
280 intersected = exitsElem<Edge3, Edge2>(elem,
285 intersection_distance,
289 intersected = exitsElem<Edge4, Edge2>(elem,
294 intersection_distance,
299 "Element type ", Utility::enum_to_string(elem->type()),
" not supported by TraceRay");
304 if (intersected_extrema.atExtrema())
312 template <
typename T,
typename FirstOrderT>
313 typename std::enable_if<!std::is_base_of<Edge, T>::value,
bool>::type
315 const unsigned short incoming_side,
316 Point & intersection_point,
317 unsigned short & intersected_side,
319 Real & intersection_distance,
320 const Point * normals)
324 debugRay(
"Called exitsElem() in 2D or 3D");
329 Point current_intersection_point;
330 Real current_intersection_distance;
340 bool try_nonplanar_incoming_side =
false;
342 const auto & direction = (*_current_ray)->direction();
344 unsigned short s = 0;
353 debugRay(
" use_backface_culling = ", use_backface_culling);
354 debugRay(
" try_nonplanar_incoming_side = ", try_nonplanar_incoming_side);
358 debugRay(
" Side ", s,
" with centroid ",
_elem_side_builder(*elem, s).vertex_average());
364 if (!try_nonplanar_incoming_side)
368 if (s == incoming_side)
370 debugRay(
" Skipping due to incoming side");
371 if (++s == T::num_sides)
379 if (use_backface_culling)
384 debugRay(
" Skipping due to backface culling dot = ", normals[s] * direction);
386 if (++s == T::num_sides)
403 debugRay(
" Skipping because we already checked this side with culling enabled");
404 if (++s == T::num_sides)
410 debugRay(
" Side that was skipped due to culling");
419 const bool intersected = sideIntersectedByLine<FirstOrderT>(elem,
424 current_intersection_point,
425 current_intersection_distance,
426 current_intersected_extrema,
428 #ifdef DEBUG_RAY_INTERSECTIONS 438 debugRay(
" Intersected at point ",
439 current_intersection_point,
441 current_intersection_distance);
442 debugRay(
" Best intersection distance = ", best_intersection_distance);
448 failTrace(
"Intersected side does not contain intersection point",
455 if (current_intersection_distance > best_intersection_distance)
457 debugRay(
" Best intersection so far");
459 intersected_side = s;
460 intersection_distance = current_intersection_distance;
461 intersection_point = current_intersection_point;
462 intersected_extrema = current_intersected_extrema;
463 best_intersection_distance = current_intersection_distance;
467 if (++s == T::num_sides || try_nonplanar_incoming_side)
476 debugRay(
" Exiting with intersection");
477 debugRay(
" intersected_side = ", intersected_side);
478 debugRay(
" intersection_distance = ", intersection_distance);
479 debugRay(
" intersection_point = ", intersection_point);
480 debugRay(
" intersected_extrema = ", intersected_extrema);
486 if (try_nonplanar_incoming_side)
491 if (use_backface_culling)
493 debugRay(
" Didn't find an intersection, retrying without backface culling");
494 use_backface_culling =
false;
504 debugRay(
" Didn't find an intersection, trying non-planar incoming_side");
505 try_nonplanar_incoming_side =
true;
515 template <
typename T,
typename FirstOrderT>
516 typename std::enable_if<std::is_base_of<Edge, T>::value,
bool>::type
518 const unsigned short incoming_side,
519 Point & intersection_point,
520 unsigned short & intersected_side,
522 Real & intersection_distance,
527 debugRay(
"Called exitsElem() in 1D");
536 intersected_side = (incoming_side == 1 ? 0 : 1);
537 intersected_extrema.
setVertex(intersected_side);
538 intersection_point = elem->
point(intersected_side);
541 debugRay(
" Incoming side is set to ", incoming_side,
" so setting to other side");
542 debugRay(
" Intersected side ", intersected_side,
" at ", intersection_point);
548 const Point extended_end_point =
553 for (MooseIndex(elem->
n_sides()) side = 0; side < elem->
n_sides(); ++side)
556 debugRay(
" Checking side ", side,
" at ", side_point);
559 if (incoming_to_side <
tol)
561 debugRay(
" Continuing because at side");
566 const Real side_to_end = (extended_end_point - side_point).
norm();
567 const Real sum = incoming_to_side + side_to_end - incoming_to_end;
568 debugRay(
" Sum = ", sum);
570 if (std::abs(sum) <
tol)
572 intersected_side = side;
574 intersection_point = side_point;
575 intersection_distance = incoming_to_side;
576 debugRay(
" Intersected at ", intersection_point);
586 const Elem * last_elem,
587 const Elem *& best_elem,
588 unsigned short & best_elem_incoming_side)
592 debugRay(
"Called moveThroughNeighbors() with ", neighbors.size(),
" neighbors, and:");
593 debugRay(
" last_elem->id() = ", last_elem ? last_elem->
id() : DofObject::invalid_id);
596 traceAssert(!best_elem,
"Best elem should be null");
598 "Best elem side should be invalid");
603 "Distance should be invalid");
607 Real longest_distance = 1.0e-12;
609 unsigned short current_incoming_side;
610 Point current_intersection_point;
611 unsigned short current_intersected_side;
613 Real current_intersection_distance;
624 if (neighbor_info._elem == last_elem)
626 debugRay(
"Skipping last elem ", last_elem->
id());
627 last_elem_info = &neighbor_info;
632 current_incoming_side,
633 current_intersection_point,
634 current_intersected_side,
635 current_intersected_extrema,
636 current_intersection_distance);
641 debugRay(
"Ray can exit through neighbor ", neighbor_info._elem->id());
643 if (current_intersection_distance > longest_distance)
645 best_elem = neighbor_info._elem;
646 best_elem_incoming_side = current_incoming_side;
651 longest_distance = current_intersection_distance;
652 best_exit_result = exit_result;
658 if (!best_elem && last_elem_info)
661 current_incoming_side,
662 current_intersection_point,
663 current_intersected_side,
664 current_intersected_extrema,
665 current_intersection_distance);
667 if (exit_result !=
NO_EXIT && current_intersection_distance > longest_distance)
669 debugRay(
"Ray can exit through last_elem ", last_elem->
id());
671 best_elem = last_elem;
672 best_elem_incoming_side = current_incoming_side;
677 best_exit_result = exit_result;
681 debugRay(
"moveThroughNeighbors() best result:");
682 debugRay(
" best_elem = ", best_elem ? best_elem->
id() : DofObject::invalid_id);
683 debugRay(
" best_elem_incoming_side = ", best_elem_incoming_side);
690 debugRay(
"moveThroughNeighbors() next neighbor elem info:");
694 return best_exit_result;
699 unsigned short & incoming_side,
700 Point & intersection_point,
701 unsigned short & intersected_side,
703 Real & intersection_distance)
705 if (!neighbor_info.
_valid)
708 const Elem * neighbor = neighbor_info.
_elem;
709 debugRay(
"Checking neighbor ", neighbor->
id(),
" with centroid ", neighbor->
vertex_average());
713 for (MooseIndex(neighbor_info.
_sides.size()) i = 0; i < neighbor_info.
_sides.size(); ++i)
716 incoming_side = neighbor_info.
_sides[i];
730 debugRay(
"Called exitsElem() from moveThroughNeighbor()");
731 const auto exit_result =
738 intersection_distance,
740 debugRay(
"Done with exitsElem() from moveThroughNeighbor()");
748 debugRay(
"Called applyOnExternalBoundary() with");
762 debugRay(
" Found ", neighbors.size(),
" vertex/edge neighbors (including self)");
763 traceAssert(std::count_if(neighbors.begin(),
767 "_current_elem not in neighbors");
769 for (
const auto & neighbor_info : neighbors)
771 if (!neighbor_info._valid)
774 const Elem * elem = neighbor_info._elem;
775 const auto &
sides = neighbor_info._sides;
776 const auto & side_normals = neighbor_info._side_normals;
778 for (MooseIndex(side_normals.size()) i = 0; i < side_normals.size(); ++i)
800 debugRay(
"Calling external onBoundary() with ",
_boundary_elems.size(),
" boundaries");
809 debugRay(
"Called applyOnInternalBoundary() with");
818 "Intersection and incoming points should be the same");
829 debugRay(
"Checking point neighbors for internal sidesets");
833 debugRay(
" Found ", neighbors.size(),
" vertex/edge neighbors");
834 traceAssert(std::count_if(neighbors.begin(),
838 "_current_elem/_last_elem not in neighbors");
840 for (
const auto & neighbor_info : neighbors)
842 if (!neighbor_info._valid)
845 const Elem * elem = neighbor_info._elem;
850 if (sidesets.empty())
852 debugRay(
" Elem ", elem->
id(),
" has no internal sidesets");
857 const auto &
sides = neighbor_info._sides;
858 const auto & side_normals = neighbor_info._side_normals;
861 for (std::size_t i = 0; i <
sides.size(); ++i)
863 const auto side =
sides[i];
865 if (sidesets[side].size() && std::abs(side_normals[i] * ray->direction()) >
TRACE_TOLERANCE)
881 if (current_elem_sidesets.size() && current_elem_sidesets[
_incoming_side].size())
889 mooseError(
"Internal sidesets are not currently supported with adaptivity in tracing");
911 debugRay(
" Calling internal onBoundary() with ",
_boundary_elems.size(),
" boundaries");
918 const unsigned short side,
919 const std::vector<BoundaryID> & bnd_ids,
925 for (
const auto bnd_id : bnd_ids)
929 if (bnd_elem.bnd_id == bnd_id)
937 debugRay(
" Need to apply boundary on elem ",
952 const Elem *& boundary_elem)
956 traceAssert(boundary_extrema.
isInvalid(),
"Extrema should be invalid");
957 traceAssert(!boundary_elem,
"Elem should be invalid");
965 const auto & direction = (*_current_ray)->direction();
976 debugRay(
" Side ", s,
" is a boundary side and the Ray exits");
986 debugRay(
"Checking current element failed, now checking neighbors");
988 debugRay(
"Found ", neighbors.size(),
" candidate neighbors (including self)");
989 for (
const auto & neighbor_info : neighbors)
993 if (!neighbor_info._valid)
996 const Elem * neighbor = neighbor_info._elem;
1001 debugRay(
"Checking neighbor ", neighbor->
id());
1004 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
1010 traceAssert(boundary_extrema.
atExtrema(),
"Should be at extrema");
1011 boundary_side = neighbor_info._sides[i];
1012 boundary_elem = neighbor;
1034 traceAssert(!ray->invalidCurrentPoint(),
"Current point is invalid");
1035 traceAssert(ray->shouldContinue(),
"Ray should not continue");
1036 if (
_study.
verifyRays() && !ray->invalidCurrentIncomingSide() && ray->maxDistance() > 0 &&
1039 failTrace(
"Ray incoming side is not incoming",
false, __LINE__);
1045 debugRay(
"At top of trace for Ray");
1046 debugRay(
"Top of trace loop Ray info\n", ray->getInfo());
1047 debugRay(
"Top of trace loop starting elem info\n", ray->currentElem()->get_info());
1052 #ifdef DEBUG_RAY_MESH_IF 1055 if (DEBUG_RAY_MESH_IF)
1065 debugRay(
"Trying to init threaded cached trace");
1093 debugRay(
"At top of ray tracing loop");
1094 debugRay(
" ray->id() = ", ray->id());
1101 debugRay(
"Top of ray tracing loop Ray info\n", ray->getInfo());
1104 traceAssert(
_current_ray == &ray,
"Current ray mismatch");
1116 if (ray->stationary())
1118 mooseAssert(ray->invalidDirection(),
"Should have an invalid direction");
1134 debugRay(
"Didn't hit vertex or edge: doing normal exits elem check");
1148 if (exits_elem_result !=
NO_EXIT)
1157 debugRay(
"Will not do normal exits elem check because at a vertex/edge");
1165 debugRay(
"Moving through neighbors");
1172 const Elem * move_through_neighbors_last =
nullptr;
1175 const std::vector<NeighborInfo> * neighbors =
nullptr;
1189 debugRay(
" Searching for vertex/edge hit with incoming side ",
1220 if (!neighbors || neighbors->empty())
1224 if (neighbors->empty())
1232 const Elem * best_neighbor =
nullptr;
1235 *neighbors, move_through_neighbors_last, best_neighbor, best_neighbor_side);
1238 if (exits_elem_result ==
NO_EXIT)
1240 failTrace(
"Could not find intersection after trying to move through point neighbors",
1252 ray->setCurrentElem(best_neighbor);
1253 ray->setCurrentIncomingSide(best_neighbor_side);
1277 debugRay(
"Done with trace");
1281 debugRay(
" _intersected_side centroid: ",
1291 debugRay(
"Incrementing ray intersections by 1 to ", ray->intersections() + 1);
1292 ray->addIntersection();
1302 debugRay(
"Max distance checks");
1304 debugRay(
" ray->maxDistance() = ", ray->maxDistance());
1305 debugRay(
" max_distance (effective) = ", max_distance);
1312 debugRay(
"At max distance");
1314 ray->setShouldContinue(
false);
1319 else if (ray->distance() > max_distance)
1321 debugRay(
"Past max distance");
1324 const auto difference = ray->distance() - max_distance;
1325 traceAssert(difference > 0,
"Negative distance change after past_max_distance");
1327 debugRay(
"Removing distance ", difference);
1328 ray->addDistance(-difference);
1329 debugRay(
" New ray->distance() = ", ray->distance());
1337 ray->setShouldContinue(
false);
1343 failTrace(
"Does not contain point after past max distance",
1351 debugRay(
"Calling onSegment() with");
1364 traceAssert(
_should_continue == ray->shouldContinue(),
"Should be the same");
1367 debugRay(
"RayKernel killed the ray or past max distance");
1368 traceAssert(!ray->trajectoryChanged(),
1369 "RayKernels should not change trajectories of Rays at end");
1376 if (ray->trajectoryChanged())
1378 debugRay(
"RayKernel changed the Ray's trajectory");
1379 debugRay(
" new direction = ", ray->direction());
1381 debugRay(
" new incoming point = ", ray->currentPoint());
1406 debugRay(
"Killing due to at end without RayKernels");
1407 traceAssert(!ray->shouldContinue(),
"Ray shouldn't continue");
1429 const Elem * boundary_elem =
nullptr;
1445 debugRay(
"Found a neighbor boundary side with:");
1453 const Elem * neighbor =
nullptr;
1472 traceAssert(neighbor->active(),
"Inactive neighbor");
1474 "_current_subdomain_id invalid");
1485 : neighbor->n_sides();
1486 traceAssert(n_sides == neighbor->n_sides(),
"n_sides incorrect");
1497 ray->setCurrentElem(neighbor);
1500 debugRay(
"Next elem: ", neighbor->id(),
" with centroid ", neighbor->vertex_average());
1501 debugRay(
"Next _incoming_side: ",
1506 "_current_subdomain_id invalid");
1522 traceAssert(!ray->shouldContinue(),
"Should be the same");
1523 debugRay(
"Internal RayBC killed the ray");
1530 if (ray->trajectoryChanged())
1532 debugRay(
"Internal RayBC changed the trajectory:");
1533 debugRay(
" new direction = ", ray->direction());
1537 const auto dot = normal * ray->direction();
1538 debugRay(
"Dot product with new direction and side = ", dot);
1546 debugRay(
" Dot > 0 (Ray turned around): Setting _current_elem = ",
1548 " and _incoming_side = ",
1556 "Internal RayBC changed the Ray point");
1562 if (neighbor->processor_id() !=
_pid)
1566 debugRay(
"Neighbor is off processor but continuing to move through neighbors");
1576 if (subdomain_changed)
1582 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())
1602 debugRay(
"RayBC changed the trajectory");
1603 debugRay(
" new direction = ", ray->direction());
1604 traceAssert(ray->direction() *
1607 "Reflected ray is not incoming");
1632 debugRay(
"Called onCompleteTrace()\n", (*_current_ray)->getInfo());
1635 possiblySaveDebugRayMesh();
1657 traceAssert(ray->shouldContinue(),
"Ray must continue");
1672 traceAssert(ray->currentElem() ==
_current_elem,
"Ray currentElem() invalid");
1673 traceAssert(ray->currentIncomingSide() ==
_incoming_side,
"Ray currentIncomingSide() invalid");
1674 traceAssert(ray->currentPoint() ==
_incoming_point,
"Ray currentPoint() invalid");
1678 ray->addProcessorCrossing();
1691 possiblySaveDebugRayMesh();
1702 failTrace(
"Elem does not contain point after trajectory change",
1707 traceAssert(ray->shouldContinue(),
"Ray should continue when trajectory is being changed");
1709 ray->setTrajectoryChanged(
false);
1710 ray->addTrajectoryChange();
1741 _old_ray_kernels.insert(current_ray_kernels.begin(), current_ray_kernels.end());
1760 std::stringstream oss;
1761 oss <<
"Ray on processor " <<
_pid <<
" and thread " <<
_tid <<
" failed to trace";
1763 oss <<
" at line " << line;
1764 oss <<
"\n\n" << reason <<
"\n\n";
1765 oss << ((*_current_ray))->getInfo() <<
"\n";
1766 oss <<
"Current trace information\n";
1767 oss <<
" _current_subdomain_id = ";
1769 oss <<
"invalid subdomain id\n";
1772 oss <<
" _current_elem_type = " << Utility::enum_to_string(
_current_elem_type) <<
"\n";
1774 oss <<
" _incoming_point = ";
1776 oss <<
"invalid point\n";
1779 oss <<
" _incoming_side = ";
1781 oss <<
"invalid side\n";
1784 oss <<
" _intersection_point = ";
1786 oss <<
"invalid point\n";
1789 oss <<
" _intersected_side = ";
1791 oss <<
"invalid side\n";
1799 oss <<
"_current_elem = invalid\n";
1801 possiblySaveDebugRayMesh();
1814 (*_current_ray)->setShouldContinue(
false);
1821 const std::vector<NeighborInfo> &
1824 traceAssert(elem,
"Elem must be valid");
1825 traceAssert(vertex,
"Vertex must be valid");
1827 debugRay(
"Called getVertexNeighbors() with:");
1828 debugRay(
" elem->id() = ", elem->
id(),
" with centroid ", elem->
vertex_average());
1829 debugRay(
" vertex->id() = ", vertex->
id(),
", at ", (
Point)*vertex);
1839 return search->second;
1844 debugRay(
"Building vertex neighbors");
1845 std::vector<NeighborInfo> & entry =
1857 for (
auto & neighbor_info : entry)
1858 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
1859 neighbor_info._side_normals[i] =
1865 const std::vector<NeighborInfo> &
1868 traceAssert(vertex < elem->n_vertices(),
"Invalid vertex");
1873 const std::vector<NeighborInfo> &
1875 const std::pair<const Node *, const Node *> & vertices,
1876 const Point & point)
1878 traceAssert(elem,
"Invalid elem");
1879 traceAssert(vertices.first,
"Must be valid");
1880 traceAssert(vertices.second,
"Must be valid");
1882 debugRay(
"Called getEdgeNeighbors() with:");
1883 debugRay(
" elem->id() = ", elem->
id(),
" with centroid ", elem->
vertex_average());
1884 debugRay(
" vertices.first = ", vertices.first->id(),
" at ", (
Point)*vertices.first);
1885 debugRay(
" vertices.second = ", vertices.second->id(),
" at ", (
Point)*vertices.second);
1886 debugRay(
" point = ", point);
1889 "Doesn't contain vertex");
1891 "Doesn't contain vertex");
1894 "Point not within edge");
1898 const auto ordered_vertices = vertices.first->id() < vertices.second->id()
1900 : std::make_pair(vertices.second, vertices.first);
1903 std::pair<bool, std::vector<NeighborInfo>> * entry;
1906 entry = &search->second;
1909 debugRay(
"Building edge neighbors");
1912 .emplace(ordered_vertices, std::make_pair(
true, std::vector<NeighborInfo>()))
1915 ordered_vertices.first,
1916 ordered_vertices.second,
1923 bool all_same_edge =
true;
1924 for (
auto & neighbor_info : entry->second)
1926 traceAssert(neighbor_info._lower_bound <= neighbor_info._upper_bound,
1927 "Bound order incorrect");
1930 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
1931 neighbor_info._side_normals[i] =
1935 if (neighbor_info._lower_bound != 0 || neighbor_info._upper_bound != 1)
1936 all_same_edge =
false;
1938 entry->first = all_same_edge;
1945 const auto edge_length =
1946 ((
Point)*ordered_vertices.first - (
Point)*ordered_vertices.second).
norm();
1947 const auto point_location = ((
Point)*ordered_vertices.first - point).norm() / edge_length;
1948 for (
auto &
info : entry->second)
1953 return entry->second;
1956 const std::vector<NeighborInfo> &
1958 const std::pair<unsigned short, unsigned short> & vertices,
1959 const Point & point)
1961 debugRay(
"Called getEdgeNeighbors(), local index version with:");
1962 debugRay(
" vertices.first = ", vertices.first);
1963 debugRay(
" vertices.second = ", vertices.second);
1964 traceAssert(vertices.first < elem->
n_vertices(),
1965 "Invalid vertex with ray " + std::to_string((*_current_ray)->id()));
1966 traceAssert(vertices.second < elem->
n_vertices(),
"Invalid vertex");
1969 elem, std::make_pair(elem->
node_ptr(vertices.first), elem->
node_ptr(vertices.second)), point);
1972 const std::vector<NeighborInfo> &
1982 const std::vector<NeighborInfo> &
1985 traceAssert(elem,
"Invalid elem");
1987 debugRay(
"Called getPointNeighbors()");
1988 debugRay(
" elem = ", elem->
id());
1989 debugRay(
" point = ", point);
2004 for (MooseIndex(neighbor_info._sides.size()) i = 0; i < neighbor_info._sides.size(); ++i)
2005 neighbor_info._side_normals[i] =
2021 mooseError(
"Should not call storeExitsElemResult() with result ", result);
2027 traceAssert((*_current_ray)->currentElem() ==
_current_elem,
"Ray currentElem() incorrect");
2029 "Ray currentPoint() incorrect");
2030 traceAssert((*_current_ray)->currentIncomingSide() ==
_incoming_side,
2031 "Ray currentIncomingSide() incorrect");
2037 "_current_elem does not contain incoming point");
2044 "Intersected point is not on intersected side");
2047 "Intersected side is not outgoing");
2054 "Incoming point is not on incoming side");
2055 if (ray->intersections() != 0 && ray->maxDistance() != 0)
2058 "Incoming side is not incoming");
2064 "_intersection_distance is incorrect");
2068 "Invalid intersection distance");
2074 for (
auto & rk : rks)
2085 "Ray currentPoint() not set before onBoundary()");
2138 if (external && !ray->trajectoryChanged() && ray->shouldContinue())
2140 std::stringstream oss;
2141 oss <<
"Don't know what to do with a Ray after it hit an external\n";
2143 oss <<
"When hitting an external RayBC, a Ray must either:\n";
2144 oss <<
" Be killed by a RayBC\n";
2145 oss <<
" Have its trajectory changed by the RayBC\n";
2146 oss <<
"by at least one of the executed RayBCs.\n\n";
2147 oss <<
"You need to either:\n";
2148 oss <<
" Kill/change the Ray sooner with RayKernels, internal RayBCs, or a max distance\n";
2149 oss <<
" Kill/change the Ray on the boundary with a RayBC\n\n";
2152 oss <<
"RayBCs executed that did not kill or change the Ray:\n";
2155 if (rbc->hasBoundary(bnd_elem.bnd_id))
2156 oss <<
" " << rbc->typeAndName() <<
" on boundary " << bnd_elem.bnd_id <<
" (" 2160 bool output_header =
false;
2166 if (rbc->hasBoundary(bnd_id))
2176 oss <<
"Boundaries that did not have any RayBCs:\n";
2177 output_header =
true;
2198 if (!ray->shouldContinue())
2205 " set a Ray to continue that was previously set to not continue.\n\n" +
2206 "Once a Ray has been set to not continue, its continue status cannot change.",
2212 " changed the trajectory of a Ray that was set to not continue,\n" +
2213 "or set a Ray whose trajectory was changed to not continue.",
bool hasRayKernels(const THREAD_ID tid)
Whether or not there are currently any active RayKernel objects.
const std::vector< NeighborInfo > & getPointNeighbors(const Elem *elem, const Point &point)
Get the point neighbors.
static const unsigned short invalid_side
Identifier for an invalid side index.
TracePointData & lastPoint()
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.
RayTracingStudy & _study
The RayTracingStudy.
virtual void postOnSegment(const THREAD_ID tid, const std::shared_ptr< Ray > &ray)
Called at the end of a Ray segment.
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.
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< std::pair< const Node *, const Node * >, std::pair< bool, std::vector< NeighborInfo > > > _edge_neighbors
The cached edge neighbors.
unsigned short vertex() const
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. ...
ElemExtrema _intersected_extrema
The work point for the intersected vertex/edge vertices of the current Ray, if any.
void onTrajectoryChanged(const std::shared_ptr< Ray > &ray)
Called when a Ray's trajectory changes.
bool segmentsOnCacheTraces() const
Whether or not to cache individual element segments when _cache_traces = true.
static const unsigned short invalid_vertex
Identifier for an invalid vertex index.
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...
void applyOnExternalBoundary(const std::shared_ptr< Ray > &ray)
Gets and applies external boundary conditions in _current_elem on side _intersected_side at _intersec...
bool hasSameLevelActiveElems() const
Whether or not the mesh has active elements of the same level.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
std::vector< std::size_t > _on_boundary_apply_index
Reusable for which boundary elements to apply for a specific RayBC in onBoundary() ...
const unsigned int invalid_uint
unsigned int get_node_index(const Node *node_ptr) const
std::string get_info() const
libMesh::ElemType _current_elem_type
The current elem type (constant on subdomain), used to avoid elem->type() calls.
T & getMesh(MooseMesh &mesh)
function to cast mesh
void onSegment(const std::shared_ptr< Ray > &ray)
Called on a single segment traced by a Ray.
void skip_partitioning(bool skip)
std::string failTraceMessage(const std::string &reason, const int line=-1)
Creates a useful error string with current tracing information.
void mooseError(Args &&... args)
void onContinueTrace(const std::shared_ptr< Ray > &)
Called when a Ray is continuing to trace after segment.
unsigned int _debug_node_count
void onSubdomainChanged(const std::shared_ptr< Ray > &ray, const bool same_ray)
Called when the subdomain changes.
void mooseWarning(Args &&... args)
virtual bool has_affine_map() const
Base class for a MooseObject used in ray tracing.
MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > _neighbor_set
const std::string & getBoundaryName(BoundaryID boundary_id)
bool _valid
Whether or not this neighbor is valid (needed for neighbors that span an edge)
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...
Base object for the RayKernel syntax.
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.
Helper for defining if at an element's edge, vertex, or neither.
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const=0
const std::vector< RayKernelBase * > & currentRayKernels(THREAD_ID tid) const
Gets the current RayKernels for a thread, which are set in segmentSubdomainSetup() ...
Parallel::Communicator _debug_comm
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
Real rayMaxDistance() const
Max distance any Ray can travel.
Struct for containing the necessary information about a cached neighbor for ray tracing.
static const libMesh::Real invalid_distance
Identifier for an invalid distance.
bool isValid(const Elem *const elem, const Point &point) const
ElemExtrema _last_intersected_extrema
The intersected vertex/edge vertices for the previous intersection, if any.
const unsigned int _dim
The mesh dimension.
void postRayTracingObject(const std::shared_ptr< Ray > &ray, const RayTracingObject *rto)
Called after executing a RayTracingObject (RayBCs and RayKernels)
bool _backface_culling
Whether or not to use element normals for backface culling.
std::vector< RayData > _aux_data
The aux data on the Ray after this segment is traced (optional)
const BoundingBox & boundingBox() const
Get the nodal bounding box for the domain.
void onBoundary(const std::shared_ptr< Ray > &ray, const bool external)
Called when a Ray hits a boundary.
Real subdomainHmax(const SubdomainID subdomain_id) const
Get the cached hmax for all elements in a subdomain.
void trace(const std::shared_ptr< Ray > &ray)
Traces a ray.
const std::vector< unsigned short > _sides
The sides on the element that the neighboring portion is contained in.
bool isRectangularDomain() const
Whether or not the domain is rectangular (if it is prefectly encompassed by its bounding box) ...
libMesh::ElemSideBuilder _elem_side_builder
Helper for building element sides without excessive allocation.
const std::pair< unsigned short, unsigned short > & edgeVertices() const
Point _incoming_point
The incoming point of the current Ray.
const Point * _current_normals
The normals for the current element for backface culling (pointer to the first normal - optional) ...
bool _exits_elem
Whether or not the current trace exits an element.
bool verifyTraceIntersections() const
Whether or not trace verification is enabled in devel/dbg modes.
unsigned short _incoming_side
The incoming side of the current Ray.
bool verifyRays() const
Whether or not to verify if Rays have valid information before being traced.
std::vector< BoundaryID > _boundary_ids
Reusable vector for calling _boundary_info.boundary_ids()
Real subdomainHmax(const Elem *elem) const
Get the approximate subdomain hmax for an element.
std::vector< Point > _side_normals
The normals of each side in _sides.
std::set< RayKernelBase * > _old_ray_kernels
Helper for avoiding calling preTrace() on the same RayKernel multiple times.
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
bool auxDataOnCacheTraces() const
Whether or not to store the Ray aux data on the cached Ray traces.
unsigned int which_neighbor_am_i(const Elem *e) const
const processor_id_type _pid
The processor id.
void preExecute()
Should be called immediately before calling any traces.
const Elem *const _elem
The element.
MooseMesh & _mesh
The MooseMesh.
bool _has_ray_kernels
Whether or not the RayTracingStudy has any RayKernels.
std::vector< unsigned long long int > _results
Results over all of the local traces, indexed by TraceRayResult.
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 Elem * _last_elem
The last element the current Ray was traced in.
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)
bool rayDependentSubdomainSetup() const
Whether or not to use Ray dependent subdomain setup.
TraceData * _current_cached_trace
The TraceData for the current cached trace (if any)
OStreamProxy err(std::cerr)
void onCompleteTrace(const std::shared_ptr< Ray > &ray)
Called when a Ray is finished tracing (whenever !ray->shouldContinue())
std::string typeAndName() const
TraceRay(RayTracingStudy &study, const THREAD_ID tid)
bool absolute_fuzzy_equals(const TypeVector< Real > &rhs, Real tol=TOLERANCE) const
std::vector< const Elem * > _neighbor_active_neighbor_children
bool sideIsNonPlanar(const Elem *elem, const unsigned short s) const
Whether or not the side on elem elem is non-planar.
std::vector< RayBoundaryConditionBase * > _on_boundary_ray_bcs
Reusable for getting the RayBCs in onBoundary()
const std::shared_ptr< Ray > * _current_ray
The current ray being traced.
void addPoint(const libMesh::Point &point)
virtual const Point * getElemNormals(const Elem *, const THREAD_ID)
Gets the outward normals for a given element.
const Elem * _current_elem
The element the current Ray is being traced in.
bool _is_rectangular_domain
Whether or not the domain is rectangular (defined perfectly by its bounding box)
virtual unsigned int n_sides() const=0
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.
const Elem * neighbor_ptr(unsigned int i) const
virtual const Point & getSideNormal(const Elem *elem, const unsigned short side, const THREAD_ID tid)
Get the outward normal for a given element side.
void setVertex(const unsigned short vertex)
Sets the "at vertex" state.
virtual bool close_to_point(const Point &p, Real tol) const
const std::vector< NeighborInfo > & getNeighbors(const Elem *elem, const ElemExtrema &extrema, const Point &point)
Get the point/vertex/edge neighbors depending on extrema.
virtual unsigned int n_vertices() const=0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
bool currentlyPropagating() const
Whether or not the study is propagating (tracing Rays)
subdomain_id_type subdomain_id() const
std::vector< TraceRayBndElement > _boundary_elems
Boundary elements that need RayBCs to be applied.
static const std::string message
void invalidate()
Invalidates the current state.
virtual unsigned short dim() const=0
const Node * node_ptr(const unsigned int i) const
void getRayBCs(std::vector< RayBoundaryConditionBase *> &result, BoundaryID id, THREAD_ID tid)
Fills the active RayBCs associated with this study and a boundary into result.
virtual void preTrace(const THREAD_ID, const std::shared_ptr< Ray > &)
Called at the beginning of a trace for a ray.
const THREAD_ID _tid
The thread id.
virtual bool is_vertex(const unsigned int i) const=0
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.
void applyOnInternalBoundary(const std::shared_ptr< Ray > &ray)
Gets and applies internal boundary conditions (if any) from _current_elem, _last_elem, and any other point neighbors that have internal sidesets at _intersection_point.
std::vector< RayData > _data
The data on the Ray after this segment is traced (optional)
MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > _neighbor_next_untested_set
std::unordered_map< const Node *, std::vector< NeighborInfo > > _vertex_neighbors
The cached vertex neighbors.
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...
MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > _neighbor_untested_set
Real _current_subdomain_hmax
The current subdomain hmax.
ExitsElemResult
Enum for the different exit results for exitElem()
unsigned short _intersected_side
The work point for the intersected side of the current Ray.
static const libMesh::Point invalid_point(invalid_distance, invalid_distance, invalid_distance)
Identifier for an invalid point.
SubdomainID _current_subdomain_id
The current SubdomainID.
bool _last
Whether or not this was the last set of segments for this Ray.
bool tolerateFailure() const
Whether or not to tolerate failure.
const BoundaryInfo & _boundary_info
The BoundaryInfo for the mesh.
BoundaryID _current_bnd_id
The current BoundaryID (used when calling RayBoundaryConditionBase::onBoundary()) ...
const std::vector< NeighborInfo > & getVertexNeighbors(const Elem *elem, const Node *vertex)
Gets the neighbors at a vertex.
Base class for the RayBC syntax.
void continueTraceOffProcessor(const std::shared_ptr< Ray > &ray)
Sets up a ray to continue tracing off processor.
Real _intersection_distance
The work point for the intersection distance of the current Ray.
processor_id_type processor_id() const
bool dataOnCacheTraces() const
Whether or not to store the Ray data on the cached Ray traces.
virtual ElemType type() const=0
void meshChanged()
Called on mesh change.
const Point & point(const unsigned int i) const
std::vector< NeighborInfo > _point_neighbor_helper
Reusable for building neighbors.
void storeExitsElemResult(const ExitsElemResult result)
Stores the result given by an intersection in _results as necessary.
bool _should_continue
Whether or not the current Ray should continue.
Point vertex_average() const
Real domainMaxLength() const
Get the inflated maximum length across the domain.
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.
bool hasInternalSidesets() const
Whether or not the local mesh has internal sidesets that have RayBCs on them.
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...
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)...
Point _intersection_point
The work point for the intersection of the current Ray.