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