17#include "libmesh/cell_hex8.h"
18#include "libmesh/cell_hex20.h"
19#include "libmesh/cell_hex27.h"
20#include "libmesh/cell_prism6.h"
21#include "libmesh/cell_prism15.h"
22#include "libmesh/cell_prism18.h"
23#include "libmesh/cell_pyramid5.h"
24#include "libmesh/cell_pyramid13.h"
25#include "libmesh/cell_pyramid14.h"
26#include "libmesh/cell_tet4.h"
27#include "libmesh/cell_tet10.h"
28#include "libmesh/cell_tet14.h"
29#include "libmesh/edge_edge2.h"
30#include "libmesh/enum_to_string.h"
31#include "libmesh/face_quad4.h"
32#include "libmesh/face_tri3.h"
33#include "libmesh/mesh.h"
34#include "libmesh/remote_elem.h"
35#include "libmesh/tensor_value.h"
41 HEX8, HEX20, HEX27, QUAD4, QUAD8, QUAD9, TET4, TET10, TET14, TRI3, TRI6,
42 TRI7, EDGE2, EDGE3, EDGE4, PYRAMID5, PYRAMID13, PYRAMID14, PRISM6, PRISM15, PRISM18};
47 const Point & direction,
51 Point & intersection_point,
52 Real & intersection_distance,
54#ifdef DEBUG_RAY_INTERSECTIONS
63 debugRaySimple(
"Called lineLineIntersect2D()");
64 debugRaySimple(
" start = ", start);
65 debugRaySimple(
" direction = ", direction);
66 debugRaySimple(
" length = ", length);
67 debugRaySimple(
" v0 = ", v0);
68 debugRaySimple(
" v1 = ", v1);
70 const auto r = direction * length;
71 const auto s = v1 - v0;
73 const auto rxs = r(0) * s(1) - r(1) * s(0);
74 debugRaySimple(
" rxs = ", rxs);
80 const auto v0mu0 = v0 - start;
82 const auto t = (v0mu0(0) * s(1) - v0mu0(1) * s(0)) / rxs;
83 debugRaySimple(
" t = ", t);
86 debugRaySimple(
"lineLineIntersect2D did not intersect: t out of range");
90 const auto u = (v0mu0(0) * r(1) - v0mu0(1) * r(0)) / rxs;
91 debugRaySimple(
" u = ", u);
94 intersection_point = start + r * t;
95 intersection_distance = t * length;
102 debugRaySimple(
"lineLineIntersect2D intersected with:");
103 debugRaySimple(
" intersection_distance = ", intersection_point);
104 debugRaySimple(
" intersection_distance = ", intersection_distance);
105 debugRaySimple(
" segment_vertex = ", Utility::enum_to_string(segment_vertex));
111 debugRaySimple(
"lineLineIntersect2d() did not intersect: u out of range");
117 const Elem *
const elem,
122 std::vector<const Elem *> active_neighbor_children,
123 std::vector<NeighborInfo> & info)
125 mooseAssert(elem->contains_point(point),
"Doesn't contain point");
130 std::unique_ptr<const Elem> side_helper;
132 auto contains_point = [&point, &info, &side_helper, &elem](
const Elem *
const candidate)
134 if (candidate->contains_point(point))
136 std::vector<unsigned short>
sides;
137 for (
const auto s : candidate->side_index_range())
139 candidate->build_side_ptr(side_helper, s);
140 if (side_helper->contains_point(point))
145 if (!
sides.empty() && candidate != elem)
147 info.emplace_back(candidate, std::move(
sides));
156 contains_point(elem);
162 active_neighbor_children,
168 std::set<const Elem *> point_neighbors;
169 elem->find_point_neighbors(point, point_neighbors);
170 for (
const auto & point_neighbor : point_neighbors)
171 if (!neighbor_set.
contains(point_neighbor) && point_neighbor != elem)
178 const Elem *
const elem,
179 const Node *
const node,
183 std::vector<const Elem *> active_neighbor_children,
184 std::vector<NeighborInfo> & info)
191 std::unique_ptr<const Elem> side_helper;
193 auto contains_node = [&node, &elem, &info, &side_helper](
const Elem *
const candidate)
196 const auto n = candidate->get_node_index(node);
197 if (n != invalid_uint && candidate->is_vertex(n))
199 std::vector<unsigned short>
sides;
200 for (
const auto s : candidate->side_index_range())
201 if (candidate->is_node_on_side(n, s))
205 mooseError(
"Failed to find a side containing node");
207 info.emplace_back(candidate, std::move(
sides));
212 if (candidate->level() < elem->level() && candidate->contains_point(*node))
214 std::vector<unsigned short>
sides;
215 for (
const auto s : candidate->side_index_range())
217 candidate->build_side_ptr(side_helper, s);
218 if (side_helper->contains_point(*node))
224 info.emplace_back(candidate, std::move(
sides));
236 elem, neighbor_set, untested_set, next_untested_set, active_neighbor_children, contains_node);
241 std::set<const Elem *> point_neighbors;
242 elem->find_point_neighbors(*node, point_neighbors);
243 for (
const auto & point_neighbor : point_neighbors)
244 for (
const auto & neighbor_node : point_neighbor->node_ref_range())
245 if (node == &neighbor_node && !neighbor_set.
contains(point_neighbor) &&
246 point_neighbor != elem)
253 const Elem *
const elem,
254 const Node *
const node1,
255 const Node *
const node2,
259 std::vector<const Elem *> active_neighbor_children,
260 std::vector<NeighborInfo> & info)
268 const Real edge_length = ((Point)*node1 - (Point)*node2).norm();
272 auto within_edge = [&elem, &node1, &node2, &edge_length, &info](
const Elem *
const candidate)
274 switch (candidate->type())
277 return findEdgeNeighborsWithinEdgeInternal<Hex8>(
278 candidate, elem, node1, node2, edge_length, info);
280 return findEdgeNeighborsWithinEdgeInternal<Tet4>(
281 candidate, elem, node1, node2, edge_length, info);
283 return findEdgeNeighborsWithinEdgeInternal<Pyramid5>(
284 candidate, elem, node1, node2, edge_length, info);
286 return findEdgeNeighborsWithinEdgeInternal<Prism6>(
287 candidate, elem, node1, node2, edge_length, info);
289 return findEdgeNeighborsWithinEdgeInternal<Hex20>(
290 candidate, elem, node1, node2, edge_length, info);
292 return findEdgeNeighborsWithinEdgeInternal<Hex27>(
293 candidate, elem, node1, node2, edge_length, info);
295 return findEdgeNeighborsWithinEdgeInternal<Tet10>(
296 candidate, elem, node1, node2, edge_length, info);
298 return findEdgeNeighborsWithinEdgeInternal<Tet14>(
299 candidate, elem, node1, node2, edge_length, info);
301 return findEdgeNeighborsWithinEdgeInternal<Pyramid13>(
302 candidate, elem, node1, node2, edge_length, info);
304 return findEdgeNeighborsWithinEdgeInternal<Pyramid14>(
305 candidate, elem, node1, node2, edge_length, info);
307 return findEdgeNeighborsWithinEdgeInternal<Prism15>(
308 candidate, elem, node1, node2, edge_length, info);
310 return findEdgeNeighborsWithinEdgeInternal<Prism18>(
311 candidate, elem, node1, node2, edge_length, info);
314 Utility::enum_to_string(candidate->type()),
315 " not supported in TraceRayTools::findEdgeNeighbors()");
323 elem, neighbor_set, untested_set, next_untested_set, active_neighbor_children, within_edge);
329 mooseAssert(!elem->active(),
"Should be inactive");
330 mooseAssert(elem->side_ptr(side)->contains_point(point),
"Side should contain point");
332 for (
unsigned int c = 0;
c < elem->n_children(); ++
c)
334 if (!elem->is_child_on_side(
c, side))
337 const auto child = elem->child_ptr(
c);
340 if (child->close_to_point(point, 5.e-5))
349 mooseError(
"Failed to find child containing point on side");
355 const auto neighbor = elem->neighbor_ptr(side);
356 if (!neighbor || neighbor->active())
360 const auto neighbor_side = neighbor->which_neighbor_am_i(elem);
366 const Point & direction,
367 const Elem *
const elem,
368 const unsigned short v0,
369 const unsigned short v1,
370 const unsigned short v2,
371 Real & intersection_distance,
374#ifdef DEBUG_RAY_INTERSECTIONS
380 debugRaySimple(
"intersectTriangle() called:");
381 debugRaySimple(
" start = ", start);
382 debugRaySimple(
" direction = ", direction);
383 debugRaySimple(
" elem->id() = ", elem->id());
384 debugRaySimple(
" v0 = ", v0,
" at ", elem->point(v0));
385 debugRaySimple(
" v1 = ", v1,
" at ", elem->point(v1));
386 debugRaySimple(
" v2 = ", v2,
" at ", elem->point(v2));
387 debugRaySimple(
" hmax = ", hmax);
388 mooseAssert(elem->is_vertex(v0),
"Not a vertex");
389 mooseAssert(elem->is_vertex(v1),
"Not a vertex");
390 mooseAssert(elem->is_vertex(v2),
"Not a vertex");
395 const auto inv_hmax = 1.0 / hmax;
397 const auto & v0_point = elem->point(v0);
399 const auto edge1 = (elem->point(v1) - v0_point) * inv_hmax;
400 const auto edge2 = (elem->point(v2) - v0_point) * inv_hmax;
402 const auto pvec = direction.cross(edge2);
404 auto det = edge1 * pvec;
405 debugRaySimple(
" det = ", det);
408 debugRaySimple(
"intersectTriangle() did not intersect: det < tol");
412 const auto tvec = (start - v0_point) * inv_hmax;
413 const auto u = tvec * pvec;
414 debugRaySimple(
" u = ", u);
415 debugRaySimple(
" u / det = ", u / det);
418 debugRaySimple(
"intersectTriangle() did not intersect: u out of range");
422 const auto qvec = tvec.cross(edge1);
423 const auto v = direction * qvec;
424 debugRaySimple(
" v = ",
v);
425 debugRaySimple(
" v / det = ",
v / det);
426 debugRaySimple(
" (u + v) / det = ", (u +
v) / det);
429 debugRaySimple(
"intersectTriangle() did not intersect: v out of range");
433 const auto possible_distance = (edge2 * qvec) / det;
434 debugRaySimple(
" possible_distance = ", possible_distance);
437 debugRaySimple(
"intersectTriangle() did not intersect: distance too small");
443 intersection_distance = possible_distance * hmax;
454 intersected_extrema.
setEdge(v0, v2);
461 intersected_extrema.
setEdge(v0, v1);
464 intersected_extrema.
setEdge(v1, v2);
466 debugRaySimple(
"intersectTriangle() intersected with:");
467 debugRaySimple(
" intersection_distance = ", intersection_distance);
468 debugRaySimple(
" intersected_extrema = ", intersected_extrema);
475 const Point & direction,
476 const Elem *
const elem,
477 const unsigned short v00,
478 const unsigned short v10,
479 const unsigned short v11,
480 const unsigned short v01,
481 Real & intersection_distance,
484#ifdef DEBUG_RAY_INTERSECTIONS
490 mooseAssert(intersected_extrema.
isInvalid(),
"Should be invalid");
491 debugRaySimple(
"intersectQuad() called:");
492 debugRaySimple(
" start = ", start);
493 debugRaySimple(
" direction = ", direction);
494 debugRaySimple(
" elem->id() = ", elem->id());
495 debugRaySimple(
" v00 = ", v00,
" at ", elem->point(v00));
496 debugRaySimple(
" v10 = ", v10,
" at ", elem->point(v10));
497 debugRaySimple(
" v11 = ", v11,
" at ", elem->point(v11));
498 debugRaySimple(
" v01 = ", v01,
" at ", elem->point(v01));
514 intersection_distance,
517#ifdef DEBUG_RAY_INTERSECTIONS
530 intersection_distance,
533#ifdef DEBUG_RAY_INTERSECTIONS
542 if (intersects && intersected_extrema.
atEdge(v00, v11))
563 for (
unsigned int v = 0;
v < elem->n_vertices(); ++
v)
575 const Real tolerance )
577 mooseAssert(extrema.
isInvalid(),
"Should be invalid");
579 for (
int e = 0; e < T::num_edges; ++e)
581 elem->point(T::edge_nodes_map[e][1]),
585 extrema.
setEdge(T::edge_nodes_map[e][0], T::edge_nodes_map[e][1]);
596 const Real tolerance )
598 switch (elem->type())
603 return withinEdgeTempl<Hex8>(elem, point, extrema, tolerance);
607 return withinEdgeTempl<Tet4>(elem, point, extrema, tolerance);
611 return withinEdgeTempl<Pyramid5>(elem, point, extrema, tolerance);
615 return withinEdgeTempl<Prism6>(elem, point, extrema, tolerance);
618 Utility::enum_to_string(elem->type()),
619 " not supported in TraceRayTools::withinEdge()");
628 switch (elem->type())
633 return atVertexOnSideTempl<Hex8>(elem, point, side);
637 return atVertexOnSideTempl<Quad4>(elem, point, side);
641 return atVertexOnSideTempl<Tri3>(elem, point, side);
645 return atVertexOnSideTempl<Tet4>(elem, point, side);
649 return atVertexOnSideTempl<Pyramid5>(elem, point, side);
653 return atVertexOnSideTempl<Prism6>(elem, point, side);
657 return atVertexOnSideTempl<Edge2>(elem, point, side);
660 Utility::enum_to_string(elem->type()),
661 " not supported in TraceRayTools::atVertexOnSide()");
668typename std::enable_if<!std::is_base_of<Edge, T>::value,
unsigned short>::type
671 mooseAssert(side < elem->n_sides(),
"Invalid side");
673 "Side does not contain point");
675 for (
int i = 0; i < nodesPerSide<T>(side); ++i)
676 if (elem->point(T::side_nodes_map[side][i]).absolute_fuzzy_equals(point,
TRACE_TOLERANCE))
677 return T::side_nodes_map[side][i];
683typename std::enable_if<std::is_base_of<Edge, T>::value,
unsigned short>::type
686 mooseAssert(side < elem->n_sides(),
"Invalid side");
688 "Side does not contain point");
699 const unsigned short side,
702 switch (elem->type())
707 return withinEdgeOnSideTempl<Hex8>(elem, point, side, extrema);
711 return withinEdgeOnSideTempl<Tet4>(elem, point, side, extrema);
715 return withinEdgeOnSideTempl<Pyramid5>(elem, point, side, extrema);
719 return withinEdgeOnSideTempl<Prism6>(elem, point, side, extrema);
722 Utility::enum_to_string(elem->type()),
723 " not supported in TraceRayTools::withinEdgeOnSide()");
730typename std::enable_if<std::is_base_of<libMesh::Cell, T>::value,
bool>::type
733 const unsigned short side,
736 mooseAssert(side < elem->n_sides(),
"Invalid side");
738 "Side does not contain point");
739 mooseAssert(extrema.
isInvalid(),
"Should be invalid");
741 int last_n = T::side_nodes_map[side][nodesPerSide<T>(side) - 1];
743 for (
int side_v = 0; side_v < nodesPerSide<T>(side); ++side_v)
744 if (
isWithinSegment(elem->point(last_n), elem->point(T::side_nodes_map[side][side_v]), point))
746 extrema.
setEdge(last_n, T::side_nodes_map[side][side_v]);
748 "Edge doesn't contain point");
752 last_n = T::side_nodes_map[side][side_v];
760 const unsigned short side,
761 const unsigned int dim,
764 mooseAssert(extrema.
isInvalid(),
"Extrema should be invalid");
765 mooseAssert(
dim == elem->dim(),
"Incorrect dim");
778 const Point & segment2,
780 const Real tolerance )
782 mooseAssert(!segment1.absolute_fuzzy_equals(segment2,
TRACE_TOLERANCE),
"Same endpoints");
784 const auto segment_length = (segment1 - segment2).norm();
785 return isWithinSegment(segment1, segment2, segment_length, point, tolerance);
790 const Point & segment2,
791 const Real segment_length,
793 const Real tolerance )
795 mooseAssert(!segment1.absolute_fuzzy_equals(segment2,
TRACE_TOLERANCE),
"Same endpoints");
796 mooseAssert(MooseUtils::absoluteFuzzyEqual((segment1 - segment2).norm(), segment_length),
797 "Invalid segment length");
799 const auto diff1 = point - segment1;
800 const auto diff2 = point - segment2;
802 if (diff1 * diff2 > tolerance * segment_length)
805 return std::abs(diff1.norm() + diff2.norm() - segment_length) < tolerance * segment_length;
811 const unsigned int dim,
812 const Real tolerance)
814 for (
unsigned int d = 0;
d <
dim; ++
d)
815 if (MooseUtils::absoluteFuzzyEqual(point(
d), bbox.min()(
d), tolerance) ||
816 MooseUtils::absoluteFuzzyEqual(point(
d), bbox.max()(
d), tolerance))
void mooseError(Args &&... args)
bool contains(const T &value) const
static const unsigned short invalid_vertex
Identifier for an invalid vertex index.
const unsigned int invalid_uint
Helper for defining if at an element's edge, vertex, or neither.
std::unique_ptr< const libMesh::Elem > buildEdge(const Elem *elem) const
void invalidate()
Invalidates the current state.
void setVertex(const unsigned short vertex)
Sets the "at vertex" state.
void setEdge(const unsigned short v1, const unsigned short v2)
Sets the "at edge" state.