libMesh
Loading...
Searching...
No Matches
elem.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19// Local includes
20#include "libmesh/elem.h"
21
22#include "libmesh/boundary_info.h"
23#include "libmesh/fe_type.h"
24#include "libmesh/fe_interface.h"
25#include "libmesh/node_elem.h"
26#include "libmesh/edge_edge2.h"
27#include "libmesh/edge_edge3.h"
28#include "libmesh/edge_edge4.h"
29#include "libmesh/edge_inf_edge2.h"
30#include "libmesh/face_c0polygon.h"
31#include "libmesh/face_tri3.h"
32#include "libmesh/face_tri3_subdivision.h"
33#include "libmesh/face_tri3_shell.h"
34#include "libmesh/face_tri6.h"
35#include "libmesh/face_tri7.h"
36#include "libmesh/face_quad4.h"
37#include "libmesh/face_quad4_shell.h"
38#include "libmesh/face_quad8.h"
39#include "libmesh/face_quad8_shell.h"
40#include "libmesh/face_quad9.h"
41#include "libmesh/face_quad9_shell.h"
42#include "libmesh/face_inf_quad4.h"
43#include "libmesh/face_inf_quad6.h"
44#include "libmesh/cell_tet4.h"
45#include "libmesh/cell_tet10.h"
46#include "libmesh/cell_tet14.h"
47#include "libmesh/cell_hex8.h"
48#include "libmesh/cell_hex20.h"
49#include "libmesh/cell_hex27.h"
50#include "libmesh/cell_inf_hex8.h"
51#include "libmesh/cell_inf_hex16.h"
52#include "libmesh/cell_inf_hex18.h"
53#include "libmesh/cell_prism6.h"
54#include "libmesh/cell_prism15.h"
55#include "libmesh/cell_prism18.h"
56#include "libmesh/cell_prism20.h"
57#include "libmesh/cell_prism21.h"
58#include "libmesh/cell_inf_prism6.h"
59#include "libmesh/cell_inf_prism12.h"
60#include "libmesh/cell_pyramid5.h"
61#include "libmesh/cell_pyramid13.h"
62#include "libmesh/cell_pyramid14.h"
63#include "libmesh/cell_pyramid18.h"
64#include "libmesh/fe_base.h"
65#include "libmesh/mesh_base.h"
66#include "libmesh/quadrature_nodal.h"
67#include "libmesh/quadrature_gauss.h"
68#include "libmesh/remote_elem.h"
69#include "libmesh/reference_elem.h"
70#include "libmesh/enum_to_string.h"
71#include "libmesh/threads.h"
72#include "libmesh/enum_elem_quality.h"
73#include "libmesh/enum_io_package.h"
74#include "libmesh/enum_order.h"
75#include "libmesh/elem_internal.h"
76
77#ifdef LIBMESH_ENABLE_PERIODIC
78#include "libmesh/mesh.h"
79#include "libmesh/periodic_boundaries.h"
80#endif
81
82
83// C++ includes
84#include <algorithm> // for std::sort
85#include <array>
86#include <iterator> // for std::ostream_iterator
87#include <sstream>
88#include <limits> // for std::numeric_limits<>
89#include <cmath> // for std::sqrt()
90#include <memory>
91#include <regex> // for exceptions in volume()
92
93
94namespace libMesh
95{
96
99
100// Initialize static member variables
101const unsigned int Elem::type_to_dim_map [] =
102 {
103 1, // EDGE2
104 1, // EDGE3
105 1, // EDGE4
106
107 2, // TRI3
108 2, // TRI6
109
110 2, // QUAD4
111 2, // QUAD8
112 2, // QUAD9
113
114 3, // TET4
115 3, // TET10
116
117 3, // HEX8
118 3, // HEX20
119 3, // HEX27
120
121 3, // PRISM6
122 3, // PRISM15
123 3, // PRISM18
124
125 3, // PYRAMID5
126 3, // PYRAMID13
127 3, // PYRAMID14
129 1, // INFEDGE2
130
131 2, // INFQUAD4
132 2, // INFQUAD6
133
134 3, // INFHEX8
135 3, // INFHEX16
136 3, // INFHEX18
137
138 3, // INFPRISM6
139 3, // INFPRISM12
140
141 0, // NODEELEM
142
143 0, // REMOTEELEM
144
145 2, // TRI3SUBDIVISION
146 2, // TRISHELL3
147 2, // QUADSHELL4
148 2, // QUADSHELL8
149
150 2, // TRI7
151 3, // TET14
152 3, // PRISM20
153 3, // PRISM21
154 3, // PYRAMID18
155
156 2, // QUADSHELL9
157
158 2, // C0POLYGON
159 3, // C0POLYHEDRON
160 };
161
162const unsigned int Elem::max_n_nodes;
163
164const unsigned int Elem::type_to_n_nodes_map [] =
165 {
166 2, // EDGE2
167 3, // EDGE3
168 4, // EDGE4
169
170 3, // TRI3
171 6, // TRI6
172
173 4, // QUAD4
174 8, // QUAD8
175 9, // QUAD9
176
177 4, // TET4
178 10, // TET10
179
180 8, // HEX8
181 20, // HEX20
182 27, // HEX27
183
184 6, // PRISM6
185 15, // PRISM15
186 18, // PRISM18
187
188 5, // PYRAMID5
189 13, // PYRAMID13
190 14, // PYRAMID14
191
192 2, // INFEDGE2
193
194 4, // INFQUAD4
195 6, // INFQUAD6
196
197 8, // INFHEX8
198 16, // INFHEX16
199 18, // INFHEX18
200
201 6, // INFPRISM6
202 12, // INFPRISM12
203
204 1, // NODEELEM
205
206 0, // REMOTEELEM
207
208 3, // TRI3SUBDIVISION
209 3, // TRISHELL3
210 4, // QUADSHELL4
211 8, // QUADSHELL8
212
213 7, // TRI7
214 14, // TET14
215 20, // PRISM20
216 21, // PRISM21
217 18, // PYRAMID18
218
219 9, // QUADSHELL9
220
221 invalid_uint, // C0POLYGON
222 invalid_uint, // C0POLYHEDRON
223 };
224
225const unsigned int Elem::type_to_n_sides_map [] =
226 {
227 2, // EDGE2
228 2, // EDGE3
229 2, // EDGE4
230
231 3, // TRI3
232 3, // TRI6
233
234 4, // QUAD4
235 4, // QUAD8
236 4, // QUAD9
237
238 4, // TET4
239 4, // TET10
240
241 6, // HEX8
242 6, // HEX20
243 6, // HEX27
244
245 5, // PRISM6
246 5, // PRISM15
247 5, // PRISM18
248
249 5, // PYRAMID5
250 5, // PYRAMID13
251 5, // PYRAMID14
252
253 2, // INFEDGE2
254
255 3, // INFQUAD4
256 3, // INFQUAD6
257
258 5, // INFHEX8
259 5, // INFHEX16
260 5, // INFHEX18
261
262 4, // INFPRISM6
263 4, // INFPRISM12
264
265 0, // NODEELEM
266
267 0, // REMOTEELEM
268
269 3, // TRI3SUBDIVISION
270 3, // TRISHELL3
271 4, // QUADSHELL4
272 4, // QUADSHELL8
273
274 3, // TRI7
275 4, // TET14
276 5, // PRISM20
277 5, // PRISM21
278 5, // PYRAMID18
279
280 4, // QUADSHELL9
281
282 invalid_uint, // C0POLYGON
283 invalid_uint, // C0POLYHEDRON
284 };
285
286const unsigned int Elem::type_to_n_edges_map [] =
287 {
288 0, // EDGE2
289 0, // EDGE3
290 0, // EDGE4
291
292 3, // TRI3
293 3, // TRI6
294
295 4, // QUAD4
296 4, // QUAD8
297 4, // QUAD9
298
299 6, // TET4
300 6, // TET10
301
302 12, // HEX8
303 12, // HEX20
304 12, // HEX27
305
306 9, // PRISM6
307 9, // PRISM15
308 9, // PRISM18
309
310 8, // PYRAMID5
311 8, // PYRAMID13
312 8, // PYRAMID14
313
314 0, // INFEDGE2
315
316 3, // INFQUAD4
317 3, // INFQUAD6
318
319 8, // INFHEX8
320 8, // INFHEX16
321 8, // INFHEX18
322
323 6, // INFPRISM6
324 6, // INFPRISM12
325
326 0, // NODEELEM
327
328 0, // REMOTEELEM
329
330 3, // TRI3SUBDIVISION
331 3, // TRISHELL3
332 4, // QUADSHELL4
333 4, // QUADSHELL8
334
335 3, // TRI7
336 6, // TET14
337 9, // PRISM20
338 9, // PRISM21
339 8, // PYRAMID18
340
341 4, // QUADSHELL9
342
343 invalid_uint, // C0POLYGON
344 invalid_uint, // C0POLYHEDRON
345 };
346
348 {
349 FIRST, // EDGE2
350 SECOND, // EDGE3
351 THIRD, // EDGE4
352
353 FIRST, // TRI3
354 SECOND, // TRI6
355
356 FIRST, // QUAD4
357 SECOND, // QUAD8
358 SECOND, // QUAD9
359
360 FIRST, // TET4
361 SECOND, // TET10
362
363 FIRST, // HEX8
364 SECOND, // HEX20
365 SECOND, // HEX27
366
367 FIRST, // PRISM6
368 SECOND, // PRISM15
369 SECOND, // PRISM18
370
371 FIRST, // PYRAMID5
372 SECOND, // PYRAMID13
373 SECOND, // PYRAMID14
374
375 FIRST, // INFEDGE2
376
377 FIRST, // INFQUAD4
378 SECOND, // INFQUAD6
379
380 FIRST, // INFHEX8
381 SECOND, // INFHEX16
382 SECOND, // INFHEX18
383
384 FIRST, // INFPRISM6
385 SECOND, // INFPRISM12
386
387 CONSTANT, // NODEELEM
388
389 INVALID_ORDER, // REMOTEELEM
390
391 FIRST, // TRI3SUBDIVISION
392 FIRST, // TRISHELL3
393 FIRST, // QUADSHELL4
394 SECOND, // QUADSHELL8
395
396 THIRD, // TRI7
397 THIRD, // TET14
398 THIRD, // PRISM20
399 THIRD, // PRISM21
400 THIRD, // PYRAMID18
401
402 SECOND, // QUADSHELL9
403
404 FIRST, // C0POLYGON
405 FIRST, // C0POLYHEDRON
406 };
407
408// ------------------------------------------------------------
409// Elem class member functions
410std::unique_ptr<Elem> Elem::disconnected_clone() const
411{
412 std::unique_ptr<Elem> returnval;
413
414 switch (this->type())
415 {
416 case C0POLYGON:
417 returnval = std::make_unique<C0Polygon>(this->n_sides());
418 break;
419
420 default:
421 returnval = Elem::build(this->type());
422 }
423
424 returnval->set_id() = this->id();
425#ifdef LIBMESH_ENABLE_UNIQUE_ID
426 if (this->valid_unique_id())
427 returnval->set_unique_id(this->unique_id());
428#endif
429
430 const auto n_elem_ints = this->n_extra_integers();
431 returnval->add_extra_integers(n_elem_ints);
432 for (unsigned int i = 0; i != n_elem_ints; ++i)
433 returnval->set_extra_integer(i, this->get_extra_integer(i));
434
435 returnval->inherit_data_from(*this);
436
437 return returnval;
438}
439
440
441
442std::unique_ptr<Elem> Elem::build(const ElemType type,
443 Elem * p)
444{
445 switch (type)
446 {
447 // 0D elements
448 case NODEELEM:
449 return std::make_unique<NodeElem>(p);
450
451 // 1D elements
452 case EDGE2:
453 return std::make_unique<Edge2>(p);
454 case EDGE3:
455 return std::make_unique<Edge3>(p);
456 case EDGE4:
457 return std::make_unique<Edge4>(p);
458
459 // 2D elements
460 case TRI3:
461 return std::make_unique<Tri3>(p);
462 case TRISHELL3:
463 return std::make_unique<TriShell3>(p);
464 case TRI3SUBDIVISION:
465 return std::make_unique<Tri3Subdivision>(p);
466 case TRI6:
467 return std::make_unique<Tri6>(p);
468 case TRI7:
469 return std::make_unique<Tri7>(p);
470 case QUAD4:
471 return std::make_unique<Quad4>(p);
472 case QUADSHELL4:
473 return std::make_unique<QuadShell4>(p);
474 case QUAD8:
475 return std::make_unique<Quad8>(p);
476 case QUADSHELL8:
477 return std::make_unique<QuadShell8>(p);
478 case QUAD9:
479 return std::make_unique<Quad9>(p);
480 case QUADSHELL9:
481 return std::make_unique<QuadShell9>(p);
482
483 // Well, a hexagon is *a* polygon...
484 case C0POLYGON:
485 return std::make_unique<C0Polygon>(6, p);
486
487 // Building a polyhedron can't currently be done without creating
488 // its nodes first
489 case C0POLYHEDRON:
490 libmesh_not_implemented_msg
491 ("Polyhedra cannot be built via Elem::build()");
492
493 // 3D elements
494 case TET4:
495 return std::make_unique<Tet4>(p);
496 case TET10:
497 return std::make_unique<Tet10>(p);
498 case TET14:
499 return std::make_unique<Tet14>(p);
500 case HEX8:
501 return std::make_unique<Hex8>(p);
502 case HEX20:
503 return std::make_unique<Hex20>(p);
504 case HEX27:
505 return std::make_unique<Hex27>(p);
506 case PRISM6:
507 return std::make_unique<Prism6>(p);
508 case PRISM15:
509 return std::make_unique<Prism15>(p);
510 case PRISM18:
511 return std::make_unique<Prism18>(p);
512 case PRISM20:
513 return std::make_unique<Prism20>(p);
514 case PRISM21:
515 return std::make_unique<Prism21>(p);
516 case PYRAMID5:
517 return std::make_unique<Pyramid5>(p);
518 case PYRAMID13:
519 return std::make_unique<Pyramid13>(p);
520 case PYRAMID14:
521 return std::make_unique<Pyramid14>(p);
522 case PYRAMID18:
523 return std::make_unique<Pyramid18>(p);
524
525#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
526 // 1D infinite elements
527 case INFEDGE2:
528 return std::make_unique<InfEdge2>(p);
529
530 // 2D infinite elements
531 case INFQUAD4:
532 return std::make_unique<InfQuad4>(p);
533 case INFQUAD6:
534 return std::make_unique<InfQuad6>(p);
535
536 // 3D infinite elements
537 case INFHEX8:
538 return std::make_unique<InfHex8>(p);
539 case INFHEX16:
540 return std::make_unique<InfHex16>(p);
541 case INFHEX18:
542 return std::make_unique<InfHex18>(p);
543 case INFPRISM6:
544 return std::make_unique<InfPrism6>(p);
545 case INFPRISM12:
546 return std::make_unique<InfPrism12>(p);
547#endif
548
549 default:
550 libmesh_error_msg("ERROR: Undefined element type == " << Utility::enum_to_string(type));
551 }
552}
553
554
555
556std::unique_ptr<Elem> Elem::build_with_id (const ElemType type,
557 dof_id_type id)
558{
559 // Call the other build() method with nullptr parent, then set the
560 // required id.
561 auto temp = Elem::build(type, nullptr);
562 temp->set_id(id);
563 return temp;
564}
565
566
567
569{
570 return &(ReferenceElem::get(this->type()));
571}
572
573
574
576{
577 // The base class implementation builds a finite element of the correct
578 // order and computes the centroid, c=(cx, cy, cz), where:
579 //
580 // [cx] [\int x dV]
581 // [cy] := (1/V) * [\int y dV]
582 // [cz] [\int z dV]
583 //
584 // using quadrature. Note that we can expand "x" in the FE space as:
585 //
586 // x = \sum_i x_i \phi_i
587 //
588 // where x_i are the nodal positions of the element and \phi_i are the
589 // associated Lagrange shape functions. This allows us to write the
590 // integrals above as e.g.:
591 //
592 // \int x dV = \sum_i x_i \int \phi_i dV
593 //
594 // Defining:
595 //
596 // V_i := \int \phi_i dV
597 //
598 // we then have:
599 //
600 // [cx] [\sum_i x_i V_i]
601 // [cy] = (1/V) * [\sum_i y_i V_i]
602 // [cz] [\sum_i z_i V_i]
603 //
604 // where:
605 // V = \sum_i V_i
606 //
607 // Derived element types can overload this method to compute
608 // the centroid more efficiently when possible.
609
610 // If this Elem has an elevated p_level, then we need to generate a
611 // barebones copy of it with zero p_level and call true_centroid()
612 // on that instead. This workaround allows us to avoid issues with
613 // calling FE::reinit() with a default_order() FEType, and then
614 // having that order incorrectly boosted by p_level.
615 if (this->p_level())
616 {
617 auto elem_copy = this->disconnected_clone();
618#ifdef LIBMESH_ENABLE_AMR
619 elem_copy->set_p_level(0);
620#endif
621
622 // Set node pointers
623 for (auto n : this->node_index_range())
624 elem_copy->set_node(n, _nodes[n]);
625
626 return elem_copy->true_centroid();
627 }
628
629 const FEFamily mapping_family = FEMap::map_fe_type(*this);
630 const FEType fe_type(this->default_order(), mapping_family);
631
632 // Build FE and attach quadrature rule. The default quadrature rule
633 // integrates the mass matrix exactly, thus it is overkill to
634 // integrate the basis functions, but this is convenient.
635 std::unique_ptr<FEBase> fe = FEBase::build(this->dim(), fe_type);
636 QGauss qrule (this->dim(), fe_type.default_quadrature_order());
637 fe->attach_quadrature_rule(&qrule);
638
639 // Pre-request required data
640 const auto & JxW = fe->get_JxW();
641 const auto & phi = fe->get_phi();
642
643 // Re-compute element-specific values
644 fe->reinit(this);
645
646 // Number of basis functions
647 auto N = phi.size();
648 libmesh_assert_equal_to(N, this->n_nodes());
649
650 // Compute V_i
651 std::vector<Real> V(N);
652 for (auto qp : index_range(JxW))
653 for (auto i : make_range(N))
654 V[i] += JxW[qp] * phi[i][qp];
655
656 // Compute centroid
657 Point cp;
658 Real vol = 0.;
659
660 for (auto i : make_range(N))
661 {
662 cp += this->point(i) * V[i];
663 vol += V[i];
664 }
665
666 return cp / vol;
667}
668
670{
671 Point cp;
672
673 const auto n_vertices = this->n_vertices();
674
675 for (unsigned int n=0; n<n_vertices; n++)
676 cp.add (this->point(n));
677
678 return (cp /= static_cast<Real>(n_vertices));
679}
680
681
682
684{
685 // Avoid calling a virtual a lot of times
686 const auto n_vertices = this->n_vertices();
687
688 // Special case for NodeElem
689 if (!n_vertices)
690 return 0;
691
692 Real h_min=std::numeric_limits<Real>::max();
693
694 for (unsigned int n_outer=0; n_outer<n_vertices; n_outer++)
695 for (unsigned int n_inner=n_outer+1; n_inner<n_vertices; n_inner++)
696 {
697 const auto diff = (this->point(n_outer) - this->point(n_inner));
698
699 h_min = std::min(h_min, diff.norm_sq());
700 }
701
702 return std::sqrt(h_min);
703}
704
705
706
708{
709 Real h_max=0;
710
711 // Avoid calling a virtual a lot of times
712 const auto n_vertices = this->n_vertices();
713
714 for (unsigned int n_outer=0; n_outer<n_vertices; n_outer++)
715 for (unsigned int n_inner=n_outer+1; n_inner<n_vertices; n_inner++)
716 {
717 const auto diff = (this->point(n_outer) - this->point(n_inner));
718
719 h_max = std::max(h_max, diff.norm_sq());
720 }
721
722 return std::sqrt(h_max);
723}
724
725
726
727Real Elem::length(const unsigned int n1,
728 const unsigned int n2) const
729{
730 libmesh_assert_less ( n1, this->n_vertices() );
731 libmesh_assert_less ( n2, this->n_vertices() );
732
733 return (this->point(n1) - this->point(n2)).norm();
734}
735
736
737
739{
740 const unsigned short n_n = this->n_nodes();
741
742 std::array<dof_id_type, Elem::max_n_nodes> node_ids;
743
744 for (unsigned short n=0; n != n_n; ++n)
745 node_ids[n] = this->node_id(n);
746
747 // Always sort, so that different local node numberings hash to the
748 // same value.
749 std::sort (node_ids.begin(), node_ids.begin()+n_n);
750
751 return Utility::hashword(node_ids.data(), n_n);
752}
753
754
755
756bool Elem::operator == (const Elem & rhs) const
757{
758 // If the elements aren't the same type, they aren't equal
759 if (this->type() != rhs.type())
760 return false;
761
762 const unsigned short n_n = this->n_nodes();
763 libmesh_assert_equal_to(n_n, rhs.n_nodes());
764
765 // Make two sorted arrays of global node ids and compare them for
766 // equality.
767 std::array<dof_id_type, Elem::max_n_nodes> this_ids, rhs_ids;
768
769 for (unsigned short n = 0; n != n_n; n++)
770 {
771 this_ids[n] = this->node_id(n);
772 rhs_ids[n] = rhs.node_id(n);
773 }
774
775 // Sort the vectors to rule out different local node numberings.
776 std::sort(this_ids.begin(), this_ids.begin()+n_n);
777 std::sort(rhs_ids.begin(), rhs_ids.begin()+n_n);
778
779 // If the node ids match, the elements are equal!
780 for (unsigned short n = 0; n != n_n; ++n)
781 if (this_ids[n] != rhs_ids[n])
782 return false;
783 return true;
784}
785
786
787
788bool Elem::topologically_equal (const Elem & rhs) const
789{
790 // If the elements aren't the same type, they aren't equal
791 if (this->type() != rhs.type())
792 return false;
793
794 libmesh_assert_equal_to(this->n_nodes(), rhs.n_nodes());
795
796 for (auto n : make_range(this->n_nodes()))
797 if (this->node_id(n) != rhs.node_id(n))
798 return false;
799
800 for (auto neigh : make_range(this->n_neighbors()))
801 {
802 if (!this->neighbor_ptr(neigh))
803 {
804 if (rhs.neighbor_ptr(neigh))
805 return false;
806 continue;
807 }
808 if (!rhs.neighbor_ptr(neigh) ||
809 this->neighbor_ptr(neigh)->id() !=
810 rhs.neighbor_ptr(neigh)->id())
811 return false;
812 }
813
814 if (this->parent())
815 {
816 if (!rhs.parent())
817 return false;
818 if (this->parent()->id() != rhs.parent()->id())
819 return false;
820 }
821 else if (rhs.parent())
822 return false;
823
824 if (this->interior_parent())
825 {
826 if (!rhs.interior_parent())
827 return false;
828 if (this->interior_parent()->id() !=
829 rhs.interior_parent()->id())
830 return false;
831 }
832 else if (rhs.interior_parent())
833 return false;
834
835 return true;
836}
837
838
839
840bool Elem::is_semilocal(const processor_id_type my_pid) const
841{
842 std::set<const Elem *> point_neighbors;
843
844 this->find_point_neighbors(point_neighbors);
845
846 for (const auto & elem : point_neighbors)
847 if (elem->processor_id() == my_pid)
848 return true;
849
850 return false;
851}
852
853
854
855unsigned int Elem::which_side_am_i (const Elem * e) const
856{
858
859 const unsigned int ns = this->n_sides();
860 const unsigned int nn = this->n_nodes();
861
862 const unsigned int en = e->n_nodes();
863
864 // e might be on any side until proven otherwise
865 std::vector<bool> might_be_side(ns, true);
866
867 for (unsigned int i=0; i != en; ++i)
868 {
869 Point side_point = e->point(i);
870 unsigned int local_node_id = libMesh::invalid_uint;
871
872 // Look for a node of this that's contiguous with node i of
873 // e. Note that the exact floating point comparison of Point
874 // positions is intentional, see the class documentation for
875 // this function.
876 for (unsigned int j=0; j != nn; ++j)
877 if (this->point(j) == side_point)
878 local_node_id = j;
879
880 // If a node of e isn't contiguous with some node of this, then
881 // e isn't a side of this.
882 if (local_node_id == libMesh::invalid_uint)
884
885 // If a node of e isn't contiguous with some node on side s of
886 // this, then e isn't on side s.
887 for (unsigned int s=0; s != ns; ++s)
888 if (!this->is_node_on_side(local_node_id, s))
889 might_be_side[s] = false;
890 }
891
892 for (unsigned int s=0; s != ns; ++s)
893 if (might_be_side[s])
894 {
895#ifdef DEBUG
896 for (unsigned int s2=s+1; s2 < ns; ++s2)
897 libmesh_assert (!might_be_side[s2]);
898#endif
899 return s;
900 }
901
902 // Didn't find any matching side
904}
905
906
907
908bool Elem::contains_vertex_of(const Elem * e, bool mesh_connection) const
909{
910 // Our vertices are the first numbered nodes
911 const unsigned int nv = e->n_vertices();
912 const unsigned int my_nv = this->n_vertices();
913
914 // Check for vertex-to-vertex containment first; contains_point() is
915 // expensive
916 for (auto n : make_range(nv))
917 {
918 const Node * vertex = e->node_ptr(n);
919 for (auto my_n : make_range(my_nv))
920 if (&this->node_ref(my_n) == vertex)
921 return true;
922 }
923
924 // If e is in our mesh, then we might be done testing
925 if (mesh_connection)
926 {
927 const unsigned int l = this->level();
928 const unsigned int el = e->level();
929
930 if (l >= el)
931 return false;
932
933 // We could also return false for l==el-1 iff we knew we had no
934 // triangular faces, but we don't have an API to check that.
935 }
936
937 // Our vertices are the first numbered nodes
938 for (auto n : make_range(nv))
939 if (this->contains_point(e->point(n)))
940 return true;
941 return false;
942}
943
944
945
946bool Elem::contains_edge_of(const Elem * e) const
947{
948 unsigned int num_contained_edges = 0;
949
950 // Our vertices are the first numbered nodes
951 for (auto n : make_range(e->n_vertices()))
952 {
953 if (this->contains_point(e->point(n)))
954 {
955 num_contained_edges++;
956 if (num_contained_edges>=2)
957 {
958 return true;
959 }
960 }
961 }
962 return false;
963}
964
965
966
968 std::set<const Elem *> & neighbor_set) const
969{
971 libmesh_assert(this->active());
972
973 neighbor_set.clear();
974 neighbor_set.insert(this);
975
976 std::set<const Elem *> untested_set, next_untested_set;
977 untested_set.insert(this);
978
979#ifdef LIBMESH_ENABLE_AMR
980 std::vector<const Elem *> active_neighbor_children;
981#endif // #ifdef LIBMESH_ENABLE_AMR
982
983 while (!untested_set.empty())
984 {
985 // Loop over all the elements in the patch that haven't already
986 // been tested
987 for (const auto & elem : untested_set)
988 for (auto current_neighbor : elem->neighbor_ptr_range())
989 {
990 if (current_neighbor &&
991 current_neighbor != remote_elem) // we have a real neighbor on this side
992 {
993 if (current_neighbor->active()) // ... if it is active
994 {
995 auto it = neighbor_set.lower_bound(current_neighbor);
996 if ((it == neighbor_set.end() || *it != current_neighbor) &&
997 current_neighbor->contains_point(p)) // ... don't have and touches p
998 {
999 // Add it and test it
1000 next_untested_set.insert(current_neighbor);
1001 neighbor_set.emplace_hint(it, current_neighbor);
1002 }
1003 }
1004#ifdef LIBMESH_ENABLE_AMR
1005 else // ... the neighbor is *not* active,
1006 { // ... so add *all* neighboring
1007 // active children that touch p
1008 active_neighbor_children.clear();
1009 current_neighbor->active_family_tree_by_neighbor
1010 (active_neighbor_children, elem);
1011
1012 for (const auto & current_child : active_neighbor_children)
1013 {
1014 auto it = neighbor_set.lower_bound(current_child);
1015 if ((it == neighbor_set.end() || *it != current_child) &&
1016 current_child->contains_point(p))
1017 {
1018 // Add it and test it
1019 next_untested_set.insert(current_child);
1020 neighbor_set.emplace_hint(it, current_child);
1021 }
1022 }
1023 }
1024#endif // #ifdef LIBMESH_ENABLE_AMR
1025 }
1026 }
1027 untested_set.swap(next_untested_set);
1028 next_untested_set.clear();
1029 }
1030}
1031
1032
1033
1034void Elem::find_point_neighbors(std::set<const Elem *> & neighbor_set) const
1035{
1036 this->find_point_neighbors(neighbor_set, this);
1037}
1038
1039
1040
1041void Elem::find_point_neighbors(std::set<const Elem *> & neighbor_set,
1042 const Elem * start_elem) const
1043{
1044 ElemInternal::find_point_neighbors(this, neighbor_set, start_elem);
1045}
1046
1047
1048
1049void Elem::find_point_neighbors(std::set<Elem *> & neighbor_set,
1050 Elem * start_elem)
1051{
1052 ElemInternal::find_point_neighbors(this, neighbor_set, start_elem);
1053}
1054
1055
1056
1058 const Point & p2,
1059 std::set<const Elem *> & neighbor_set) const
1060{
1061 // Simple but perhaps suboptimal code: find elements containing the
1062 // first point, then winnow this set down by removing elements which
1063 // don't also contain the second point
1064
1065 libmesh_assert(this->contains_point(p2));
1066 this->find_point_neighbors(p1, neighbor_set);
1067
1068 std::set<const Elem *>::iterator it = neighbor_set.begin();
1069 const std::set<const Elem *>::iterator end = neighbor_set.end();
1070
1071 while (it != end)
1072 {
1073 // As of C++11, set::erase returns an iterator to the element
1074 // following the erased element, or end.
1075 if (!(*it)->contains_point(p2))
1076 it = neighbor_set.erase(it);
1077 else
1078 ++it;
1079 }
1080}
1081
1082
1083
1084void Elem::find_edge_neighbors(std::set<const Elem *> & neighbor_set) const
1085{
1086 neighbor_set.clear();
1087 neighbor_set.insert(this);
1088
1089 std::set<const Elem *> untested_set, next_untested_set;
1090 untested_set.insert(this);
1091
1092 while (!untested_set.empty())
1093 {
1094 // Loop over all the elements in the patch that haven't already
1095 // been tested
1096 for (const auto & elem : untested_set)
1097 {
1098 for (auto current_neighbor : elem->neighbor_ptr_range())
1099 {
1100 if (current_neighbor &&
1101 current_neighbor != remote_elem) // we have a real neighbor on this side
1102 {
1103 if (current_neighbor->active()) // ... if it is active
1104 {
1105 if (this->contains_edge_of(current_neighbor) // ... and touches us
1106 || current_neighbor->contains_edge_of(this))
1107 {
1108 // Make sure we'll test it
1109 if (!neighbor_set.count(current_neighbor))
1110 next_untested_set.insert (current_neighbor);
1111
1112 // And add it
1113 neighbor_set.insert (current_neighbor);
1114 }
1115 }
1116#ifdef LIBMESH_ENABLE_AMR
1117 else // ... the neighbor is *not* active,
1118 { // ... so add *all* neighboring
1119 // active children
1120 std::vector<const Elem *> active_neighbor_children;
1121
1122 current_neighbor->active_family_tree_by_neighbor
1123 (active_neighbor_children, elem);
1124
1125 for (const auto & current_child : active_neighbor_children)
1126 if (this->contains_edge_of(current_child) || current_child->contains_edge_of(this))
1127 {
1128 // Make sure we'll test it
1129 if (!neighbor_set.count(current_child))
1130 next_untested_set.insert (current_child);
1131
1132 neighbor_set.insert (current_child);
1133 }
1134 }
1135#endif // #ifdef LIBMESH_ENABLE_AMR
1136 }
1137 }
1138 }
1139 untested_set.swap(next_untested_set);
1140 next_untested_set.clear();
1141 }
1142}
1143
1144
1145
1146void Elem::find_interior_neighbors(std::set<const Elem *> & neighbor_set) const
1147{
1148 ElemInternal::find_interior_neighbors(this, neighbor_set);
1149}
1150
1151
1152
1153void Elem::find_interior_neighbors(std::set<Elem *> & neighbor_set)
1154{
1155 ElemInternal::find_interior_neighbors(this, neighbor_set);
1156}
1157
1158
1159
1161{
1162 // interior parents make no sense for full-dimensional elements.
1163 if (this->dim() >= LIBMESH_DIM)
1164 return nullptr;
1165
1166 // they USED TO BE only good for level-0 elements, but we now
1167 // support keeping interior_parent() valid on refined boundary
1168 // elements.
1169 // if (this->level() != 0)
1170 // return this->parent()->interior_parent();
1171
1172 // We store the interior_parent pointer after both the parent
1173 // neighbor and neighbor pointers
1174 Elem * interior_p = _elemlinks[1+this->n_sides()];
1175
1176 // If we have an interior_parent, we USED TO assume it was a
1177 // one-higher-dimensional interior element, but we now allow e.g.
1178 // edge elements to have a 3D interior_parent with no
1179 // intermediate 2D element.
1180 // libmesh_assert (!interior_p ||
1181 // interior_p->dim() == (this->dim()+1));
1182 libmesh_assert (!interior_p ||
1183 (interior_p == remote_elem) ||
1184 (interior_p->dim() > this->dim()));
1185
1186 // If an element in a multi-dimensional mesh has an interior_parent
1187 // link, it should be at our level or coarser, just like a neighbor
1188 // link. Our collect_families() code relies on this, but it might
1189 // be tempting for users to manually assign something that breaks
1190 // it.
1191 //
1192 // However, we *also* create temporary side elements, and we don't
1193 // bother with creating ancestors for those, so they can be at level
1194 // 0 even when they're sides of non-level-0 elements.
1195 libmesh_assert (!interior_p ||
1196 (interior_p->level() <= this->level()) ||
1197 (this->level() == 0 &&
1198 this->id() == DofObject::invalid_id));
1199
1200 return interior_p;
1201}
1202
1203
1204
1206{
1207 // See the const version for comments
1208 if (this->dim() >= LIBMESH_DIM)
1209 return nullptr;
1210
1211 Elem * interior_p = _elemlinks[1+this->n_sides()];
1212
1213 libmesh_assert (!interior_p ||
1214 (interior_p == remote_elem) ||
1215 (interior_p->dim() > this->dim()));
1216
1217 return interior_p;
1218}
1219
1220
1221
1223{
1224 // interior parents make no sense for full-dimensional elements.
1225 libmesh_assert (!p ||
1226 this->dim() < LIBMESH_DIM);
1227
1228 // If we have an interior_parent, we USED TO assume it was a
1229 // one-higher-dimensional interior element, but we now allow e.g.
1230 // edge elements to have a 3D interior_parent with no
1231 // intermediate 2D element.
1232 // libmesh_assert (!p ||
1233 // p->dim() == (this->dim()+1));
1234 libmesh_assert (!p ||
1235 (p == remote_elem) ||
1236 (p->dim() > this->dim()));
1237
1238 _elemlinks[1+this->n_sides()] = p;
1239}
1240
1241
1242
1243#ifdef LIBMESH_ENABLE_PERIODIC
1244
1245Elem * Elem::topological_neighbor (const unsigned int i,
1246 MeshBase & mesh,
1247 const PointLocatorBase & point_locator,
1248 const PeriodicBoundaries * pb)
1249{
1250 libmesh_assert_less (i, this->n_neighbors());
1251
1252 Elem * neighbor_i = this->neighbor_ptr(i);
1253 if (neighbor_i != nullptr)
1254 return neighbor_i;
1255
1256 if (pb)
1257 {
1258 // Since the neighbor is nullptr it must be on a boundary. We need
1259 // see if this is a periodic boundary in which case it will have a
1260 // topological neighbor
1261 std::vector<boundary_id_type> bc_ids;
1262 mesh.get_boundary_info().boundary_ids(this, cast_int<unsigned short>(i), bc_ids);
1263 for (const auto & id : bc_ids)
1264 if (pb->boundary(id))
1265 {
1266 // Since the point locator inside of periodic boundaries
1267 // returns a const pointer we will retrieve the proper
1268 // pointer directly from the mesh object.
1269 const Elem * const cn = pb->neighbor(id, point_locator, this, i);
1270 neighbor_i = const_cast<Elem *>(cn);
1271
1272 // Since coarse elements do not have more refined
1273 // neighbors we need to make sure that we don't return one
1274 // of these types of neighbors.
1275 if (neighbor_i)
1276 while (level() < neighbor_i->level())
1277 neighbor_i = neighbor_i->parent();
1278 return neighbor_i;
1279 }
1280 }
1281
1282 return nullptr;
1283}
1284
1285
1286
1287const Elem * Elem::topological_neighbor (const unsigned int i,
1288 const MeshBase & mesh,
1289 const PointLocatorBase & point_locator,
1290 const PeriodicBoundaries * pb) const
1291{
1292 libmesh_assert_less (i, this->n_neighbors());
1293
1294 const Elem * neighbor_i = this->neighbor_ptr(i);
1295 if (neighbor_i != nullptr)
1296 return neighbor_i;
1297
1298 if (pb)
1299 {
1300 // Since the neighbor is nullptr it must be on a boundary. We need
1301 // see if this is a periodic boundary in which case it will have a
1302 // topological neighbor
1303 std::vector<boundary_id_type> bc_ids;
1304 mesh.get_boundary_info().boundary_ids(this, cast_int<unsigned short>(i), bc_ids);
1305 for (const auto & id : bc_ids)
1306 if (pb->boundary(id))
1307 {
1308 neighbor_i = pb->neighbor(id, point_locator, this, i);
1309
1310 // Since coarse elements do not have more refined
1311 // neighbors we need to make sure that we don't return one
1312 // of these types of neighbors.
1313 if (neighbor_i)
1314 while (level() < neighbor_i->level())
1315 neighbor_i = neighbor_i->parent();
1316 return neighbor_i;
1317 }
1318 }
1319
1320 return nullptr;
1321}
1322
1323
1325 const MeshBase & mesh,
1326 const PointLocatorBase & point_locator,
1327 const PeriodicBoundaries * pb) const
1328{
1329 // First see if this is a normal "interior" neighbor
1330 if (has_neighbor(elem))
1331 return true;
1332
1333 for (auto n : this->side_index_range())
1334 if (this->topological_neighbor(n, mesh, point_locator, pb))
1335 return true;
1336
1337 return false;
1338}
1339
1340
1341#endif
1342
1343#ifndef NDEBUG
1344
1346{
1347 libmesh_assert(this->valid_id());
1348 for (auto n : this->node_index_range())
1349 {
1350 libmesh_assert(this->node_ptr(n));
1351 libmesh_assert(this->node_ptr(n)->valid_id());
1352 }
1353}
1354
1355
1356
1358{
1359 for (auto n : this->side_index_range())
1360 {
1361 const Elem * neigh = this->neighbor_ptr(n);
1362
1363 // Any element might have a remote neighbor; checking
1364 // to make sure that's not inaccurate is tough.
1365 if (neigh == remote_elem)
1366 continue;
1367
1368 if (neigh)
1369 {
1370 // Only subactive elements have subactive neighbors
1371 libmesh_assert (this->subactive() || !neigh->subactive());
1372
1373 const Elem * elem = this;
1374
1375 // If we're subactive but our neighbor isn't, its
1376 // return neighbor link will be to our first active
1377 // ancestor OR to our inactive ancestor of the same
1378 // level as neigh,
1379 if (this->subactive() && !neigh->subactive())
1380 {
1381 for (elem = this; !elem->active();
1382 elem = elem->parent())
1383 libmesh_assert(elem);
1384 }
1385 else
1386 {
1387 unsigned int rev = neigh->which_neighbor_am_i(elem);
1388 libmesh_assert_less (rev, neigh->n_neighbors());
1389
1390 if (this->subactive() && !neigh->subactive())
1391 {
1392 while (neigh->neighbor_ptr(rev) != elem)
1393 {
1394 libmesh_assert(elem->parent());
1395 elem = elem->parent();
1396 }
1397 }
1398 else
1399 {
1400 const Elem * nn = neigh->neighbor_ptr(rev);
1401 libmesh_assert(nn);
1402
1403 for (; elem != nn; elem = elem->parent())
1404 libmesh_assert(elem);
1405 }
1406 }
1407 }
1408 // If we don't have a neighbor and we're not subactive, our
1409 // ancestors shouldn't have any neighbors in this same
1410 // direction.
1411 else if (!this->subactive())
1412 {
1413 const Elem * my_parent = this->parent();
1414 if (my_parent &&
1415 // A parent with a different dimension isn't really one of
1416 // our ancestors, it means we're on a boundary mesh and this
1417 // is an interior mesh element for which we're on a side.
1418 // Nothing to test for in that case.
1419 (my_parent->dim() == this->dim()))
1420 libmesh_assert (!my_parent->neighbor_ptr(n));
1421 }
1422 }
1423}
1424
1425#endif // !NDEBUG
1426
1427
1428
1429void Elem::make_links_to_me_local(unsigned int n, unsigned int nn)
1430{
1431 Elem * neigh = this->neighbor_ptr(n);
1432
1433 // Don't bother calling this function unless it's necessary
1434 libmesh_assert(neigh);
1435 libmesh_assert(!neigh->is_remote());
1436
1437 const unsigned int this_level = this->level();
1438 const unsigned int neigh_level = neigh->level();
1439
1440 // We never have neighbors more refined than us
1441 libmesh_assert_less_equal (neigh_level, this_level);
1442
1443 // We never have subactive neighbors of non subactive elements
1444 libmesh_assert(!neigh->subactive() || this->subactive());
1445
1446 // If we have a neighbor less refined than us then it must not
1447 // have any more refined descendants we could have pointed to
1448 // instead.
1449 libmesh_assert((neigh_level == this_level) ||
1450 (neigh->active() && !this->subactive()) ||
1451 (!neigh->has_children() && this->subactive()));
1452
1453 // What side of neigh are we on? nn.
1454 //
1455 // We can't use the usual Elem method because we're in the middle of
1456 // restoring topology. We can't compare side_ptr nodes because
1457 // users want to abuse neighbor_ptr to point to
1458 // not-technically-neighbors across mesh slits. We can't compare
1459 // node locations because users want to move those
1460 // not-technically-neighbors until they're
1461 // not-even-geometrically-neighbors.
1462
1463 // Find any elements that might need to point to elem
1464 std::vector<Elem *> neigh_family;
1465#ifdef LIBMESH_ENABLE_AMR
1466 neigh->total_family_tree_by_side(neigh_family, nn);
1467#else
1468 neigh_family.push_back(neigh);
1469#endif
1470
1471 // Pull objects out of the loop to reduce heap operations
1472 std::unique_ptr<Elem> my_side, neigh_side;
1473
1474 // And point them to elem
1475 for (auto & neigh_family_member : neigh_family)
1476 {
1477 // Only subactive elements point to other subactive elements
1478 const bool member_subactive = neigh_family_member->subactive();
1479 if (this->subactive() && !member_subactive)
1480 continue;
1481
1482 // neigh (and possibly some of its family) might be at a lower
1483 // level than us, with a neighbor at that lower level. We
1484 // would exit early if neigh was at a lower level, except we do
1485 // want to handle neighbor links from subactive descendents.
1486 const unsigned int member_level = neigh_family_member->level();
1487 if (member_level < this_level)
1488 continue;
1489
1490 // Ideally, the neighbor link ought to either be correct
1491 // already or ought to be to remote_elem.
1492 //
1493 // However, if we're redistributing a newly created elem,
1494 // after an AMR step but before find_neighbors has fixed up
1495 // neighbor links, we might have an out of date neighbor
1496 // link to elem's parent instead.
1497#ifdef LIBMESH_ENABLE_AMR
1498 libmesh_assert((neigh_family_member->neighbor_ptr(nn) &&
1499 (neigh_family_member->neighbor_ptr(nn)->active() ||
1500 this->is_ancestor_of(neigh_family_member->neighbor_ptr(nn)) ||
1501 neigh_family_member->neighbor_ptr(nn)->is_ancestor_of(this))) ||
1502 (neigh_family_member->neighbor_ptr(nn) == remote_elem) ||
1503 ((this->refinement_flag() == JUST_REFINED) &&
1504 (this->parent() != nullptr) &&
1505 (neigh_family_member->neighbor_ptr(nn) == this->parent())));
1506#else
1507 libmesh_assert((neigh_family_member->neighbor_ptr(nn) == this) ||
1508 (neigh_family_member->neighbor_ptr(nn) == remote_elem));
1509#endif
1510
1511 // Some of neigh's family might be at a higher (finer) level
1512 // than us, and might need to point back to one of our children
1513 // rather than to us.
1514 if (member_level > this_level)
1515 {
1516 if (this->ancestor())
1517 continue;
1518
1519 if (member_subactive && this->has_children())
1520 continue;
1521 }
1522
1523 // If neigh is at a coarser level than us, some of neigh's
1524 // subactive family just won't line up with us!
1525 if (neigh_level < this_level &&
1526 member_level > neigh_level)
1527 {
1528 libmesh_assert(member_subactive);
1529
1530 this->side_ptr(my_side, n);
1531 neigh_family_member->side_ptr(neigh_side, nn);
1532
1533 if (*my_side != *neigh_side)
1534 continue;
1535 }
1536
1537 neigh_family_member->set_neighbor(nn, this);
1538 }
1539}
1540
1541
1543{
1544 libmesh_assert_not_equal_to (this, remote_elem);
1545
1546 // We need to have handled any children first
1547#if defined(LIBMESH_ENABLE_AMR) && defined(DEBUG)
1548 if (this->has_children())
1549 for (auto & child : this->child_ref_range())
1550 libmesh_assert_equal_to (&child, remote_elem);
1551#endif
1552
1553 // Remotify any neighbor links
1554 for (auto neigh : this->neighbor_ptr_range())
1555 {
1556 if (neigh && neigh != remote_elem)
1557 {
1558 // My neighbor should never be more refined than me; my real
1559 // neighbor would have been its parent in that case.
1560 libmesh_assert_greater_equal (this->level(), neigh->level());
1561
1562 if (this->level() == neigh->level() &&
1563 neigh->has_neighbor(this))
1564 {
1565#ifdef LIBMESH_ENABLE_AMR
1566 // My neighbor may have descendants which also consider me a
1567 // neighbor
1568 std::vector<Elem *> family;
1569 neigh->total_family_tree_by_neighbor (family, this);
1570
1571 // FIXME - There's a lot of ugly const_casts here; we
1572 // may want to make remote_elem non-const
1573 for (auto & n : family)
1574 {
1575 libmesh_assert (n);
1576 if (n == remote_elem)
1577 continue;
1578 unsigned int my_s = n->which_neighbor_am_i(this);
1579 libmesh_assert_less (my_s, n->n_neighbors());
1580 libmesh_assert_equal_to (n->neighbor_ptr(my_s), this);
1581 n->set_neighbor(my_s, const_cast<RemoteElem *>(remote_elem));
1582 }
1583#else
1584 unsigned int my_s = neigh->which_neighbor_am_i(this);
1585 libmesh_assert_less (my_s, neigh->n_neighbors());
1586 libmesh_assert_equal_to (neigh->neighbor_ptr(my_s), this);
1587 neigh->set_neighbor(my_s, const_cast<RemoteElem *>(remote_elem));
1588#endif
1589 }
1590#ifdef LIBMESH_ENABLE_AMR
1591 // Even if my neighbor doesn't link back to me, it might
1592 // have subactive descendants which do
1593 else if (neigh->has_children())
1594 {
1595 // If my neighbor at the same level doesn't have me as a
1596 // neighbor, I must be subactive
1597 libmesh_assert(this->level() > neigh->level() ||
1598 this->subactive());
1599
1600 // My neighbor must have some ancestor of mine as a
1601 // neighbor
1602 Elem * my_ancestor = this->parent();
1603 libmesh_assert(my_ancestor);
1604 while (!neigh->has_neighbor(my_ancestor))
1605 {
1606 my_ancestor = my_ancestor->parent();
1607 libmesh_assert(my_ancestor);
1608 }
1609
1610 // My neighbor may have descendants which consider me a
1611 // neighbor
1612 std::vector<Elem *> family;
1613 neigh->total_family_tree_by_subneighbor (family, my_ancestor, this);
1614
1615 for (auto & n : family)
1616 {
1617 libmesh_assert (n);
1618 if (n->is_remote())
1619 continue;
1620 unsigned int my_s = n->which_neighbor_am_i(this);
1621 libmesh_assert_less (my_s, n->n_neighbors());
1622 libmesh_assert_equal_to (n->neighbor_ptr(my_s), this);
1623 // TODO: we may want to make remote_elem non-const.
1624 n->set_neighbor(my_s, const_cast<RemoteElem *>(remote_elem));
1625 }
1626 }
1627#endif
1628 }
1629 }
1630
1631#ifdef LIBMESH_ENABLE_AMR
1632 // Remotify parent's child link
1633 Elem * my_parent = this->parent();
1634 if (my_parent &&
1635 // As long as it's not already remote
1636 my_parent != remote_elem &&
1637 // And it's a real parent, not an interior parent
1638 this->dim() == my_parent->dim())
1639 {
1640 unsigned int me = my_parent->which_child_am_i(this);
1641 libmesh_assert_equal_to (my_parent->child_ptr(me), this);
1642 my_parent->set_child(me, const_cast<RemoteElem *>(remote_elem));
1643 }
1644#endif
1645}
1646
1647
1649{
1650 libmesh_assert_not_equal_to (this, remote_elem);
1651
1652 // We need to have handled any children first
1653#ifdef LIBMESH_ENABLE_AMR
1654 libmesh_assert (!this->has_children());
1655#endif
1656
1657 // Nullify any neighbor links
1658 for (auto neigh : this->neighbor_ptr_range())
1659 {
1660 if (neigh && neigh != remote_elem)
1661 {
1662 // My neighbor should never be more refined than me; my real
1663 // neighbor would have been its parent in that case.
1664 libmesh_assert_greater_equal (this->level(), neigh->level());
1665
1666 if (this->level() == neigh->level() &&
1667 neigh->has_neighbor(this))
1668 {
1669#ifdef LIBMESH_ENABLE_AMR
1670 // My neighbor may have descendants which also consider me a
1671 // neighbor
1672 std::vector<Elem *> family;
1673 neigh->total_family_tree_by_neighbor (family, this);
1674
1675 for (auto & n : family)
1676 {
1677 libmesh_assert (n);
1678 if (n->is_remote())
1679 continue;
1680 unsigned int my_s = n->which_neighbor_am_i(this);
1681 libmesh_assert_less (my_s, n->n_neighbors());
1682 libmesh_assert_equal_to (n->neighbor_ptr(my_s), this);
1683 n->set_neighbor(my_s, nullptr);
1684 }
1685#else
1686 unsigned int my_s = neigh->which_neighbor_am_i(this);
1687 libmesh_assert_less (my_s, neigh->n_neighbors());
1688 libmesh_assert_equal_to (neigh->neighbor_ptr(my_s), this);
1689 neigh->set_neighbor(my_s, nullptr);
1690#endif
1691 }
1692#ifdef LIBMESH_ENABLE_AMR
1693 // Even if my neighbor doesn't link back to me, it might
1694 // have subactive descendants which do
1695 else if (neigh->has_children())
1696 {
1697 // If my neighbor at the same level doesn't have me as a
1698 // neighbor, I must be subactive
1699 libmesh_assert(this->level() > neigh->level() ||
1700 this->subactive());
1701
1702 // My neighbor must have some ancestor of mine as a
1703 // neighbor
1704 Elem * my_ancestor = this->parent();
1705 libmesh_assert(my_ancestor);
1706 while (!neigh->has_neighbor(my_ancestor))
1707 {
1708 my_ancestor = my_ancestor->parent();
1709 libmesh_assert(my_ancestor);
1710 }
1711
1712 // My neighbor may have descendants which consider me a
1713 // neighbor
1714 std::vector<Elem *> family;
1715 neigh->total_family_tree_by_subneighbor (family, my_ancestor, this);
1716
1717 for (auto & n : family)
1718 {
1719 libmesh_assert (n);
1720 if (n->is_remote())
1721 continue;
1722 unsigned int my_s = n->which_neighbor_am_i(this);
1723 libmesh_assert_less (my_s, n->n_neighbors());
1724 libmesh_assert_equal_to (n->neighbor_ptr(my_s), this);
1725 n->set_neighbor(my_s, nullptr);
1726 }
1727 }
1728#endif
1729 }
1730 }
1731
1732#ifdef LIBMESH_ENABLE_AMR
1733 // We can't currently delete a child with a parent!
1734 libmesh_assert (!this->parent());
1735#endif
1736}
1737
1738
1739
1740void Elem::write_connectivity (std::ostream & out_stream,
1741 const IOPackage iop) const
1742{
1743 libmesh_assert (out_stream.good());
1745 libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
1746
1747 switch (iop)
1748 {
1749 case TECPLOT:
1750 {
1751 // This connectivity vector will be used repeatedly instead
1752 // of being reconstructed inside the loop.
1753 std::vector<dof_id_type> conn;
1754 for (auto sc : make_range(this->n_sub_elem()))
1755 {
1756 this->connectivity(sc, TECPLOT, conn);
1757
1758 std::copy(conn.begin(),
1759 conn.end(),
1760 std::ostream_iterator<dof_id_type>(out_stream, " "));
1761
1762 out_stream << '\n';
1763 }
1764 return;
1765 }
1766
1767 case UCD:
1768 {
1769 for (auto i : this->node_index_range())
1770 out_stream << this->node_id(i)+1 << "\t";
1771
1772 out_stream << '\n';
1773 return;
1774 }
1775
1776 default:
1777 libmesh_error_msg("Unsupported IO package " << iop);
1778 }
1779}
1780
1781
1782
1784{
1785 switch (q)
1786 {
1787 // Return the maximum ratio of edge lengths, or zero if that
1788 // maximum would otherwise be infinity.
1789 case EDGE_LENGTH_RATIO:
1790 {
1791 if (this->dim() < 2)
1792 return 1;
1793
1794 std::vector<Real> edge_lengths(this->n_edges());
1795 for (auto e : index_range(edge_lengths))
1796 edge_lengths[e] = (this->point(this->local_edge_node(e,1)) -
1797 this->point(this->local_edge_node(e,0))).norm();
1798
1799 auto [min, max] =
1800 std::minmax_element(edge_lengths.begin(), edge_lengths.end());
1801
1802 if (*min == 0.)
1803 return 0.;
1804 else
1805 return *max / *min;
1806 }
1807
1808 case MIN_ANGLE:
1809 case MAX_ANGLE:
1810 {
1811 // 1D elements don't have interior angles, so just return some
1812 // dummy value in that case.
1813 if (this->dim() < 2)
1814 return 0.;
1815
1816 // Initialize return values
1817 Real min_angle = std::numeric_limits<Real>::max();
1818 Real max_angle = -std::numeric_limits<Real>::max();
1819
1820 for (auto n : this->node_index_range())
1821 {
1822 // Get list of edge ids adjacent to this node.
1823 const auto adjacent_edge_ids = this->edges_adjacent_to_node(n);
1824
1825 // Skip any nodes with fewer than 2 adjacent edges. You
1826 // need at least two adjacent edges to form an interior
1827 // element angle.
1828 auto N = adjacent_edge_ids.size();
1829 if (N < 2)
1830 continue;
1831
1832 // Consider all possible pairs of edges adjacent to node n
1833 for (unsigned int first = 0; first < N-1; ++first)
1834 for (unsigned int second = first+1; second < N; ++second)
1835 {
1836 // Get ids of first and second edges
1837 auto first_edge = adjacent_edge_ids[first];
1838 auto second_edge = adjacent_edge_ids[second];
1839
1840 // Get node ids of first and second edge
1841 auto first_edge_node_0 = this->local_edge_node(first_edge, 0);
1842 auto first_edge_node_1 = this->local_edge_node(first_edge, 1);
1843 auto second_edge_node_0 = this->local_edge_node(second_edge, 0);
1844 auto second_edge_node_1 = this->local_edge_node(second_edge, 1);
1845
1846 // Orient both edges so that edge node 0 == n
1847 if (first_edge_node_0 != n)
1848 std::swap(first_edge_node_0, first_edge_node_1);
1849 if (second_edge_node_0 != n)
1850 std::swap(second_edge_node_0, second_edge_node_1);
1851
1852 libmesh_assert_equal_to(first_edge_node_0, n);
1853 libmesh_assert_equal_to(second_edge_node_0, n);
1854
1855 // Locally oriented edge vectors
1856 Point
1857 first_ev = this->point(first_edge_node_1) - this->point(first_edge_node_0),
1858 second_ev = this->point(second_edge_node_1) - this->point(second_edge_node_0);
1859
1860 // Angle between them in the range [0, pi]
1861 Real theta = std::acos(first_ev.unit() * second_ev.unit());
1862
1863 // Track min and max angles seen
1864 min_angle = std::min(theta, min_angle);
1865 max_angle = std::max(theta, max_angle);
1866 }
1867 }
1868
1869 // Return requested extreme value (in degrees)
1870 return Real(180)/libMesh::pi * ((q == MIN_ANGLE) ? min_angle : max_angle);
1871 }
1872
1873 case MIN_DIHEDRAL_ANGLE:
1874 case MAX_DIHEDRAL_ANGLE:
1875 {
1876 // For 1D and 2D elements, just call this function with MIN,MAX_ANGLE instead.
1877 if (this->dim() < 3)
1878 return this->quality((q == MIN_DIHEDRAL_ANGLE) ? MIN_ANGLE : MAX_ANGLE);
1879
1880 // Initialize return values
1881 Real min_angle = std::numeric_limits<Real>::max();
1882 Real max_angle = -std::numeric_limits<Real>::max();
1883
1884 // Algorithm for computing dihedral angles:
1885 // .) Loop over the edges, use the edge_sides_map to get the
1886 // two sides adjacent to the edge.
1887 // .) For each adjacent side, use the side_nodes_map to get the
1888 // list of three (or more) node ids on that side.
1889 // .) Use the node ids to compute the (approximate) inward
1890 // normal for the side. Note: this is approximate since 3D
1891 // elements with four-sided faces and quadratic tetrahedra
1892 // do not necessarily have planar faces.
1893 // .) Compute the dihedral angle for the current edge, compare
1894 // it to the current min and max dihedral angles.
1895 for (auto e : this->edge_index_range())
1896 {
1897 // Get list of edge ids adjacent to this node.
1898 const auto adjacent_side_ids = this->sides_on_edge(e);
1899
1900 // All 3D elements should have exactly two sides adjacent to each edge.
1901 libmesh_assert_equal_to(adjacent_side_ids.size(), 2);
1902
1903 // Get lists of node ids on each side
1904 const auto side_0_node_ids = this->nodes_on_side(adjacent_side_ids[0]);
1905 const auto side_1_node_ids = this->nodes_on_side(adjacent_side_ids[1]);
1906
1907 // All 3D elements have at least three nodes on each side
1908 libmesh_assert_greater_equal(side_0_node_ids.size(), 3);
1909 libmesh_assert_greater_equal(side_1_node_ids.size(), 3);
1910
1911 // Construct (approximate) inward normal on each adjacent side
1912 const auto side_0_normal =
1913 (this->point(side_0_node_ids[2]) - this->point(side_0_node_ids[0])).cross
1914 (this->point(side_0_node_ids[1]) - this->point(side_0_node_ids[0])).unit();
1915 const auto side_1_normal =
1916 (this->point(side_1_node_ids[2]) - this->point(side_1_node_ids[0])).cross
1917 (this->point(side_1_node_ids[1]) - this->point(side_1_node_ids[0])).unit();
1918
1919 // Compute dihedral angle between the planes.
1920 // Using the absolute value ensures that we get the same result
1921 // even if the orientation of one of the planes is flipped, i.e.
1922 // it always gives us a value in the range [0, pi/2].
1923 // https://en.wikipedia.org/wiki/Dihedral_angle
1924 Real theta = std::acos(std::abs(side_0_normal * side_1_normal));
1925
1926 // Track min and max angles seen
1927 min_angle = std::min(theta, min_angle);
1928 max_angle = std::max(theta, max_angle);
1929 }
1930
1931 // Return requested extreme value (in degrees)
1932 return Real(180)/libMesh::pi * ((q == MIN_DIHEDRAL_ANGLE) ? min_angle : max_angle);
1933 }
1934
1935 case JACOBIAN:
1936 case SCALED_JACOBIAN:
1937 {
1938 // 1D elements don't have interior corners, so this metric
1939 // does not really apply to them.
1940 const auto N = this->dim();
1941 if (N < 2)
1942 return 1.;
1943
1944 // Initialize return value
1945 Real min_node_area = std::numeric_limits<Real>::max();
1946
1947 for (auto n : this->node_index_range())
1948 {
1949 // Get list of edge ids adjacent to this node.
1950 auto adjacent_edge_ids = this->edges_adjacent_to_node(n);
1951
1952 // Skip any nodes that don't have dim() adjacent edges. In 2D,
1953 // you need at least two adjacent edges to compute the cross
1954 // product, and in 3D, you need at least three adjacent edges
1955 // to compute the scalar triple product. The only element
1956 // type which has an unusual topology in this regard is the
1957 // Pyramid element in 3D, where 4 edges meet at the apex node.
1958 // For now, we just skip this node when computing the JACOBIAN
1959 // metric for Pyramids.
1960 if (adjacent_edge_ids.size() != N)
1961 continue;
1962
1963 // Construct oriented edges
1964 std::vector<Point> oriented_edges(N);
1965 for (auto i : make_range(N))
1966 {
1967 auto node_0 = this->local_edge_node(adjacent_edge_ids[i], 0);
1968 auto node_1 = this->local_edge_node(adjacent_edge_ids[i], 1);
1969 if (node_0 != n)
1970 std::swap(node_0, node_1);
1971 oriented_edges[i] = this->point(node_1) - this->point(node_0);
1972 }
1973
1974 // Compute unscaled area (2D) or volume (3D) using the
1975 // cross product (2D) or scalar triple product (3D) of the
1976 // oriented edges. We take the absolute value so that we
1977 // don't have to worry about the sign of the area.
1978 Real node_area = (N == 2) ?
1979 cross_norm(oriented_edges[0], oriented_edges[1]) :
1980 std::abs(triple_product(oriented_edges[0], oriented_edges[1], oriented_edges[2]));
1981
1982 // Divide by (non-zero) edge lengths if computing scaled Jacobian.
1983 // If any length is zero, then set node_area to zero. This means that
1984 // e.g. degenerate quadrilaterals will have a zero SCALED_JACOBIAN metric.
1985 if (q == SCALED_JACOBIAN)
1986 for (auto i : make_range(N))
1987 {
1988 Real len_i = oriented_edges[i].norm();
1989 node_area = (len_i == 0.) ? 0. : (node_area / len_i);
1990 }
1991
1992 // Update minimum
1993 min_node_area = std::min(node_area, min_node_area);
1994 }
1995
1996 return min_node_area;
1997 }
1998
1999 // Return 1 if we made it here
2000 default:
2001 {
2002 libmesh_do_once( libmesh_here();
2003
2004 libMesh::err << "ERROR: quality metric "
2006 << " not implemented on element type "
2007 << Utility::enum_to_string(this->type())
2008 << std::endl
2009 << "Returning 1."
2010 << std::endl; );
2011
2012 return 1.;
2013 }
2014 }
2015}
2016
2017
2018
2019bool Elem::ancestor() const
2020{
2021#ifdef LIBMESH_ENABLE_AMR
2022
2023 // Use a fast, DistributedMesh-safe definition
2024 const bool is_ancestor =
2025 !this->active() && !this->subactive();
2026
2027 // But check for inconsistencies if we have time
2028#ifdef DEBUG
2029 if (!is_ancestor && this->has_children())
2030 {
2031 for (auto & c : this->child_ref_range())
2032 {
2033 if (&c != remote_elem)
2034 {
2035 libmesh_assert(!c.active());
2036 libmesh_assert(!c.ancestor());
2037 }
2038 }
2039 }
2040#endif // DEBUG
2041
2042 return is_ancestor;
2043
2044#else
2045 return false;
2046#endif
2047}
2048
2049
2050
2051#ifdef LIBMESH_ENABLE_AMR
2052
2054{
2055 const unsigned int nc = this->n_children();
2056
2057 if (!_children)
2058 {
2059 _children = std::make_unique<Elem *[]>(nc);
2060
2061 for (unsigned int c = 0; c != nc; c++)
2062 this->set_child(c, nullptr);
2063 }
2064
2065 for (unsigned int c = 0; c != nc; c++)
2066 {
2067 if (this->_children[c] == nullptr || this->_children[c] == remote_elem)
2068 {
2069 libmesh_assert_equal_to (this, elem->parent());
2070 this->set_child(c, elem);
2071 return;
2072 }
2073 }
2074
2075 libmesh_error_msg("Error: Tried to add a child to an element with full children array");
2076}
2077
2078
2079
2080void Elem::add_child (Elem * elem, unsigned int c)
2081{
2082 if (!this->has_children())
2083 {
2084 const unsigned int nc = this->n_children();
2085 _children = std::make_unique<Elem *[]>(nc);
2086
2087 for (unsigned int i = 0; i != nc; i++)
2088 this->set_child(i, nullptr);
2089 }
2090
2091 libmesh_assert (this->_children[c] == nullptr || this->child_ptr(c) == remote_elem);
2092 libmesh_assert (elem == remote_elem || this == elem->parent());
2093
2094 this->set_child(c, elem);
2095}
2096
2097
2098
2099void Elem::replace_child (Elem * elem, unsigned int c)
2100{
2102
2103 libmesh_assert(this->child_ptr(c));
2104
2105 this->set_child(c, elem);
2106}
2107
2108
2109
2110void Elem::family_tree (std::vector<const Elem *> & family,
2111 bool reset) const
2112{
2113 ElemInternal::family_tree(this, family, reset);
2114}
2115
2116
2117
2118void Elem::family_tree (std::vector<Elem *> & family,
2119 bool reset)
2120{
2121 ElemInternal::family_tree(this, family, reset);
2122}
2123
2124
2125
2126void Elem::total_family_tree (std::vector<const Elem *> & family,
2127 bool reset) const
2128{
2129 ElemInternal::total_family_tree(this, family, reset);
2130}
2131
2132
2133
2134void Elem::total_family_tree (std::vector<Elem *> & family,
2135 bool reset)
2136{
2137 ElemInternal::total_family_tree(this, family, reset);
2138}
2139
2140
2141
2142void Elem::active_family_tree (std::vector<const Elem *> & active_family,
2143 bool reset) const
2144{
2145 ElemInternal::active_family_tree(this, active_family, reset);
2146}
2147
2148
2149
2150void Elem::active_family_tree (std::vector<Elem *> & active_family,
2151 bool reset)
2152{
2153 ElemInternal::active_family_tree(this, active_family, reset);
2154}
2155
2156
2157
2158void Elem::family_tree_by_side (std::vector<const Elem *> & family,
2159 unsigned int side,
2160 bool reset) const
2161{
2162 ElemInternal::family_tree_by_side(this, family, side, reset);
2163}
2164
2165
2166
2167void Elem:: family_tree_by_side (std::vector<Elem *> & family,
2168 unsigned int side,
2169 bool reset)
2170{
2171 ElemInternal::family_tree_by_side(this, family, side, reset);
2172}
2173
2174
2175
2176void Elem::total_family_tree_by_side (std::vector<const Elem *> & family,
2177 unsigned int side,
2178 bool reset) const
2179{
2180 ElemInternal::total_family_tree_by_side(this, family, side, reset);
2181}
2182
2183
2184
2185void Elem::total_family_tree_by_side (std::vector<Elem *> & family,
2186 unsigned int side,
2187 bool reset)
2188{
2189 ElemInternal::total_family_tree_by_side(this, family, side, reset);
2190}
2191
2192
2193
2194void Elem::active_family_tree_by_side (std::vector<const Elem *> & family,
2195 unsigned int side,
2196 bool reset) const
2197{
2198 ElemInternal::active_family_tree_by_side(this, family, side, reset);
2199}
2200
2201
2202
2203void Elem::active_family_tree_by_side (std::vector<Elem *> & family,
2204 unsigned int side,
2205 bool reset)
2206{
2207 ElemInternal::active_family_tree_by_side(this, family, side, reset);
2208}
2209
2210
2211
2212void Elem::family_tree_by_neighbor (std::vector<const Elem *> & family,
2213 const Elem * neighbor,
2214 bool reset) const
2215{
2216 ElemInternal::family_tree_by_neighbor(this, family, neighbor, reset);
2217}
2218
2219
2220
2221void Elem::family_tree_by_neighbor (std::vector<Elem *> & family,
2222 Elem * neighbor,
2223 bool reset)
2224{
2225 ElemInternal::family_tree_by_neighbor(this, family, neighbor, reset);
2226}
2227
2228
2229
2230void Elem::total_family_tree_by_neighbor (std::vector<const Elem *> & family,
2231 const Elem * neighbor,
2232 bool reset) const
2233{
2234 ElemInternal::total_family_tree_by_neighbor(this, family, neighbor, reset);
2235}
2236
2237
2238
2239void Elem::total_family_tree_by_neighbor (std::vector<Elem *> & family,
2240 Elem * neighbor,
2241 bool reset)
2242{
2243 ElemInternal::total_family_tree_by_neighbor(this, family, neighbor, reset);
2244}
2245
2246
2247
2248void Elem::family_tree_by_subneighbor (std::vector<const Elem *> & family,
2249 const Elem * neighbor,
2250 const Elem * subneighbor,
2251 bool reset) const
2252{
2253 ElemInternal::family_tree_by_subneighbor(this, family, neighbor, subneighbor, reset);
2254}
2255
2256
2257
2258void Elem::family_tree_by_subneighbor (std::vector<Elem *> & family,
2259 Elem * neighbor,
2260 Elem * subneighbor,
2261 bool reset)
2262{
2263 ElemInternal::family_tree_by_subneighbor(this, family, neighbor, subneighbor, reset);
2264}
2265
2266
2267
2268void Elem::total_family_tree_by_subneighbor (std::vector<const Elem *> & family,
2269 const Elem * neighbor,
2270 const Elem * subneighbor,
2271 bool reset) const
2272{
2273 ElemInternal::total_family_tree_by_subneighbor(this, family, neighbor, subneighbor, reset);
2274}
2275
2276
2277
2278void Elem::total_family_tree_by_subneighbor (std::vector<Elem *> & family,
2279 Elem * neighbor,
2280 Elem * subneighbor,
2281 bool reset)
2282{
2283 ElemInternal::total_family_tree_by_subneighbor(this, family, neighbor, subneighbor, reset);
2284}
2285
2286
2287
2288void Elem::active_family_tree_by_neighbor (std::vector<const Elem *> & family,
2289 const Elem * neighbor,
2290 bool reset) const
2291{
2292 ElemInternal::active_family_tree_by_neighbor(this, family, neighbor, reset);
2293}
2294
2295
2296
2297void Elem::active_family_tree_by_neighbor (std::vector<Elem *> & family,
2298 Elem * neighbor,
2299 bool reset)
2300{
2301 ElemInternal::active_family_tree_by_neighbor(this, family, neighbor, reset);
2302}
2303
2304
2305
2306void Elem::active_family_tree_by_topological_neighbor (std::vector<const Elem *> & family,
2307 const Elem * neighbor,
2308 const MeshBase & mesh,
2309 const PointLocatorBase & point_locator,
2310 const PeriodicBoundaries * pb,
2311 bool reset) const
2312{
2314 mesh, point_locator, pb,
2315 reset);
2316}
2317
2318
2319
2320void Elem::active_family_tree_by_topological_neighbor (std::vector<Elem *> & family,
2321 Elem * neighbor,
2322 const MeshBase & mesh,
2323 const PointLocatorBase & point_locator,
2324 const PeriodicBoundaries * pb,
2325 bool reset)
2326{
2328 mesh, point_locator, pb,
2329 reset);
2330}
2331
2332
2333bool Elem::is_child_on_edge(const unsigned int c,
2334 const unsigned int e) const
2335{
2336 libmesh_assert_less (c, this->n_children());
2337 libmesh_assert_less (e, this->n_edges());
2338
2339 std::unique_ptr<const Elem> my_edge = this->build_edge_ptr(e);
2340 std::unique_ptr<const Elem> child_edge = this->child_ptr(c)->build_edge_ptr(e);
2341
2342 // We're assuming that an overlapping child edge has the same
2343 // number and orientation as its parent
2344 return (child_edge->node_id(0) == my_edge->node_id(0) ||
2345 child_edge->node_id(1) == my_edge->node_id(1));
2346}
2347
2348
2349
2350unsigned int Elem::min_p_level_by_neighbor(const Elem * neighbor_in,
2351 unsigned int current_min) const
2352{
2353 libmesh_assert(!this->subactive());
2354 libmesh_assert(neighbor_in->active());
2355
2356 // If we're an active element this is simple
2357 if (this->active())
2358 return std::min(current_min, this->p_level());
2359
2360 libmesh_assert(has_neighbor(neighbor_in));
2361
2362 // The p_level() of an ancestor element is already the minimum
2363 // p_level() of its children - so if that's high enough, we don't
2364 // need to examine any children.
2365 if (current_min <= this->p_level())
2366 return current_min;
2367
2368 unsigned int min_p_level = current_min;
2369
2370 for (auto & c : this->child_ref_range())
2371 if (&c != remote_elem && c.has_neighbor(neighbor_in))
2372 min_p_level =
2373 c.min_p_level_by_neighbor(neighbor_in, min_p_level);
2374
2375 return min_p_level;
2376}
2377
2378
2379unsigned int Elem::min_new_p_level_by_neighbor(const Elem * neighbor_in,
2380 unsigned int current_min) const
2381{
2382 libmesh_assert(!this->subactive());
2383 libmesh_assert(neighbor_in->active());
2384
2385 // If we're an active element this is simple
2386 if (this->active())
2387 {
2388 unsigned int new_p_level = this->p_level();
2389 if (this->p_refinement_flag() == Elem::REFINE)
2390 new_p_level += 1;
2391 if (this->p_refinement_flag() == Elem::COARSEN)
2392 {
2393 libmesh_assert_greater (new_p_level, 0);
2394 new_p_level -= 1;
2395 }
2396 return std::min(current_min, new_p_level);
2397 }
2398
2399 libmesh_assert(has_neighbor(neighbor_in));
2400
2401 unsigned int min_p_level = current_min;
2402
2403 for (auto & c : this->child_ref_range())
2404 if (&c != remote_elem && c.has_neighbor(neighbor_in))
2405 min_p_level =
2406 c.min_new_p_level_by_neighbor(neighbor_in, min_p_level);
2407
2408 return min_p_level;
2409}
2410
2411
2412
2413unsigned int Elem::as_parent_node (unsigned int child,
2414 unsigned int child_node) const
2415{
2416 const unsigned int nc = this->n_children();
2417 libmesh_assert_less(child, nc);
2418
2419 // Cached return values, indexed first by embedding_matrix version,
2420 // then by child number, then by child node number.
2421 std::vector<std::vector<std::vector<signed char>>> &
2422 cached_parent_indices = this->_get_parent_indices_cache();
2423
2424 unsigned int em_vers = this->embedding_matrix_version();
2425
2426 // We may be updating the cache on one thread, and while that
2427 // happens we can't safely access the cache from other threads.
2428 Threads::spin_mutex::scoped_lock lock(parent_indices_mutex);
2429
2430 if (em_vers >= cached_parent_indices.size())
2431 cached_parent_indices.resize(em_vers+1);
2432
2433 if (child >= cached_parent_indices[em_vers].size())
2434 {
2435 const signed char nn = cast_int<signed char>(this->n_nodes());
2436
2437 cached_parent_indices[em_vers].resize(nc);
2438
2439 for (unsigned int c = 0; c != nc; ++c)
2440 {
2441 const unsigned int ncn = this->n_nodes_in_child(c);
2442 cached_parent_indices[em_vers][c].resize(ncn);
2443 for (unsigned int cn = 0; cn != ncn; ++cn)
2444 {
2445 for (signed char n = 0; n != nn; ++n)
2446 {
2447 const Real em_val = this->embedding_matrix
2448 (c, cn, n);
2449 if (em_val == 1)
2450 {
2451 cached_parent_indices[em_vers][c][cn] = n;
2452 break;
2453 }
2454
2455 if (em_val != 0)
2456 {
2457 cached_parent_indices[em_vers][c][cn] =
2458 -1;
2459 break;
2460 }
2461
2462 // We should never see an all-zero embedding matrix
2463 // row
2464 libmesh_assert_not_equal_to (n+1, nn);
2465 }
2466 }
2467 }
2468 }
2469
2470 const signed char cache_val =
2471 cached_parent_indices[em_vers][child][child_node];
2472 if (cache_val == -1)
2473 return libMesh::invalid_uint;
2474
2475 return cached_parent_indices[em_vers][child][child_node];
2476}
2477
2478
2479
2480const std::vector<std::pair<unsigned char, unsigned char>> &
2482 unsigned int child_node) const
2483{
2484 // Indexed first by embedding matrix type, then by child id, then by
2485 // child node, then by bracketing pair
2486 std::vector<std::vector<std::vector<std::vector<std::pair<unsigned char, unsigned char>>>>> &
2487 cached_bracketing_nodes = this->_get_bracketing_node_cache();
2488
2489 const unsigned int em_vers = this->embedding_matrix_version();
2490
2491 // We may be updating the cache on one thread, and while that
2492 // happens we can't safely access the cache from other threads.
2493 Threads::spin_mutex::scoped_lock lock(parent_bracketing_nodes_mutex);
2494
2495 if (cached_bracketing_nodes.size() <= em_vers)
2496 cached_bracketing_nodes.resize(em_vers+1);
2497
2498 const unsigned int nc = this->n_children();
2499
2500 // If we haven't cached the bracketing nodes corresponding to this
2501 // embedding matrix yet, let's do so now.
2502 if (cached_bracketing_nodes[em_vers].size() < nc)
2503 {
2504 // If we're a second-order element but we're not a full-order
2505 // element, then some of our bracketing nodes may not exist
2506 // except on the equivalent full-order element. Let's build an
2507 // equivalent full-order element and make a copy of its cache to
2508 // use.
2509 if (this->default_order() != FIRST &&
2510 second_order_equivalent_type(this->type(), /*full_ordered=*/ true) != this->type())
2511 {
2512 // Check that we really are the non-full-order type
2513 libmesh_assert_equal_to
2514 (second_order_equivalent_type (this->type(), false),
2515 this->type());
2516
2517 // Build the full-order type
2518 ElemType full_type =
2519 second_order_equivalent_type(this->type(), /*full_ordered=*/ true);
2520 std::unique_ptr<Elem> full_elem = Elem::build(full_type);
2521
2522 // This won't work for elements with multiple
2523 // embedding_matrix versions, but every such element is full
2524 // order anyways.
2525 libmesh_assert_equal_to(em_vers, 0);
2526
2527 // Make sure its cache has been built. We temporarily
2528 // release our mutex lock so that the inner call can
2529 // re-acquire it.
2530 lock.release();
2531 full_elem->parent_bracketing_nodes(0,0);
2532
2533 // And then we need to lock again, so that if someone *else*
2534 // grabbed our lock before we did we don't risk accessing
2535 // cached_bracketing_nodes while they're working on it.
2536 // Threading is hard.
2537 lock.acquire(parent_bracketing_nodes_mutex);
2538
2539 // Copy its cache
2540 cached_bracketing_nodes =
2541 full_elem->_get_bracketing_node_cache();
2542
2543 // Now we don't need to build the cache ourselves.
2544 return cached_bracketing_nodes[em_vers][child][child_node];
2545 }
2546
2547 cached_bracketing_nodes[em_vers].resize(nc);
2548
2549 const unsigned int nn = this->n_nodes();
2550
2551 // We have to examine each child
2552 for (unsigned int c = 0; c != nc; ++c)
2553 {
2554 const unsigned int ncn = this->n_nodes_in_child(c);
2555
2556 cached_bracketing_nodes[em_vers][c].resize(ncn);
2557
2558 // We have to examine each node in that child
2559 for (unsigned int n = 0; n != ncn; ++n)
2560 {
2561 // If this child node isn't a vertex or an infinite
2562 // child element's mid-infinite-edge node, then we need
2563 // to find bracketing nodes on the child.
2564 if (!this->is_vertex_on_child(c, n)
2565#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2566 && !this->is_mid_infinite_edge_node(n)
2567#endif
2568 )
2569 {
2570 // Use the embedding matrix to find the child node
2571 // location in parent master element space
2572 Point bracketed_pt;
2573
2574 for (unsigned int pn = 0; pn != nn; ++pn)
2575 {
2576 const Real em_val =
2577 this->embedding_matrix(c,n,pn);
2578
2579 libmesh_assert_not_equal_to (em_val, 1);
2580 if (em_val != 0.)
2581 bracketed_pt.add_scaled(this->master_point(pn), em_val);
2582 }
2583
2584 // Check each pair of nodes on the child which are
2585 // also both parent nodes
2586 for (unsigned int n1 = 0; n1 != ncn; ++n1)
2587 {
2588 if (n1 == n)
2589 continue;
2590
2591 unsigned int parent_n1 =
2592 this->as_parent_node(c,n1);
2593
2594 if (parent_n1 == libMesh::invalid_uint)
2595 continue;
2596
2597 Point p1 = this->master_point(parent_n1);
2598
2599 for (unsigned int n2 = n1+1; n2 < nn; ++n2)
2600 {
2601 if (n2 == n)
2602 continue;
2603
2604 unsigned int parent_n2 =
2605 this->as_parent_node(c,n2);
2606
2607 if (parent_n2 == libMesh::invalid_uint)
2608 continue;
2609
2610 Point p2 = this->master_point(parent_n2);
2611
2612 Point pmid = (p1 + p2)/2;
2613
2614 if (pmid == bracketed_pt)
2615 {
2616 cached_bracketing_nodes[em_vers][c][n].emplace_back(parent_n1, parent_n2);
2617 break;
2618 }
2619 else
2620 libmesh_assert(!pmid.absolute_fuzzy_equals(bracketed_pt));
2621 }
2622 }
2623 }
2624 // If this child node is a parent node, we need to
2625 // find bracketing nodes on the parent.
2626 else
2627 {
2628 unsigned int parent_node = this->as_parent_node(c,n);
2629
2630 Point bracketed_pt;
2631
2632 // If we're not a parent node, use the embedding
2633 // matrix to find the child node location in parent
2634 // master element space
2635 if (parent_node == libMesh::invalid_uint)
2636 {
2637 for (unsigned int pn = 0; pn != nn; ++pn)
2638 {
2639 const Real em_val =
2640 this->embedding_matrix(c,n,pn);
2641
2642 libmesh_assert_not_equal_to (em_val, 1);
2643 if (em_val != 0.)
2644 bracketed_pt.add_scaled(this->master_point(pn), em_val);
2645 }
2646 }
2647 // If we're a parent node then we need no arithmetic
2648 else
2649 bracketed_pt = this->master_point(parent_node);
2650
2651 for (unsigned int n1 = 0; n1 != nn; ++n1)
2652 {
2653 if (n1 == parent_node)
2654 continue;
2655
2656 Point p1 = this->master_point(n1);
2657
2658 for (unsigned int n2 = n1+1; n2 < nn; ++n2)
2659 {
2660 if (n2 == parent_node)
2661 continue;
2662
2663 Point pmid = (p1 + this->master_point(n2))/2;
2664
2665 if (pmid == bracketed_pt)
2666 {
2667 cached_bracketing_nodes[em_vers][c][n].emplace_back(n1, n2);
2668 break;
2669 }
2670 else
2671 libmesh_assert(!pmid.absolute_fuzzy_equals(bracketed_pt));
2672 }
2673 }
2674 }
2675 }
2676 }
2677 }
2678
2679 return cached_bracketing_nodes[em_vers][child][child_node];
2680}
2681
2682
2683const std::vector<std::pair<dof_id_type, dof_id_type>>
2684Elem::bracketing_nodes(unsigned int child,
2685 unsigned int child_node) const
2686{
2687 std::vector<std::pair<dof_id_type, dof_id_type>> returnval;
2688
2689 const std::vector<std::pair<unsigned char, unsigned char>> & pbc =
2690 this->parent_bracketing_nodes(child,child_node);
2691
2692 for (const auto & pb : pbc)
2693 {
2694 const unsigned short n_n = this->n_nodes();
2695 if (pb.first < n_n && pb.second < n_n)
2696 returnval.emplace_back(this->node_id(pb.first), this->node_id(pb.second));
2697 else
2698 {
2699 // We must be on a non-full-order higher order element...
2700 libmesh_assert_not_equal_to(this->default_order(), FIRST);
2701 libmesh_assert_not_equal_to
2702 (second_order_equivalent_type (this->type(), true),
2703 this->type());
2704 libmesh_assert_equal_to
2705 (second_order_equivalent_type (this->type(), false),
2706 this->type());
2707
2708 // And that's a shame, because this is a nasty search:
2709
2710 // Build the full-order type
2711 ElemType full_type =
2712 second_order_equivalent_type(this->type(), /*full_ordered=*/ true);
2713 std::unique_ptr<Elem> full_elem = Elem::build(full_type);
2714
2717
2718 // Find the bracketing nodes by figuring out what
2719 // already-created children will have them.
2720
2721 // This only doesn't break horribly because we add children
2722 // and nodes in straightforward + hierarchical orders...
2723 for (unsigned int c=0; c <= child; ++c)
2724 {
2725 libmesh_assert(this->child_ptr(c));
2726 if (this->child_ptr(c) == remote_elem)
2727 continue;
2728
2729 for (auto n : make_range(this->n_nodes_in_child(c)))
2730 {
2731 if (c == child && n == child_node)
2732 break;
2733
2734 if (pb.first == full_elem->as_parent_node(c,n))
2735 {
2736 // We should be consistent
2737 if (pt1 != DofObject::invalid_id)
2738 libmesh_assert_equal_to(pt1, this->child_ptr(c)->node_id(n));
2739
2740 pt1 = this->child_ptr(c)->node_id(n);
2741 }
2742
2743 if (pb.second == full_elem->as_parent_node(c,n))
2744 {
2745 // We should be consistent
2746 if (pt2 != DofObject::invalid_id)
2747 libmesh_assert_equal_to(pt2, this->child_ptr(c)->node_id(n));
2748
2749 pt2 = this->child_ptr(c)->node_id(n);
2750 }
2751 }
2752 }
2753
2754 // We should *usually* find all bracketing nodes by the time
2755 // we query them (again, because of the child & node add
2756 // order)
2757 //
2758 // The exception is if we're a HEX20, in which case we will
2759 // find pairs of vertex nodes and edge nodes bracketing the
2760 // new central node but we *won't* find the pairs of face
2761 // nodes which we would have had on a HEX27. In that case
2762 // we'll still have enough bracketing nodes for a
2763 // topological lookup, but we won't be able to make the
2764 // following assertions.
2765 if (this->type() != HEX20)
2766 {
2767 libmesh_assert_not_equal_to (pt1, DofObject::invalid_id);
2768 libmesh_assert_not_equal_to (pt2, DofObject::invalid_id);
2769 }
2770
2771 if (pt1 != DofObject::invalid_id &&
2772 pt2 != DofObject::invalid_id)
2773 returnval.emplace_back(pt1, pt2);
2774 }
2775 }
2776
2777 return returnval;
2778}
2779#endif // #ifdef LIBMESH_ENABLE_AMR
2780
2781
2782
2783
2784bool Elem::contains_point (const Point & p, Real tol) const
2785{
2786 // We currently allow the user to enlarge the bounding box by
2787 // providing a tol > TOLERANCE (so this routine is identical to
2788 // Elem::close_to_point()), but print a warning so that the
2789 // user can eventually switch his code over to calling close_to_point()
2790 // instead, which is intended to be used for this purpose.
2791 if (tol > TOLERANCE)
2792 {
2793 libmesh_do_once(libMesh::err
2794 << "WARNING: Resizing bounding box to match user-specified tolerance!\n"
2795 << "In the future, calls to Elem::contains_point() with tol > TOLERANCE\n"
2796 << "will be more optimized, but should not be used\n"
2797 << "to search for points 'close to' elements!\n"
2798 << "Instead, use Elem::close_to_point() for this purpose.\n"
2799 << std::endl;);
2800 return this->point_test(p, tol, tol);
2801 }
2802 else
2803 return this->point_test(p, TOLERANCE, tol);
2804}
2805
2806
2807
2808
2809bool Elem::close_to_point (const Point & p, Real tol) const
2810{
2811 // This test uses the user's passed-in tolerance for the
2812 // bounding box test as well, thereby allowing the routine to
2813 // find points which are not only "in" the element, but also
2814 // "nearby" to within some tolerance.
2815 return this->point_test(p, tol, tol);
2816}
2817
2818
2819
2820
2821bool Elem::point_test(const Point & p, Real box_tol, Real map_tol) const
2822{
2823 libmesh_assert_greater (box_tol, 0.);
2824 libmesh_assert_greater (map_tol, 0.);
2825
2826 // This is a great optimization on first order elements, but it
2827 // could return false negatives on higher orders
2828 if (this->default_order() == FIRST)
2829 {
2830 // Check to make sure the element *could* contain this point, so we
2831 // can avoid an expensive inverse_map call if it doesn't.
2832 bool
2833#if LIBMESH_DIM > 2
2834 point_above_min_z = false,
2835 point_below_max_z = false,
2836#endif
2837#if LIBMESH_DIM > 1
2838 point_above_min_y = false,
2839 point_below_max_y = false,
2840#endif
2841 point_above_min_x = false,
2842 point_below_max_x = false;
2843
2844 // For relative bounding box checks in physical space
2845 const Real my_hmax = this->hmax();
2846
2847 for (auto & n : this->node_ref_range())
2848 {
2849 point_above_min_x = point_above_min_x || (n(0) - my_hmax*box_tol <= p(0));
2850 point_below_max_x = point_below_max_x || (n(0) + my_hmax*box_tol >= p(0));
2851#if LIBMESH_DIM > 1
2852 point_above_min_y = point_above_min_y || (n(1) - my_hmax*box_tol <= p(1));
2853 point_below_max_y = point_below_max_y || (n(1) + my_hmax*box_tol >= p(1));
2854#endif
2855#if LIBMESH_DIM > 2
2856 point_above_min_z = point_above_min_z || (n(2) - my_hmax*box_tol <= p(2));
2857 point_below_max_z = point_below_max_z || (n(2) + my_hmax*box_tol >= p(2));
2858#endif
2859 }
2860
2861 if (
2862#if LIBMESH_DIM > 2
2863 !point_above_min_z ||
2864 !point_below_max_z ||
2865#endif
2866#if LIBMESH_DIM > 1
2867 !point_above_min_y ||
2868 !point_below_max_y ||
2869#endif
2870 !point_above_min_x ||
2871 !point_below_max_x)
2872 return false;
2873 }
2874
2875 // To be on the safe side, we converge the inverse_map() iteration
2876 // to a slightly tighter tolerance than that requested by the
2877 // user...
2878 const Point mapped_point = FEMap::inverse_map(this->dim(),
2879 this,
2880 p,
2881 0.1*map_tol, // <- this is |dx| tolerance, the Newton residual should be ~ |dx|^2
2882 /*secure=*/ false,
2883 /*extra_checks=*/ false);
2884
2885 // Check that the refspace point maps back to p! This is only necessary
2886 // for 1D and 2D elements, 3D elements always live in 3D.
2887 //
2888 // TODO: The contains_point() function could most likely be implemented
2889 // more efficiently in the element sub-classes themselves, at least for
2890 // the linear element types.
2891 if (this->dim() < 3)
2892 {
2893 Point xyz = FEMap::map(this->dim(), this, mapped_point);
2894
2895 // Compute the distance between the original point and the re-mapped point.
2896 // They should be in the same place.
2897 Real dist = (xyz - p).norm();
2898
2899
2900 // If dist is larger than some fraction of the tolerance, then return false.
2901 // This can happen when e.g. a 2D element is living in 3D, and
2902 // FEMap::inverse_map() maps p onto the projection of the element,
2903 // effectively "tricking" on_reference_element().
2904 if (dist > this->hmax() * map_tol)
2905 return false;
2906 }
2907
2908 return this->on_reference_element(mapped_point, map_tol);
2909}
2910
2911
2912
2913
2915{
2916 QNodal qnodal {this->dim()};
2917 FEMap fe_map;
2918 auto & jac = fe_map.get_jacobian();
2919
2920 // We have a separate check for is_singular_node() below, so in this
2921 // case its "OK" to do nodal quadrature on pyramids.
2922 qnodal.allow_nodal_pyramid_quadrature = true;
2923 qnodal.init(*this);
2924 auto & qp = qnodal.get_points();
2925 libmesh_assert_equal_to(qp.size(), this->n_nodes());
2926
2927 std::vector<Point> one_point(1);
2928 std::vector<Real> one_weight(1,1);
2929 for (auto i : index_range(qp))
2930 {
2931 if (this->is_singular_node(i))
2932 continue;
2933
2934 one_point[0] = qp[i];
2935
2936 fe_map.init_reference_to_physical_map(this->dim(), one_point, this);
2937 fe_map.compute_map(this->dim(), one_weight, this, false);
2938
2939 if (jac[0] <= 0)
2940 return false;
2941 }
2942
2943 return true;
2944}
2945
2946
2947
2948void Elem::print_info (std::ostream & os) const
2949{
2950 os << this->get_info()
2951 << std::endl;
2952}
2953
2954
2955
2956std::string Elem::get_info () const
2957{
2958 std::ostringstream oss;
2959
2960 oss << " Elem Information" << '\n'
2961 << " id()=";
2962
2963 if (this->valid_id())
2964 oss << this->id();
2965 else
2966 oss << "invalid";
2967
2968#ifdef LIBMESH_ENABLE_UNIQUE_ID
2969 oss << ", unique_id()=";
2970 if (this->valid_unique_id())
2971 oss << this->unique_id();
2972 else
2973 oss << "invalid";
2974#endif
2975
2976 oss << ", subdomain_id()=" << this->subdomain_id();
2977 oss << ", processor_id()=" << this->processor_id() << '\n';
2978
2979 oss << " type()=" << Utility::enum_to_string(this->type()) << '\n'
2980 << " dim()=" << this->dim() << '\n'
2981 << " n_nodes()=" << this->n_nodes() << '\n';
2982
2983 oss << " mapping=" << Utility::enum_to_string(this->mapping_type()) << '\n';
2984
2985 for (auto n : this->node_index_range())
2986 {
2987 oss << " " << n << this->node_ref(n);
2988 if (this->mapping_type() == RATIONAL_BERNSTEIN_MAP)
2989 {
2990 const unsigned char datum_index = this->mapping_data();
2991 oss << " weight=" <<
2992 this->node_ref(n).get_extra_datum<Real>(datum_index) << '\n';
2993 }
2994 }
2995
2996 oss << " n_sides()=" << this->n_sides() << '\n';
2997
2998 for (auto s : this->side_index_range())
2999 {
3000 oss << " neighbor(" << s << ")=";
3001 if (this->neighbor_ptr(s))
3002 oss << this->neighbor_ptr(s)->id() << '\n';
3003 else
3004 oss << "nullptr\n";
3005 }
3006
3007 if (!this->infinite())
3008 {
3009 oss << " hmin()=" << this->hmin()
3010 << ", hmax()=" << this->hmax() << '\n'
3011 << " volume()=" << this->volume() << '\n';
3012 }
3013 oss << " active()=" << this->active()
3014 << ", ancestor()=" << this->ancestor()
3015 << ", subactive()=" << this->subactive()
3016 << ", has_children()=" << this->has_children() << '\n'
3017 << " parent()=";
3018 if (this->parent())
3019 oss << this->parent()->id() << '\n';
3020 else
3021 oss << "nullptr\n";
3022 oss << " level()=" << this->level()
3023 << ", p_level()=" << this->p_level() << '\n'
3024#ifdef LIBMESH_ENABLE_AMR
3025 << " refinement_flag()=" << Utility::enum_to_string(this->refinement_flag()) << '\n'
3026 << " p_refinement_flag()=" << Utility::enum_to_string(this->p_refinement_flag()) << '\n'
3027#endif
3028#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
3029 << " infinite()=" << this->infinite() << '\n';
3030 if (this->infinite())
3031 oss << " origin()=" << this->origin() << '\n'
3032#endif
3033 ;
3034
3035 oss << " DoFs=";
3036 for (auto s : make_range(this->n_systems()))
3037 for (auto v : make_range(this->n_vars(s)))
3038 for (auto c : make_range(this->n_comp(s,v)))
3039 oss << '(' << s << '/' << v << '/' << this->dof_number(s,v,c) << ") ";
3040
3041
3042 return oss.str();
3043}
3044
3045
3046
3048{
3049 // Tell any of my neighbors about my death...
3050 // Looks strange, huh?
3051 for (auto n : this->side_index_range())
3052 {
3053 Elem * current_neighbor = this->neighbor_ptr(n);
3054 if (current_neighbor && current_neighbor != remote_elem)
3055 {
3056 // Note: it is possible that I see the neighbor
3057 // (which is coarser than me)
3058 // but they don't see me, so avoid that case.
3059 if (current_neighbor->level() == this->level())
3060 {
3061 const unsigned int w_n_a_i = current_neighbor->which_neighbor_am_i(this);
3062 libmesh_assert_less (w_n_a_i, current_neighbor->n_neighbors());
3063 current_neighbor->set_neighbor(w_n_a_i, nullptr);
3064 this->set_neighbor(n, nullptr);
3065 }
3066 }
3067 }
3068}
3069
3070
3071
3072
3073unsigned int Elem::n_second_order_adjacent_vertices (const unsigned int) const
3074{
3075 // for linear elements, always return 0
3076 return 0;
3077}
3078
3079
3080
3081unsigned short int Elem::second_order_adjacent_vertex (const unsigned int,
3082 const unsigned int) const
3083{
3084 // for linear elements, always return 0
3085 return 0;
3086}
3087
3088
3089
3090std::pair<unsigned short int, unsigned short int>
3091Elem::second_order_child_vertex (const unsigned int) const
3092{
3093 // for linear elements, always return 0
3094 return std::pair<unsigned short int, unsigned short int>(0,0);
3095}
3096
3097
3098
3100{
3101 switch (et)
3102 {
3103 case NODEELEM:
3104 return NODEELEM;
3105 case EDGE2:
3106 case EDGE3:
3107 case EDGE4:
3108 return EDGE2;
3109 case TRI3:
3110 case TRI6:
3111 case TRI7:
3112 return TRI3;
3113 case TRISHELL3:
3114 return TRISHELL3;
3115 case QUAD4:
3116 case QUAD8:
3117 case QUAD9:
3118 return QUAD4;
3119 case QUADSHELL4:
3120 case QUADSHELL8:
3121 case QUADSHELL9:
3122 return QUADSHELL4;
3123 case TET4:
3124 case TET10:
3125 case TET14:
3126 return TET4;
3127 case HEX8:
3128 case HEX27:
3129 case HEX20:
3130 return HEX8;
3131 case PRISM6:
3132 case PRISM15:
3133 case PRISM18:
3134 case PRISM20:
3135 case PRISM21:
3136 return PRISM6;
3137 case PYRAMID5:
3138 case PYRAMID13:
3139 case PYRAMID14:
3140 case PYRAMID18:
3141 return PYRAMID5;
3142
3143#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
3144
3145 case INFEDGE2:
3146 return INFEDGE2;
3147 case INFQUAD4:
3148 case INFQUAD6:
3149 return INFQUAD4;
3150 case INFHEX8:
3151 case INFHEX16:
3152 case INFHEX18:
3153 return INFHEX8;
3154 case INFPRISM6:
3155 case INFPRISM12:
3156 return INFPRISM6;
3157
3158#endif
3159
3160 default:
3161 // unknown element
3162 return INVALID_ELEM;
3163 }
3164}
3165
3166
3167
3169 const bool full_ordered)
3170{
3171 switch (et)
3172 {
3173 case NODEELEM:
3174 return NODEELEM;
3175 case EDGE2:
3176 case EDGE3:
3177 {
3178 // full_ordered not relevant
3179 return EDGE3;
3180 }
3181
3182 case EDGE4:
3183 {
3184 // full_ordered not relevant
3185 return EDGE4;
3186 }
3187
3188 case TRI3:
3189 case TRI6:
3190 {
3191 // full_ordered not relevant
3192 return TRI6;
3193 }
3194
3195 case TRI7:
3196 return TRI7;
3197
3198 // Currently there is no TRISHELL6, so similarly to other types
3199 // where this is the case, we just return the input.
3200 case TRISHELL3:
3201 return TRISHELL3;
3202
3203 case QUAD4:
3204 case QUAD8:
3205 {
3206 if (full_ordered)
3207 return QUAD9;
3208 else
3209 return QUAD8;
3210 }
3211
3212 case QUADSHELL4:
3213 case QUADSHELL8:
3214 {
3215 if (full_ordered)
3216 return QUADSHELL9;
3217 else
3218 return QUADSHELL8;
3219 }
3220
3221 case QUAD9:
3222 {
3223 // full_ordered not relevant
3224 return QUAD9;
3225 }
3226
3227 case QUADSHELL9:
3228 {
3229 // full_ordered not relevant
3230 return QUADSHELL9;
3231 }
3232
3233 case TET4:
3234 case TET10:
3235 {
3236 // full_ordered not relevant
3237 return TET10;
3238 }
3239
3240 case TET14:
3241 return TET14;
3242
3243 case HEX8:
3244 case HEX20:
3245 {
3246 // see below how this correlates with INFHEX8
3247 if (full_ordered)
3248 return HEX27;
3249 else
3250 return HEX20;
3251 }
3252
3253 case HEX27:
3254 {
3255 // full_ordered not relevant
3256 return HEX27;
3257 }
3258
3259 case PRISM6:
3260 case PRISM15:
3261 {
3262 if (full_ordered)
3263 return PRISM18;
3264 else
3265 return PRISM15;
3266 }
3267
3268 // full_ordered not relevant, already fully second order
3269 case PRISM18:
3270 return PRISM18;
3271 case PRISM20:
3272 return PRISM20;
3273 case PRISM21:
3274 return PRISM21;
3275 case PYRAMID18:
3276 return PYRAMID18;
3277
3278 case PYRAMID5:
3279 case PYRAMID13:
3280 {
3281 if (full_ordered)
3282 return PYRAMID14;
3283 else
3284 return PYRAMID13;
3285 }
3286
3287 case PYRAMID14:
3288 {
3289 // full_ordered not relevant
3290 return PYRAMID14;
3291 }
3292
3293
3294
3295#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
3296
3297 // infinite elements
3298 case INFEDGE2:
3299 {
3300 return INFEDGE2;
3301 }
3302
3303 case INFQUAD4:
3304 case INFQUAD6:
3305 {
3306 // full_ordered not relevant
3307 return INFQUAD6;
3308 }
3309
3310 case INFHEX8:
3311 case INFHEX16:
3312 {
3313 /*
3314 * Note that this matches with \p Hex8:
3315 * For full-ordered, \p InfHex18 and \p Hex27
3316 * belong together, and for not full-ordered,
3317 * \p InfHex16 and \p Hex20 belong together.
3318 */
3319 if (full_ordered)
3320 return INFHEX18;
3321 else
3322 return INFHEX16;
3323 }
3324
3325 case INFHEX18:
3326 {
3327 // full_ordered not relevant
3328 return INFHEX18;
3329 }
3330
3331 case INFPRISM6:
3332 case INFPRISM12:
3333 {
3334 // full_ordered not relevant
3335 return INFPRISM12;
3336 }
3337
3338#endif
3339
3340
3341 default:
3342 {
3343 // what did we miss?
3344 libmesh_error_msg("No second order equivalent element type for et = "
3346 }
3347 }
3348}
3349
3350
3351
3353{
3354 switch (et)
3355 {
3356 case NODEELEM:
3357 return NODEELEM;
3358 case EDGE2:
3359 case EDGE3:
3360 return EDGE3;
3361
3362 case EDGE4:
3363 return EDGE4;
3364
3365 case TRI3:
3366 case TRI6:
3367 case TRI7:
3368 return TRI7;
3369
3370 // Currently there is no TRISHELL6, so similarly to other types
3371 // where this is the case, we just return the input.
3372 case TRISHELL3:
3373 return TRISHELL3;
3374
3375 case QUAD4:
3376 case QUAD8:
3377 case QUAD9:
3378 return QUAD9;
3379
3380 case QUADSHELL4:
3381 case QUADSHELL8:
3382 case QUADSHELL9:
3383 return QUADSHELL9;
3384
3385 case TET4:
3386 case TET10:
3387 case TET14:
3388 return TET14;
3389
3390 case HEX8:
3391 case HEX20:
3392 case HEX27:
3393 return HEX27;
3394
3395 // We don't strictly need the 21st node for DoFs, but some code
3396 // depends on it for e.g. refinement patterns
3397 case PRISM6:
3398 case PRISM15:
3399 case PRISM18:
3400 case PRISM20:
3401 case PRISM21:
3402 return PRISM21;
3403
3404 case PYRAMID5:
3405 case PYRAMID13:
3406 case PYRAMID14:
3407 case PYRAMID18:
3408 return PYRAMID18;
3409
3410
3411
3412#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
3413 case INFEDGE2:
3414 return INFEDGE2;
3415
3416 case INFQUAD4:
3417 case INFQUAD6:
3418 return INFQUAD6;
3419
3420 case INFHEX8:
3421 case INFHEX16:
3422 case INFHEX18:
3423 return INFHEX18;
3424
3425 // Probably ought to implement INFPRISM13 and/or 14; until then
3426 // we'll just return the not-complete-order ElemType, in
3427 // accordance which what seems like bad precedent...
3428 case INFPRISM6:
3429 case INFPRISM12:
3430 return INFPRISM12;
3431#endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
3432
3433 default:
3434 {
3435 // what did we miss?
3436 libmesh_error_msg("No complete order equivalent element type for et = "
3438 }
3439 }
3440}
3441
3442
3443
3449
3450
3451
3452
3458
3459
3460
3461
3463{
3464 // The default implementation builds a finite element of the correct
3465 // order and sums up the JxW contributions. This can be expensive,
3466 // so the various element types can overload this method and compute
3467 // the volume more efficiently.
3468 const FEFamily mapping_family = FEMap::map_fe_type(*this);
3469 const FEType fe_type(this->default_order(), mapping_family);
3470
3471 std::unique_ptr<FEBase> fe (FEBase::build(this->dim(),
3472 fe_type));
3473
3474 // Use a map with a negative Jacobian tolerance, in case we're asked
3475 // for the net volume of a tangled element
3476 fe->get_fe_map().set_jacobian_tolerance(std::numeric_limits<Real>::lowest());
3477
3478 const std::vector<Real> & JxW = fe->get_JxW();
3479
3480 // The default quadrature rule should integrate the mass matrix,
3481 // thus it should be plenty to compute the area
3482 QGauss qrule (this->dim(), fe_type.default_quadrature_order());
3483
3484 fe->attach_quadrature_rule(&qrule);
3485
3486 fe->reinit(this);
3487
3488 Real vol=0.;
3489 for (auto jxw : JxW)
3490 vol += jxw;
3491
3492 return vol;
3493
3494}
3495
3496
3497
3499{
3500 Point pmin = this->point(0);
3501 Point pmax = pmin;
3502
3503 unsigned int n_points = this->n_nodes();
3504 for (unsigned int p=0; p != n_points; ++p)
3505 for (unsigned d=0; d<LIBMESH_DIM; ++d)
3506 {
3507 const Point & pt = this->point(p);
3508 if (pmin(d) > pt(d))
3509 pmin(d) = pt(d);
3510
3511 if (pmax(d) < pt(d))
3512 pmax(d) = pt(d);
3513 }
3514
3515 return BoundingBox(pmin, pmax);
3516}
3517
3518Point
3519Elem::side_vertex_average_normal(const unsigned int s) const
3520{
3521 unsigned int dim = this->dim();
3522 const std::unique_ptr<const Elem> face = this->build_side_ptr(s);
3523 std::unique_ptr<libMesh::FEBase> fe(
3525 fe->add_p_level_in_reinit(false); // Yes, really use the default order
3526 const std::vector<Point> & normals = fe->get_normals();
3527 std::vector<Point> ref_side_vertex_average_v = {face->reference_elem()->vertex_average()};
3528 fe->reinit(this, s, TOLERANCE, &ref_side_vertex_average_v);
3529 return normals[0];
3530}
3531
3532bool Elem::is_vertex_on_parent(unsigned int c,
3533 unsigned int n) const
3534{
3535#ifdef LIBMESH_ENABLE_AMR
3536
3537 unsigned int my_n_vertices = this->n_vertices();
3538 for (unsigned int n_parent = 0; n_parent != my_n_vertices;
3539 ++n_parent)
3540 if (this->node_ptr(n_parent) == this->child_ptr(c)->node_ptr(n))
3541 return true;
3542 return false;
3543
3544#else
3545
3546 // No AMR?
3547 libmesh_ignore(c,n);
3548 libmesh_error_msg("ERROR: AMR disabled, how did we get here?");
3549 return true;
3550
3551#endif
3552}
3553
3554
3555
3556unsigned int Elem::opposite_side(const unsigned int /*s*/) const
3557{
3558 // If the subclass didn't rederive this, using it is an error
3559 libmesh_not_implemented();
3560}
3561
3562
3563
3564unsigned int Elem::opposite_node(const unsigned int /*n*/,
3565 const unsigned int /*s*/) const
3566{
3567 // If the subclass didn't rederive this, using it is an error
3568 libmesh_not_implemented();
3569}
3570
3571
3572unsigned int Elem::center_node_on_side(const unsigned short libmesh_dbg_var(side)) const
3573{
3574 libmesh_assert_less (side, this->n_sides());
3575 return invalid_uint;
3576}
3577
3578
3579void Elem::swap2boundarysides(unsigned short s1,
3580 unsigned short s2,
3581 BoundaryInfo * boundary_info) const
3582{
3583 std::vector<boundary_id_type> ids1, ids2;
3584 boundary_info->boundary_ids(this, s1, ids1);
3585 boundary_info->boundary_ids(this, s2, ids2);
3586 boundary_info->remove_side(this, s1);
3587 boundary_info->remove_side(this, s2);
3588 if (!ids1.empty())
3589 boundary_info->add_side(this, s2, ids1);
3590 if (!ids2.empty())
3591 boundary_info->add_side(this, s1, ids2);
3592}
3593
3594
3595void Elem::swap2boundaryedges(unsigned short e1,
3596 unsigned short e2,
3597 BoundaryInfo * boundary_info) const
3598{
3599 std::vector<boundary_id_type> ids1, ids2;
3600 boundary_info->edge_boundary_ids(this, e1, ids1);
3601 boundary_info->edge_boundary_ids(this, e2, ids2);
3602 boundary_info->remove_edge(this, e1);
3603 boundary_info->remove_edge(this, e2);
3604 if (!ids1.empty())
3605 boundary_info->add_edge(this, e2, ids1);
3606 if (!ids2.empty())
3607 boundary_info->add_edge(this, e1, ids2);
3608}
3609
3610bool
3611Elem::is_internal(const unsigned int i) const
3612{
3613 switch (this->dim())
3614 {
3615 case 0:
3616 return false;
3617
3618 case 1:
3619 return !this->is_vertex(i);
3620
3621 case 2:
3622 return !this->is_vertex(i) && !this->is_edge(i);
3623
3624 case 3:
3625 return !this->is_vertex(i) && !this->is_edge(i) && !this->is_face(i);
3626
3627 default:
3628 libmesh_error_msg("impossible element dimension " << std::to_string(this->dim()));
3629 return 0;
3630 }
3631}
3632
3633bool
3634Elem::positive_edge_orientation(const unsigned int i) const
3635{
3636 libmesh_assert_less (i, this->n_edges());
3637
3638 return this->point(this->local_edge_node(i, 0)) >
3639 this->point(this->local_edge_node(i, 1));
3640}
3641
3642bool
3643Elem::positive_face_orientation(const unsigned int i) const
3644{
3645 libmesh_assert_less (i, this->n_faces());
3646
3647 // Get the number of vertices N of face i. Note that for 3d elements, i.e.
3648 // elements for which this->n_faces() > 0, the number of vertices on any of
3649 // its sides (or faces) is just the number of that face's sides (or edges).
3650 const unsigned int N = Elem::type_to_n_sides_map[this->side_type(i)];
3651
3652 const std::vector<unsigned int> nodes = this->nodes_on_side(i);
3653
3654 auto cmp = [&](const unsigned int & m, const unsigned int & n) -> bool
3655 { return this->point(m) < this->point(n); };
3656
3657 const unsigned int v = std::distance(nodes.begin(),
3658 std::min_element(nodes.begin(), nodes.begin() + N, cmp));
3659
3660 return cmp(nodes[(v - 1 + N) % N], nodes[(v + 1) % N]);
3661}
3662
3663bool
3664Elem::relative_edge_face_order(const unsigned int e, const unsigned int s) const
3665{
3666 libmesh_assert_less (e, this->n_edges());
3667 libmesh_assert_less (s, this->n_faces());
3669
3670 const unsigned int N = Elem::type_to_n_sides_map[this->side_type(s)];
3671
3672 unsigned int v;
3673 for (v = 0; v < N; v++)
3674 if (this->local_side_node(s, v) == this->local_edge_node(e, 0))
3675 break;
3676
3677 libmesh_assert (this->local_side_node(s, (v + 1) % N) ==
3678 this->local_edge_node(e, 1) ||
3679 this->local_side_node(s, (v - 1 + N) % N) ==
3680 this->local_edge_node(e, 1));
3681
3682 return this->local_side_node(s, (v + 1) % N) ==
3683 this->local_edge_node(e, 1);
3684}
3685
3686} // namespace libMesh
unsigned int n_vars
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure.
void edge_boundary_ids(const Elem *const elem, const unsigned short int edge, std::vector< boundary_id_type > &vec_to_fill) const
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
void remove_edge(const Elem *elem, const unsigned short int edge)
Removes all boundary conditions associated with edge edge of element elem, if any exist.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
void remove_side(const Elem *elem, const unsigned short int side)
Removes all boundary conditions associated with side side of element elem, if any exist.
Defines a Cartesian bounding box by the two corner extremum.
unsigned int n_systems() const
Definition dof_object.h:913
unsigned int n_comp(const unsigned int s, const unsigned int var) const
Definition dof_object.h:978
bool valid_id() const
Definition dof_object.h:861
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
unsigned int n_extra_integers() const
Returns how many extra integers are associated to the DofObject.
processor_id_type processor_id() const
Definition dof_object.h:881
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition dof_object.h:473
unique_id_type unique_id() const
Definition dof_object.h:835
T get_extra_datum(const unsigned int index) const
Gets the value on this object of the extra datum associated with index, which should have been obtain...
bool valid_unique_id() const
Definition dof_object.h:869
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual unsigned int n_nodes_in_child(unsigned int) const
Definition elem.h:667
void family_tree(std::vector< const Elem * > &family, bool reset=true) const
Fills the vector family with the children of this element, recursively.
Definition elem.C:2110
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
virtual std::unique_ptr< Elem > disconnected_clone() const
Definition elem.C:410
void total_family_tree_by_side(std::vector< const Elem * > &family, unsigned int side, bool reset=true) const
Same as the total_family_tree() member, but only adds elements which are next to side.
Definition elem.C:2176
virtual const std::vector< std::pair< unsigned char, unsigned char > > & parent_bracketing_nodes(unsigned int c, unsigned int n) const
Definition elem.C:2481
virtual BoundingBox loose_bounding_box() const
Definition elem.C:3498
SimpleRange< NeighborPtrIter > neighbor_ptr_range()
Returns a range with all neighbors of an element, usable in range-based for loops.
Definition elem.h:3520
virtual std::vector< std::vector< std::vector< std::vector< std::pair< unsigned char, unsigned char > > > > > & _get_bracketing_node_cache() const
Elem subclasses which don't do their own bracketing node calculations will need to supply a static ca...
Definition elem.h:2218
RefinementState refinement_flag() const
Definition elem.h:3227
static const unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition elem.h:643
virtual unsigned int center_node_on_side(const unsigned short side) const
Definition elem.C:3572
void total_family_tree_by_subneighbor(std::vector< const Elem * > &family, const Elem *neighbor, const Elem *subneighbor, bool reset=true) const
Same as the family_tree_by_subneighbor() member, but also adds any subactive descendants.
Definition elem.C:2268
bool active() const
Definition elem.h:2958
unsigned char mapping_data() const
Definition elem.h:3153
bool has_neighbor(const Elem *elem) const
Definition elem.h:2645
void print_info(std::ostream &os=libMesh::out) const
Prints relevant information about the element.
Definition elem.C:2948
virtual unsigned int n_vertices() const =0
const Point & point(const unsigned int i) const
Definition elem.h:2462
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const =0
const Node & node_ref(const unsigned int i) const
Definition elem.h:2538
virtual Point true_centroid() const
Definition elem.C:575
virtual Point origin() const
Definition elem.h:1923
static const unsigned int type_to_n_edges_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of edges on the element...
Definition elem.h:742
virtual bool is_child_on_edge(const unsigned int c, const unsigned int e) const
Definition elem.C:2333
void set_child(unsigned int c, Elem *elem)
Sets the pointer to the child for this element.
Definition elem.h:3199
bool has_children() const
Definition elem.h:2996
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
static std::unique_ptr< Elem > build_with_id(const ElemType type, dof_id_type id)
Calls the build() method above with a nullptr parent, and additionally sets the newly-created Elem's ...
Definition elem.C:556
bool topologically_equal(const Elem &rhs) const
Definition elem.C:788
virtual unsigned int n_nodes() const =0
void active_family_tree_by_side(std::vector< const Elem * > &family, unsigned int side, bool reset=true) const
Same as the active_family_tree() member, but only adds elements which are next to side.
Definition elem.C:2194
const Elem * parent() const
Definition elem.h:3047
void family_tree_by_subneighbor(std::vector< const Elem * > &family, const Elem *neighbor, const Elem *subneighbor, bool reset=true) const
Same as the family_tree() member, but only adds elements which are next to subneighbor.
Definition elem.C:2248
virtual std::pair< unsigned short int, unsigned short int > second_order_child_vertex(const unsigned int n) const
Definition elem.C:3091
void make_links_to_me_local(unsigned int n, unsigned int neighbor_side)
Resets the neighbor_side pointers of our nth neighbor (and its descendants, if appropriate) to point ...
Definition elem.C:1429
bool operator==(const Elem &rhs) const
Definition elem.C:756
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition elem.h:2635
SideIter _last_side()
Definition elem.h:3495
static ElemType complete_order_equivalent_type(const ElemType et)
Definition elem.C:3352
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const =0
void active_family_tree_by_topological_neighbor(std::vector< const Elem * > &family, const Elem *neighbor, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb, bool reset=true) const
Same as the active_family_tree_by_neighbor() member, but the neighbor here may be a topological (e....
Definition elem.C:2306
const Elem * child_ptr(unsigned int i) const
Definition elem.h:3180
virtual const std::vector< std::pair< dof_id_type, dof_id_type > > bracketing_nodes(unsigned int c, unsigned int n) const
Definition elem.C:2684
bool positive_edge_orientation(const unsigned int i) const
Definition elem.C:3634
void family_tree_by_neighbor(std::vector< const Elem * > &family, const Elem *neighbor, bool reset=true) const
Same as the family_tree() member, but only adds elements which are next to neighbor.
Definition elem.C:2212
bool has_topological_neighbor(const Elem *elem, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb) const
Definition elem.C:1324
bool ancestor() const
Definition elem.C:2019
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
Definition elem.h:2936
virtual void connectivity(const unsigned int sc, const IOPackage iop, std::vector< dof_id_type > &conn) const =0
SideIter _first_side()
Side iterator helper functions.
Definition elem.h:3487
void total_family_tree_by_neighbor(std::vector< const Elem * > &family, const Elem *neighbor, bool reset=true) const
Same as the family_tree_by_neighbor() member, but also adds any subactive descendants.
Definition elem.C:2230
bool point_test(const Point &p, Real box_tol, Real map_tol) const
Shared private implementation used by the contains_point() and close_to_point() routines.
Definition elem.C:2821
unsigned int n_neighbors() const
Definition elem.h:713
virtual bool is_mid_infinite_edge_node(const unsigned int) const
Definition elem.h:1914
SimpleRange< NodeRefIter > node_ref_range()
Returns a range with all nodes of an element, usable in range-based for loops.
Definition elem.h:2682
virtual unsigned int opposite_node(const unsigned int n, const unsigned int s) const
Definition elem.C:3564
Node ** _nodes
Pointers to the nodes we are connected to.
Definition elem.h:2254
virtual bool is_vertex_on_parent(unsigned int c, unsigned int n) const
Definition elem.C:3532
virtual Order default_order() const =0
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
void set_interior_parent(Elem *p)
Sets the pointer to the element's interior_parent.
Definition elem.C:1222
static ElemType first_order_equivalent_type(const ElemType et)
Definition elem.C:3099
void remove_links_to_me()
Resets this element's neighbors' appropriate neighbor pointers and its parent's and children's approp...
Definition elem.C:1648
bool positive_face_orientation(const unsigned int i) const
Definition elem.C:3643
virtual unsigned int n_second_order_adjacent_vertices(const unsigned int n) const
Definition elem.C:3073
void total_family_tree(std::vector< const Elem * > &family, bool reset=true) const
Same as the family_tree() member, but also adds any subactive descendants.
Definition elem.C:2126
side_iterator boundary_sides_end()
Definition elem.C:3453
virtual bool is_face(const unsigned int i) const =0
void find_point_neighbors(const Point &p, std::set< const Elem * > &neighbor_set) const
This function finds all active elements (including this one) which are in the same manifold as this e...
Definition elem.C:967
side_iterator boundary_sides_begin()
Iterator accessor functions.
Definition elem.C:3444
void nullify_neighbors()
Replaces this element with nullptr for all of its neighbors.
Definition elem.C:3047
virtual bool has_invertible_map(Real tol=TOLERANCE *TOLERANCE) const
Definition elem.C:2914
std::unique_ptr< Elem *[]> _children
unique_ptr to array of this element's children.
Definition elem.h:2270
unsigned int min_new_p_level_by_neighbor(const Elem *neighbor, unsigned int current_min) const
Definition elem.C:2379
void find_interior_neighbors(std::set< const Elem * > &neighbor_set) const
This function finds all active elements (not including this one) in the parent manifold of this eleme...
Definition elem.C:1146
void swap2boundarysides(unsigned short s1, unsigned short s2, BoundaryInfo *boundary_info) const
Swaps two sides in boundary_info, if it is non-null.
Definition elem.C:3579
virtual Real embedding_matrix(const unsigned int child_num, const unsigned int child_node_num, const unsigned int parent_node_num) const =0
virtual bool is_singular_node(unsigned int) const
Definition elem.h:1847
bool contains_vertex_of(const Elem *e, bool mesh_connection=false) const
Definition elem.C:908
unsigned int which_child_am_i(const Elem *e) const
Definition elem.h:3209
virtual Real hmin() const
Definition elem.C:683
static ElemType second_order_equivalent_type(const ElemType et, const bool full_ordered=true)
Definition elem.C:3168
bool is_semilocal(const processor_id_type my_pid) const
Definition elem.C:840
void libmesh_assert_valid_neighbors() const
Checks for consistent neighbor links on this element.
Definition elem.C:1357
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition elem.C:2784
virtual unsigned short dim() const =0
virtual Real quality(const ElemQuality q) const
Definition elem.C:1783
void find_edge_neighbors(const Point &p1, const Point &p2, std::set< const Elem * > &neighbor_set) const
This function finds all active elements in the same manifold as this element which touch the current ...
Definition elem.C:1057
virtual bool is_vertex_on_child(unsigned int, unsigned int n) const
Definition elem.h:773
void libmesh_assert_valid_node_pointers() const
Checks for a valid id and pointers to nodes with valid ids on this element.
Definition elem.C:1345
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const =0
Similar to Elem::local_side_node(), but instead of a side id, takes an edge id and a node id on that ...
subdomain_id_type subdomain_id() const
Definition elem.h:2591
virtual unsigned int n_sub_elem() const =0
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
Definition elem.h:628
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
Definition elem.h:2355
static const unsigned int type_to_n_sides_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of sides on the element...
Definition elem.h:678
void make_links_to_me_remote()
Resets this element's neighbors' appropriate neighbor pointers and its parent's and children's approp...
Definition elem.C:1542
virtual bool is_edge(const unsigned int i) const =0
virtual dof_id_type key() const
Definition elem.C:738
Elem ** _elemlinks
Pointers to this element's parent and neighbors, and for lower-dimensional elements' interior_parent.
Definition elem.h:2260
unsigned int level() const
Definition elem.h:3091
virtual Real hmax() const
Definition elem.C:707
ElemMappingType mapping_type() const
Definition elem.h:3137
virtual bool is_remote() const
Definition elem.h:596
static const unsigned int max_n_nodes
The maximum number of nodes any element can contain.
Definition elem.h:654
unsigned int min_p_level_by_neighbor(const Elem *neighbor, unsigned int current_min) const
Definition elem.C:2350
std::string get_info() const
Prints relevant information about the element to a string.
Definition elem.C:2956
virtual Point side_vertex_average_normal(const unsigned int s) const
Definition elem.C:3519
virtual std::vector< std::vector< std::vector< signed char > > > & _get_parent_indices_cache() const
Elem subclasses which don't do their own child-to-parent node calculations will need to supply a stat...
Definition elem.h:2232
virtual unsigned int n_faces() const =0
bool contains_edge_of(const Elem *e) const
Definition elem.C:946
virtual unsigned int opposite_side(const unsigned int s) const
Definition elem.C:3556
const Node * node_ptr(const unsigned int i) const
Definition elem.h:2516
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
Definition elem.C:2053
void replace_child(Elem *elem, unsigned int c)
Replaces the child pointer at the specified index in the child array.
Definition elem.C:2099
virtual unsigned int as_parent_node(unsigned int c, unsigned int n) const
Definition elem.C:2413
static const Order type_to_default_order_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the default approximation order of...
Definition elem.h:990
void active_family_tree(std::vector< const Elem * > &active_family, bool reset=true) const
Same as the family_tree() member, but only adds the active children.
Definition elem.C:2142
virtual std::vector< unsigned int > sides_on_edge(const unsigned int) const =0
const Elem * reference_elem() const
Definition elem.C:568
bool is_internal(const unsigned int i) const
Definition elem.C:3611
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i)=0
IntRange< unsigned short > edge_index_range() const
Definition elem.h:2709
Real length(const unsigned int n1, const unsigned int n2) const
Definition elem.C:727
unsigned int which_side_am_i(const Elem *e) const
This function tells you which side the boundary element e is.
Definition elem.C:855
virtual Real volume() const
Definition elem.C:3462
virtual bool is_vertex(const unsigned int i) const =0
virtual unsigned int n_children() const =0
virtual unsigned int embedding_matrix_version() const
Definition elem.h:2060
void swap2boundaryedges(unsigned short e1, unsigned short e2, BoundaryInfo *boundary_info) const
Swaps two edges in boundary_info, if it is non-null.
Definition elem.C:3595
void write_connectivity(std::ostream &out, const IOPackage iop) const
Writes the element connectivity for various IO packages to the passed ostream "out".
Definition elem.C:1740
virtual ElemType type() const =0
IntRange< unsigned short > node_index_range() const
Definition elem.h:2700
virtual Point master_point(const unsigned int i) const =0
const Elem * interior_parent() const
Definition elem.C:1160
bool relative_edge_face_order(const unsigned int e, const unsigned int s) const
Definition elem.C:3664
virtual unsigned int n_edges() const =0
virtual ElemType side_type(const unsigned int s) const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
bool subactive() const
Definition elem.h:2976
unsigned int p_level() const
Definition elem.h:3125
void active_family_tree_by_neighbor(std::vector< const Elem * > &family, const Elem *neighbor, bool reset=true) const
Same as the active_family_tree() member, but only adds elements which are next to neighbor.
Definition elem.C:2288
const Elem * topological_neighbor(const unsigned int i, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb) const
Definition elem.C:1287
RefinementState p_refinement_flag() const
Definition elem.h:3243
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const
Definition elem.C:3081
virtual bool close_to_point(const Point &p, Real tol) const
Definition elem.C:2809
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const =0
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2615
virtual bool infinite() const =0
void family_tree_by_side(std::vector< const Elem * > &family, unsigned int side, bool reset=true) const
Same as the family_tree() member, but only adds elements which are next to side.
Definition elem.C:2158
Point vertex_average() const
Definition elem.C:669
IntRange< unsigned short > side_index_range() const
Definition elem.h:2727
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int) const =0
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
Class contained in FE that encapsulates mapping (i.e.
Definition fe_map.h:48
const std::vector< Real > & get_jacobian() const
Definition fe_map.h:223
static Point map(const unsigned int dim, const Elem *elem, const Point &reference_point)
Definition fe_map.C:1954
static FEFamily map_fe_type(const Elem &elem)
Definition fe_map.C:46
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition fe_map.C:1512
void init_reference_to_physical_map(const std::vector< Point > &qp, const Elem *elem)
Definition fe_map.C:109
virtual void compute_map(const unsigned int dim, const std::vector< Real > &qw, const Elem *elem, bool calculate_d2phi)
Compute the jacobian and some other additional data fields.
Definition fe_map.C:1323
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
Order default_quadrature_order() const
Definition fe_type.h:415
This is the MeshBase class.
Definition mesh_base.h:81
A Node is like a Point, but with more information.
Definition node.h:55
We're using a class instead of a typedef to allow forward declarations and future flexibility.
PeriodicBoundaryBase * boundary(boundary_id_type id)
const Elem * neighbor(boundary_id_type boundary_id, const PointLocatorBase &point_locator, const Elem *e, unsigned int side, unsigned int *neigh_side=nullptr) const
This is the base class for point locators.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
This class implements specific orders of Gauss quadrature.
This class implements nodal quadrature rules for various element types.
In parallel meshes where a ghost element has neighbors which do not exist on the local processor,...
Definition remote_elem.h:61
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
void add(const TypeVector< T2 > &)
Add to this vector without creating a temporary.
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
TypeVector< T > unit() const
MeshBase & mesh
void family_tree_by_subneighbor(T elem, std::vector< T > &family, T neighbor_in, T subneighbor, bool reset=true)
void find_interior_neighbors(T this_elem, std::set< T > &neighbor_set)
void total_family_tree_by_side(T elem, std::vector< T > &family, unsigned int s, bool reset)
void family_tree(T elem, std::vector< T > &family, bool reset=true)
void active_family_tree_by_topological_neighbor(T elem, std::vector< T > &family, T neighbor_in, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb, bool reset=true)
void active_family_tree(T elem, std::vector< T > &active_family, bool reset=true)
void find_point_neighbors(T this_elem, std::set< T > &neighbor_set, T start_elem)
void family_tree_by_neighbor(T elem, std::vector< T > &family, T neighbor_in, bool reset=true)
void total_family_tree(T elem, std::vector< T > &family, bool reset)
void total_family_tree_by_subneighbor(T elem, std::vector< T > &family, T neighbor_in, T subneighbor, bool reset=true)
void total_family_tree_by_neighbor(T elem, std::vector< T > &family, T neighbor_in, bool reset=true)
void active_family_tree_by_side(T elem, std::vector< T > &family, unsigned int side, bool reset=true)
void active_family_tree_by_neighbor(T elem, std::vector< T > &family, T neighbor_in, bool reset=true)
void family_tree_by_side(T elem, std::vector< T > &family, unsigned int s, bool reset)
const Elem & get(const ElemType type_in)
std::string enum_to_string(const T e)
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval=0)
The hashword function takes an array of uint32_t's of length 'length' and computes a single key from ...
Definition hashword.h:158
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
IOPackage
libMesh interfaces with several different software packages for the purposes of creating,...
ElemType
Defines an enum for geometric element types.
void libmesh_ignore(const Args &...)
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
@ RATIONAL_BERNSTEIN_MAP
libmesh_assert(ctx)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition libmesh.h:303
const Real pi
.
Definition libmesh.h:292
Threads::spin_mutex parent_indices_mutex
Definition elem.C:97
Threads::spin_mutex parent_bracketing_nodes_mutex
Definition elem.C:98
T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.
const RemoteElem * remote_elem
Definition remote_elem.C:57
ElemQuality
Defines an enum for element quality metrics.
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Definition id_types.h:104
@ INVALID_ORDER
Definition enum_order.h:88
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
The definition of the struct used for iterating over sides.
Definition elem.h:3508
Used to iterate over the sides of an element which are on the boundary of the Mesh.