https://mooseframework.inl.gov
Loading...
Searching...
No Matches
TraceRayTools.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "TraceRayTools.h"
11
12// MOOSE includes
13#include "MooseTypes.h"
14#include "MooseUtils.h"
15
16// libMesh includes
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"
36
37using namespace libMesh;
38
39namespace TraceRayTools
40{
41
46
47bool
49 const Point & direction,
50 const Real length,
51 const Point & v0,
52 const Point & v1,
53 Point & intersection_point,
54 Real & intersection_distance,
55 SegmentVertices & segment_vertex
56#ifdef DEBUG_RAY_INTERSECTIONS
57 ,
58 const bool debug
59#endif
60)
61
62{
63 // TODO: consider using hmax scaling here
64 mooseAssert(segment_vertex == SEGMENT_VERTEX_NONE, "Vertex should be none");
65 debugRaySimple("Called lineLineIntersect2D()");
66 debugRaySimple(" start = ", start);
67 debugRaySimple(" direction = ", direction);
68 debugRaySimple(" length = ", length);
69 debugRaySimple(" v0 = ", v0);
70 debugRaySimple(" v1 = ", v1);
71
72 const auto r = direction * length;
73 const auto s = v1 - v0;
74
75 const auto rxs = r(0) * s(1) - r(1) * s(0);
76 debugRaySimple(" rxs = ", rxs);
77
78 // Lines are parallel or colinear
79 if (std::abs(rxs) < TRACE_TOLERANCE)
80 return false;
81
82 const auto v0mu0 = v0 - start;
83
84 const auto t = (v0mu0(0) * s(1) - v0mu0(1) * s(0)) / rxs;
85 debugRaySimple(" t = ", t);
86 if (0 >= t + TRACE_TOLERANCE || t - TRACE_TOLERANCE > 1.0)
87 {
88 debugRaySimple("lineLineIntersect2D did not intersect: t out of range");
89 return false;
90 }
91
92 const auto u = (v0mu0(0) * r(1) - v0mu0(1) * r(0)) / rxs;
93 debugRaySimple(" u = ", u);
94 if (0 < u + TRACE_TOLERANCE && u - TRACE_TOLERANCE <= 1.0)
95 {
96 intersection_point = start + r * t;
97 intersection_distance = t * length;
98
99 if (u < TRACE_TOLERANCE)
100 segment_vertex = SEGMENT_VERTEX_0;
101 else if (u > 1.0 - TRACE_TOLERANCE)
102 segment_vertex = SEGMENT_VERTEX_1;
103
104 debugRaySimple("lineLineIntersect2D intersected with:");
105 debugRaySimple(" intersection_distance = ", intersection_point);
106 debugRaySimple(" intersection_distance = ", intersection_distance);
107 debugRaySimple(" segment_vertex = ", Utility::enum_to_string(segment_vertex));
108
109 return true;
110 }
111
112 // Not parallel, but don't intersect
113 debugRaySimple("lineLineIntersect2d() did not intersect: u out of range");
114 return false;
115}
116
117void
119 const Elem * const elem,
120 const Point & point,
124 std::vector<const Elem *> active_neighbor_children,
125 std::vector<NeighborInfo> & info)
126{
127 mooseAssert(elem->contains_point(point), "Doesn't contain point");
128
129 info.clear();
130
131 // Helper for avoiding extraneous allocation when building side elements
132 std::unique_ptr<const Elem> side_helper;
133
134 auto contains_point = [&point, &info, &side_helper, &elem](const Elem * const candidate)
135 {
136 if (candidate->contains_point(point))
137 {
138 std::vector<unsigned short> sides;
139 for (const auto s : candidate->side_index_range())
140 {
141 candidate->build_side_ptr(side_helper, s);
142 if (side_helper->contains_point(point))
143 sides.push_back(s);
144 }
145
146 // Dont add the local element
147 if (!sides.empty() && candidate != elem)
148 {
149 info.emplace_back(candidate, std::move(sides));
150 return true;
151 }
152 }
153
154 return false;
155 };
156
157 // Fill info for the element that was passed in
158 contains_point(elem);
159
160 findNeighbors(elem,
161 neighbor_set,
162 untested_set,
163 next_untested_set,
164 active_neighbor_children,
165 contains_point);
166
167#ifndef NDEBUG
168 // In non-opt modes, verify that we found all of the correct neighbors
169 // using the more expensive libMesh routine
170 std::set<const Elem *> point_neighbors;
171 elem->find_point_neighbors(point, point_neighbors);
172 for (const auto & point_neighbor : point_neighbors)
173 if (!neighbor_set.contains(point_neighbor) && point_neighbor != elem)
174 mooseError("Missed a point neighbor");
175#endif
176}
177
178void
180 const Elem * const elem,
181 const Node * const node,
185 std::vector<const Elem *> active_neighbor_children,
186 std::vector<NeighborInfo> & info)
187{
188 mooseAssert(elem->get_node_index(node) != libMesh::invalid_uint, "Doesn't contain node");
189
190 info.clear();
191
192 // Helper for avoiding extraneous allocations when building side elements
193 std::unique_ptr<const Elem> side_helper;
194
195 auto contains_node = [&node, &elem, &info, &side_helper](const Elem * const candidate)
196 {
197 // Candidate has this node and it is a vertex - add sides that contain said node
198 const auto n = candidate->get_node_index(node);
199 if (n != invalid_uint && candidate->is_vertex(n))
200 {
201 std::vector<unsigned short> sides;
202 for (const auto s : candidate->side_index_range())
203 if (candidate->is_node_on_side(n, s))
204 sides.push_back(s);
205
206 if (sides.empty())
207 mooseError("Failed to find a side containing node");
208
209 info.emplace_back(candidate, std::move(sides));
210 return true;
211 }
212 // In the case of a less refined candidate, the node can be a hanging node. The candidate
213 // will only ever have the hanging node if it is less refined.
214 if (candidate->level() < elem->level() && candidate->contains_point(*node))
215 {
216 std::vector<unsigned short> sides;
217 for (const auto s : candidate->side_index_range())
218 {
219 candidate->build_side_ptr(side_helper, s);
220 if (side_helper->contains_point(*node))
221 sides.push_back(s);
222 }
223
224 if (!sides.empty())
225 {
226 info.emplace_back(candidate, std::move(sides));
227 return true;
228 }
229 }
230
231 return false;
232 };
233
234 // Fill info for the element that was passed in
235 contains_node(elem);
236
238 elem, neighbor_set, untested_set, next_untested_set, active_neighbor_children, contains_node);
239
240#ifndef NDEBUG
241 // In non-opt modes, verify that we found all of the correct neighbors
242 // using the more expensive libMesh routine
243 std::set<const Elem *> point_neighbors;
244 elem->find_point_neighbors(*node, point_neighbors);
245 for (const auto & point_neighbor : point_neighbors)
246 for (const auto & neighbor_node : point_neighbor->node_ref_range())
247 if (node == &neighbor_node && !neighbor_set.contains(point_neighbor) &&
248 point_neighbor != elem)
249 mooseError("Missed a node neighbor");
250#endif
251}
252
253void
255 const Elem * const elem,
256 const Node * const node1,
257 const Node * const node2,
261 std::vector<const Elem *> active_neighbor_children,
262 std::vector<NeighborInfo> & info)
263{
264 mooseAssert(elem->get_node_index(node1) != libMesh::invalid_uint, "Doesn't contain node");
265 mooseAssert(elem->get_node_index(node2) != libMesh::invalid_uint, "Doesn't contain node");
266
267 info.clear();
268
269 // The length for this edge used for checking if a point is contained within said edge
270 const Real edge_length = ((Point)*node1 - (Point)*node2).norm();
271
272 // Lambda that returns whether or not a candidate element contains an edge that is within the
273 // target edge defined by node1 and node2. Also fills "info" if a match is found
274 auto within_edge = [&elem, &node1, &node2, &edge_length, &info](const Elem * const candidate)
275 {
276 switch (candidate->type())
277 {
278 case HEX8:
279 return findEdgeNeighborsWithinEdgeInternal<Hex8>(
280 candidate, elem, node1, node2, edge_length, info);
281 case TET4:
282 return findEdgeNeighborsWithinEdgeInternal<Tet4>(
283 candidate, elem, node1, node2, edge_length, info);
284 case PYRAMID5:
285 return findEdgeNeighborsWithinEdgeInternal<Pyramid5>(
286 candidate, elem, node1, node2, edge_length, info);
287 case PRISM6:
288 return findEdgeNeighborsWithinEdgeInternal<Prism6>(
289 candidate, elem, node1, node2, edge_length, info);
290 case HEX20:
291 return findEdgeNeighborsWithinEdgeInternal<Hex20>(
292 candidate, elem, node1, node2, edge_length, info);
293 case HEX27:
294 return findEdgeNeighborsWithinEdgeInternal<Hex27>(
295 candidate, elem, node1, node2, edge_length, info);
296 case TET10:
297 return findEdgeNeighborsWithinEdgeInternal<Tet10>(
298 candidate, elem, node1, node2, edge_length, info);
299 case TET14:
300 return findEdgeNeighborsWithinEdgeInternal<Tet14>(
301 candidate, elem, node1, node2, edge_length, info);
302 case PYRAMID13:
303 return findEdgeNeighborsWithinEdgeInternal<Pyramid13>(
304 candidate, elem, node1, node2, edge_length, info);
305 case PYRAMID14:
306 return findEdgeNeighborsWithinEdgeInternal<Pyramid14>(
307 candidate, elem, node1, node2, edge_length, info);
308 case PRISM15:
309 return findEdgeNeighborsWithinEdgeInternal<Prism15>(
310 candidate, elem, node1, node2, edge_length, info);
311 case PRISM18:
312 return findEdgeNeighborsWithinEdgeInternal<Prism18>(
313 candidate, elem, node1, node2, edge_length, info);
314 default:
315 mooseError("Element type ",
316 Utility::enum_to_string(candidate->type()),
317 " not supported in TraceRayTools::findEdgeNeighbors()");
318 }
319 };
320
321 // Fill info for the element that was passed in
322 within_edge(elem);
323
325 elem, neighbor_set, untested_set, next_untested_set, active_neighbor_children, within_edge);
326}
327
328const Elem *
329childContainingPointOnSide(const Elem * elem, const Point & point, const unsigned short side)
330{
331 mooseAssert(!elem->active(), "Should be inactive");
332 mooseAssert(elem->side_ptr(side)->contains_point(point), "Side should contain point");
333
334 for (unsigned int c = 0; c < elem->n_children(); ++c)
335 {
336 if (!elem->is_child_on_side(c, side))
337 continue;
338
339 const auto child = elem->child_ptr(c);
340 // Experience shows that we need to loosen this tolerance just a little
341 // The default is libMesh::TOLERANCE = 1e-6
342 if (child->close_to_point(point, 5.e-5))
343 {
344 if (child->active())
345 return child;
346 else
347 return childContainingPointOnSide(child, point, side);
348 }
349 }
350
351 mooseError("Failed to find child containing point on side");
352}
353
354const Elem *
355getActiveNeighbor(const Elem * elem, const unsigned short side, const Point & point)
356{
357 const auto neighbor = elem->neighbor_ptr(side);
358 if (!neighbor || neighbor->active())
359 return neighbor;
360
361 // There is adaptivity... need to find the active child that contains the point
362 const auto neighbor_side = neighbor->which_neighbor_am_i(elem);
363 return childContainingPointOnSide(neighbor, point, neighbor_side);
364}
365
366bool
368 const Point & direction,
369 const Elem * const elem,
370 const unsigned short v0,
371 const unsigned short v1,
372 const unsigned short v2,
373 Real & intersection_distance,
374 ElemExtrema & intersected_extrema,
375 const Real hmax
376#ifdef DEBUG_RAY_INTERSECTIONS
377 ,
378 const bool debug
379#endif
380)
381{
382 debugRaySimple("intersectTriangle() called:");
383 debugRaySimple(" start = ", start);
384 debugRaySimple(" direction = ", direction);
385 debugRaySimple(" elem->id() = ", elem->id());
386 debugRaySimple(" v0 = ", v0, " at ", elem->point(v0));
387 debugRaySimple(" v1 = ", v1, " at ", elem->point(v1));
388 debugRaySimple(" v2 = ", v2, " at ", elem->point(v2));
389 debugRaySimple(" hmax = ", hmax);
390 mooseAssert(elem->is_vertex(v0), "Not a vertex");
391 mooseAssert(elem->is_vertex(v1), "Not a vertex");
392 mooseAssert(elem->is_vertex(v2), "Not a vertex");
393
394 // We are scaling the whole element (start, v0, v1, v2) by 1 / hmax as an alternative to scaling
395 // the tolerance by hmax. If an intersection is found, the resulting intersection distance is
396 // then scaled by hmax to reverse the original scaling.
397 const auto inv_hmax = 1.0 / hmax;
398
399 const auto & v0_point = elem->point(v0);
400
401 const auto edge1 = (elem->point(v1) - v0_point) * inv_hmax;
402 const auto edge2 = (elem->point(v2) - v0_point) * inv_hmax;
403
404 const auto pvec = direction.cross(edge2);
405
406 auto det = edge1 * pvec;
407 debugRaySimple(" det = ", det);
408 if (det < TRACE_TOLERANCE)
409 {
410 debugRaySimple("intersectTriangle() did not intersect: det < tol");
411 return false;
412 }
413
414 const auto tvec = (start - v0_point) * inv_hmax;
415 const auto u = tvec * pvec;
416 debugRaySimple(" u = ", u);
417 debugRaySimple(" u / det = ", u / det);
418 if (u < -TRACE_TOLERANCE || u > det + TRACE_TOLERANCE)
419 {
420 debugRaySimple("intersectTriangle() did not intersect: u out of range");
421 return false;
422 }
423
424 const auto qvec = tvec.cross(edge1);
425 const auto v = direction * qvec;
426 debugRaySimple(" v = ", v);
427 debugRaySimple(" v / det = ", v / det);
428 debugRaySimple(" (u + v) / det = ", (u + v) / det);
429 if (v < -TRACE_TOLERANCE || u + v > det + TRACE_TOLERANCE)
430 {
431 debugRaySimple("intersectTriangle() did not intersect: v out of range");
432 return false;
433 }
434
435 const auto possible_distance = (edge2 * qvec) / det;
436 debugRaySimple(" possible_distance = ", possible_distance);
437 if (possible_distance <= TRACE_TOLERANCE)
438 {
439 debugRaySimple("intersectTriangle() did not intersect: distance too small");
440 return false;
441 }
442
443 // Recall that the element was scaled by (1 / hmax), reverse this scaling by
444 // scaling the intersection distance by hmax
445 intersection_distance = possible_distance * hmax;
446
447 // Here, u and v aren't truly u and v. The actual u and v are obtained with:
448 // u = u / det and v = v / det -> move det to the RHS to avoid division
449 if (u < TRACE_TOLERANCE * det)
450 {
451 if (v < TRACE_TOLERANCE * det) // u = 0, v = 0
452 intersected_extrema.setVertex(v0);
453 else if (v > (1.0 - TRACE_TOLERANCE) * det) // u = 0, v = 1
454 intersected_extrema.setVertex(v2);
455 else // u = 0
456 intersected_extrema.setEdge(v0, v2);
457 }
458 else if (v < TRACE_TOLERANCE * det)
459 {
460 if (u > (1.0 - TRACE_TOLERANCE) * det) // u = 1, v = 0
461 intersected_extrema.setVertex(v1);
462 else // v = 0
463 intersected_extrema.setEdge(v0, v1);
464 }
465 else if ((u + v > (1.0 - TRACE_TOLERANCE) * det)) // u + v = 1
466 intersected_extrema.setEdge(v1, v2);
467
468 debugRaySimple("intersectTriangle() intersected with:");
469 debugRaySimple(" intersection_distance = ", intersection_distance);
470 debugRaySimple(" intersected_extrema = ", intersected_extrema);
471
472 return true;
473}
474
475bool
476intersectQuad(const Point & start,
477 const Point & direction,
478 const Elem * const elem,
479 const unsigned short v00,
480 const unsigned short v10,
481 const unsigned short v11,
482 const unsigned short v01,
483 Real & intersection_distance,
484 ElemExtrema & intersected_extrema,
485 const Real hmax
486#ifdef DEBUG_RAY_INTERSECTIONS
487 ,
488 const bool debug
489#endif
490)
491{
492 mooseAssert(intersected_extrema.isInvalid(), "Should be invalid");
493 debugRaySimple("intersectQuad() called:");
494 debugRaySimple(" start = ", start);
495 debugRaySimple(" direction = ", direction);
496 debugRaySimple(" elem->id() = ", elem->id());
497 debugRaySimple(" v00 = ", v00, " at ", elem->point(v00));
498 debugRaySimple(" v10 = ", v10, " at ", elem->point(v10));
499 debugRaySimple(" v11 = ", v11, " at ", elem->point(v11));
500 debugRaySimple(" v01 = ", v01, " at ", elem->point(v01));
501
502 // NOTE discovered by @GiudGiud: In the case that you have
503 // a glancing intersection (the direction is within the plane
504 // of the face), you could possibly miss a further intersection
505 // on the second triangle. In reality, this should not be
506 // a problem because we check all sides of the element, so
507 // we would find a further intersection in the future.
508
509 // First check the triangle contained by v00, v10, v11
510 bool intersects = intersectTriangle(start,
511 direction,
512 elem,
513 v00,
514 v10,
515 v11,
516 intersection_distance,
517 intersected_extrema,
518 hmax
519#ifdef DEBUG_RAY_INTERSECTIONS
520 ,
521 debug
522#endif
523 );
524 // If no intersection, check the triangle contained by v11, v01, v00
525 if (!intersects)
526 intersects = intersectTriangle(start,
527 direction,
528 elem,
529 v11,
530 v01,
531 v00,
532 intersection_distance,
533 intersected_extrema,
534 hmax
535#ifdef DEBUG_RAY_INTERSECTIONS
536 ,
537 debug
538#endif
539 );
540
541 // Because we split the quad into two triangles, we could intersect the edge v00 - v11. However,
542 // that really isn't an edge - it's a diagonal across the quad. If we intersect this edge, be sure
543 // to invalidate it
544 if (intersects && intersected_extrema.atEdge(v00, v11))
545 intersected_extrema.invalidate();
546
547 return intersects;
548}
549
550bool
552{
553 return TRACEABLE_ELEMTYPES.count(elem->type());
554}
555
556bool
558{
559 return ADAPTIVITY_TRACEABLE_ELEMTYPES.count(elem->type());
560}
561
562unsigned short
563atVertex(const Elem * elem, const Point & point)
564{
565 for (unsigned int v = 0; v < elem->n_vertices(); ++v)
566 if (elem->point(v).absolute_fuzzy_equals(point, TRACE_TOLERANCE))
567 return v;
568
570}
571
572template <typename T>
573bool
575 const Point & point,
576 ElemExtrema & extrema,
577 const Real tolerance /* = TRACE_TOLERANCE */)
578{
579 mooseAssert(extrema.isInvalid(), "Should be invalid");
580
581 for (int e = 0; e < T::num_edges; ++e)
582 if (isWithinSegment(elem->point(T::edge_nodes_map[e][0]),
583 elem->point(T::edge_nodes_map[e][1]),
584 point,
585 tolerance))
586 {
587 extrema.setEdge(T::edge_nodes_map[e][0], T::edge_nodes_map[e][1]);
588 return true;
589 }
590
591 return false;
592}
593
594bool
595withinEdge(const Elem * elem,
596 const Point & point,
597 ElemExtrema & extrema,
598 const Real tolerance /* = TRACE_TOLERANCE */)
599{
600 switch (elem->type())
601 {
602 case HEX8:
603 case HEX20:
604 case HEX27:
605 return withinEdgeTempl<Hex8>(elem, point, extrema, tolerance);
606 case TET4:
607 case TET10:
608 case TET14:
609 return withinEdgeTempl<Tet4>(elem, point, extrema, tolerance);
610 case PYRAMID5:
611 case PYRAMID13:
612 case PYRAMID14:
613 return withinEdgeTempl<Pyramid5>(elem, point, extrema, tolerance);
614 case PRISM6:
615 case PRISM15:
616 case PRISM18:
617 return withinEdgeTempl<Prism6>(elem, point, extrema, tolerance);
618 default:
619 mooseError("Element type ",
621 " not supported in TraceRayTools::withinEdge()");
622 }
623
624 return false;
625}
626
627unsigned short
628atVertexOnSide(const Elem * elem, const Point & point, const unsigned short side)
629{
630 switch (elem->type())
631 {
632 case HEX8:
633 case HEX20:
634 case HEX27:
635 return atVertexOnSideTempl<Hex8>(elem, point, side);
636 case QUAD4:
637 case QUAD8:
638 case QUAD9:
639 return atVertexOnSideTempl<Quad4>(elem, point, side);
640 case TRI3:
641 case TRI6:
642 case TRI7:
643 return atVertexOnSideTempl<Tri3>(elem, point, side);
644 case TET4:
645 case TET10:
646 case TET14:
647 return atVertexOnSideTempl<Tet4>(elem, point, side);
648 case PYRAMID5:
649 case PYRAMID13:
650 case PYRAMID14:
651 return atVertexOnSideTempl<Pyramid5>(elem, point, side);
652 case PRISM6:
653 case PRISM15:
654 case PRISM18:
655 return atVertexOnSideTempl<Prism6>(elem, point, side);
656 case EDGE2:
657 case EDGE3:
658 case EDGE4:
659 return atVertexOnSideTempl<Edge2>(elem, point, side);
660 default:
661 mooseError("Element type ",
663 " not supported in TraceRayTools::atVertexOnSide()");
664 }
665
667}
668
669template <typename T>
670typename std::enable_if<!std::is_base_of<Edge, T>::value, unsigned short>::type
671atVertexOnSideTempl(const Elem * elem, const Point & point, const unsigned short side)
672{
673 mooseAssert(side < elem->n_sides(), "Invalid side");
674 mooseAssert(elem->side_ptr(side)->close_to_point(point, LOOSE_TRACE_TOLERANCE),
675 "Side does not contain point");
676
677 for (int i = 0; i < nodesPerSide<T>(side); ++i)
678 if (elem->point(T::side_nodes_map[side][i]).absolute_fuzzy_equals(point, TRACE_TOLERANCE))
679 return T::side_nodes_map[side][i];
680
682}
683
684template <typename T>
685typename std::enable_if<std::is_base_of<Edge, T>::value, unsigned short>::type
686atVertexOnSideTempl(const Elem * elem, const Point & point, const unsigned short side)
687{
688 mooseAssert(side < elem->n_sides(), "Invalid side");
689 mooseAssert(elem->side_ptr(side)->close_to_point(point, LOOSE_TRACE_TOLERANCE),
690 "Side does not contain point");
691
692 if (elem->point(side).absolute_fuzzy_equals(point, TRACE_TOLERANCE))
693 return side;
694
696}
697
698bool
699withinEdgeOnSide(const Elem * const elem,
700 const Point & point,
701 const unsigned short side,
702 ElemExtrema & extrema)
703{
704 switch (elem->type())
705 {
706 case HEX8:
707 case HEX20:
708 case HEX27:
709 return withinEdgeOnSideTempl<Hex8>(elem, point, side, extrema);
710 case TET4:
711 case TET10:
712 case TET14:
713 return withinEdgeOnSideTempl<Tet4>(elem, point, side, extrema);
714 case PYRAMID5:
715 case PYRAMID13:
716 case PYRAMID14:
717 return withinEdgeOnSideTempl<Pyramid5>(elem, point, side, extrema);
718 case PRISM6:
719 case PRISM15:
720 case PRISM18:
721 return withinEdgeOnSideTempl<Prism6>(elem, point, side, extrema);
722 default:
723 mooseError("Element type ",
725 " not supported in TraceRayTools::withinEdgeOnSide()");
726 }
727
728 return false;
729}
730
731template <typename T>
732typename std::enable_if<std::is_base_of<Cell, T>::value, bool>::type
733withinEdgeOnSideTempl(const Elem * const elem,
734 const Point & point,
735 const unsigned short side,
736 ElemExtrema & extrema)
737{
738 mooseAssert(side < elem->n_sides(), "Invalid side");
739 mooseAssert(elem->side_ptr(side)->close_to_point(point, LOOSE_TRACE_TOLERANCE),
740 "Side does not contain point");
741 mooseAssert(extrema.isInvalid(), "Should be invalid");
742
743 int last_n = T::side_nodes_map[side][nodesPerSide<T>(side) - 1];
744
745 for (int side_v = 0; side_v < nodesPerSide<T>(side); ++side_v)
746 if (isWithinSegment(elem->point(last_n), elem->point(T::side_nodes_map[side][side_v]), point))
747 {
748 extrema.setEdge(last_n, T::side_nodes_map[side][side_v]);
749 mooseAssert(extrema.buildEdge(elem)->close_to_point(point, LOOSE_TRACE_TOLERANCE),
750 "Edge doesn't contain point");
751 return true;
752 }
753 else
754 last_n = T::side_nodes_map[side][side_v];
755
756 return false;
757}
758
759bool
760withinExtremaOnSide(const Elem * const elem,
761 const Point & point,
762 const unsigned short side,
763 const unsigned int dim,
764 ElemExtrema & extrema)
765{
766 mooseAssert(extrema.isInvalid(), "Extrema should be invalid");
767 mooseAssert(dim == elem->dim(), "Incorrect dim");
768
769 extrema.first = atVertexOnSide(elem, point, side);
770 if (extrema.atVertex())
771 return true;
772 if (dim == 3 && withinEdgeOnSide(elem, point, side, extrema))
773 return true;
774
775 return false;
776}
777
778bool
779isWithinSegment(const Point & segment1,
780 const Point & segment2,
781 const Point & point,
782 const Real tolerance /* = TRACE_TOLERANCE */)
783{
784 mooseAssert(!segment1.absolute_fuzzy_equals(segment2, TRACE_TOLERANCE), "Same endpoints");
785
786 const auto segment_length = (segment1 - segment2).norm();
787 return isWithinSegment(segment1, segment2, segment_length, point, tolerance);
788}
789
790bool
791isWithinSegment(const Point & segment1,
792 const Point & segment2,
793 const Real segment_length,
794 const Point & point,
795 const Real tolerance /* = TRACE_TOLERANCE */)
796{
797 mooseAssert(!segment1.absolute_fuzzy_equals(segment2, TRACE_TOLERANCE), "Same endpoints");
798 mooseAssert(MooseUtils::absoluteFuzzyEqual((segment1 - segment2).norm(), segment_length),
799 "Invalid segment length");
800
801 const auto diff1 = point - segment1;
802 const auto diff2 = point - segment2;
803
804 if (diff1 * diff2 > tolerance * segment_length)
805 return false;
806
807 return std::abs(diff1.norm() + diff2.norm() - segment_length) < tolerance * segment_length;
808}
809
810bool
812 const Point & point,
813 const unsigned int dim,
814 const Real tolerance)
815{
816 for (unsigned int d = 0; d < dim; ++d)
817 if (MooseUtils::absoluteFuzzyEqual(point(d), bbox.min()(d), tolerance) ||
818 MooseUtils::absoluteFuzzyEqual(point(d), bbox.max()(d), tolerance))
819 return true;
820
821 return false;
822}
823}
const double v
void mooseError(Args &&... args)
char ** sides
unsigned int dim
bool contains(const T &value) const
const Point & max() const
const Point & min() const
dof_id_type id() const
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const=0
bool active() const
virtual unsigned int n_vertices() const=0
const Point & point(const unsigned int i) const
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
const Elem * child_ptr(unsigned int i) const
unsigned int which_neighbor_am_i(const Elem *e) const
void find_point_neighbors(const Point &p, std::set< const Elem * > &neighbor_set) const
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
virtual unsigned short dim() const=0
unsigned int level() const
virtual bool is_vertex(const unsigned int i) const=0
virtual unsigned int n_children() const=0
unsigned int get_node_index(const Node *node_ptr) const
virtual ElemType type() const=0
const Elem * neighbor_ptr(unsigned int i) const
bool absolute_fuzzy_equals(const TypeVector< Real > &rhs, Real tol=TOLERANCE) const
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
static const unsigned short invalid_vertex
Identifier for an invalid vertex index.
bool withinEdgeTempl(const Elem *elem, const Point &point, ElemExtrema &extrema, const Real tolerance=TRACE_TOLERANCE)
Determines if a point is within edge on an element.
void findNodeNeighbors(const Elem *const elem, const Node *const node, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &neighbor_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &untested_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &next_untested_set, std::vector< const Elem * > active_neighbor_children, std::vector< NeighborInfo > &info)
bool withinExtremaOnSide(const Elem *const elem, const Point &point, const unsigned short side, const unsigned int dim, ElemExtrema &extrema)
Determines if a point is within an Elem's extrema (at vertex/within edge) on a side.
bool withinEdge(const Elem *elem, const Point &point, ElemExtrema &extrema, const Real tolerance=TRACE_TOLERANCE)
Determines if a point is within an edge on an element.
std::enable_if<!std::is_base_of< Edge, T >::value, unsignedshort >::type atVertexOnSideTempl(const Elem *elem, const Point &point, const unsigned short side)
Determines if a point is at a vertex on the side of an element.
bool intersectTriangle(const Point &start, const Point &direction, const Elem *const elem, const unsigned short v0, const unsigned short v1, const unsigned short v2, Real &intersection_distance, ElemExtrema &intersected_extrema, const Real hmax #ifdef DEBUG_RAY_INTERSECTIONS, const bool debug #endif)
Checks for the intersection of a ray and a triangular face.
const Real TRACE_TOLERANCE
The standard tolerance to use in tracing.
unsigned short atVertex(const Elem *elem, const Point &point)
Determines if a point is at a vertex of an element.
bool isWithinSegment(const Point &segment1, const Point &segment2, const Point &point, const Real tolerance=TRACE_TOLERANCE)
Checks whether or not a point is within a line segment.
bool isAdaptivityTraceableElem(const Elem *elem)
bool lineLineIntersect2D(const Point &start, const Point &direction, const Real length, const Point &v0, const Point &v1, Point &intersection_point, Real &intersection_distance, SegmentVertices &segment_vertex #ifdef DEBUG_RAY_INTERSECTIONS, const bool debug #endif)
Checks for the intersection of the line u0 -> u1 with the line v0 -> v1, where u0 = start and u1 = st...
bool intersectQuad(const Point &start, const Point &direction, const Elem *const elem, const unsigned short v00, const unsigned short v10, const unsigned short v11, const unsigned short v01, Real &intersection_distance, ElemExtrema &intersected_extrema, const Real hmax #ifdef DEBUG_RAY_INTERSECTIONS, const bool debug #endif)
Checks for the intersection of a ray and a quadrilateral, numbered as such:
const Elem * childContainingPointOnSide(const Elem *elem, const Point &point, const unsigned short side)
Find the child of an elem that contains a point on a specified side of elem.
bool withinEdgeOnSide(const Elem *const elem, const Point &point, const unsigned short side, ElemExtrema &extrema)
Determines if a point is within an edge on the side of an element.
const Real LOOSE_TRACE_TOLERANCE
Looser tolerance for use in error checking in difficult situations.
const Elem * getActiveNeighbor(const Elem *elem, const unsigned short side, const Point &point)
Get the active neighbor on side of elem that contains point.
bool onBoundingBoxBoundary(const BoundingBox &bbox, const Point &point, const unsigned int dim, const Real tolerance)
Whether or not point is on the boundary (min/max) of bbox.
void findPointNeighbors(const Elem *const elem, const Point &point, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &neighbor_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &untested_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &next_untested_set, std::vector< const Elem * > active_neighbor_children, std::vector< NeighborInfo > &info)
Rewrite of the find_point_neighbors function in libMesh, instead using a statically allocated set: re...
void findNeighbors(const Elem *const elem, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &neighbor_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &untested_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &next_untested_set, std::vector< const Elem * > active_neighbor_children, KeepFunctor &keep_functor)
More generalized form of the find_point_neighbors function in libMesh.
const std::set< int > TRACEABLE_ELEMTYPES
The element types that are traceable.
std::enable_if< std::is_base_of< libMesh::Cell, T >::value, bool >::type withinEdgeOnSideTempl(const Elem *const elem, const Point &point, const unsigned short side, ElemExtrema &extrema)
Determines if a point is within an edge on the side of an element.
const std::set< int > ADAPTIVITY_TRACEABLE_ELEMTYPES
The element types that are traceable with adaptivity.
bool isTraceableElem(const Elem *elem)
void findEdgeNeighbors(const Elem *const elem, const Node *const node1, const Node *const node2, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &neighbor_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &untested_set, MooseUtils::StaticallyAllocatedSet< const Elem *, MAX_POINT_NEIGHBORS > &next_untested_set, std::vector< const Elem * > active_neighbor_children, std::vector< NeighborInfo > &info)
SegmentVertices
Enum for the possible vertices on a segment used in lineLineIntersect2D()
unsigned short atVertexOnSide(const Elem *elem, const Point &point, const unsigned short side)
Determines if a point is at a vertex on the side of en element.
std::string enum_to_string(const T e)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
const unsigned int invalid_uint
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Helper for defining if at an element's edge, vertex, or neither.
Definition ElemExtrema.h:26
bool isInvalid() const
Definition ElemExtrema.h:48
std::unique_ptr< const libMesh::Elem > buildEdge(const Elem *elem) const
Definition ElemExtrema.C:22
bool atEdge() const
Definition ElemExtrema.h:71
void invalidate()
Invalidates the current state.
Definition ElemExtrema.h:87
bool atVertex() const
Definition ElemExtrema.h:56
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.