libMesh
Loading...
Searching...
No Matches
fe_abstract.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18// libmesh includes
19#include "libmesh/fe.h"
20#include "libmesh/libmesh_logging.h"
21#include "libmesh/enum_elem_type.h"
22#include "libmesh/boundary_info.h"
23#include "libmesh/mesh_base.h"
24#include "libmesh/dense_matrix.h"
25#include "libmesh/dense_vector.h"
26#include "libmesh/dof_map.h"
27#include "libmesh/elem.h"
28#include "libmesh/fe_interface.h"
29#include "libmesh/numeric_vector.h"
30#include "libmesh/periodic_boundaries.h"
31#include "libmesh/periodic_boundary.h"
32#include "libmesh/quadrature.h"
33#include "libmesh/quadrature_gauss.h"
34#include "libmesh/remote_elem.h"
35#include "libmesh/tensor_value.h"
36#include "libmesh/threads.h"
37#include "libmesh/enum_to_string.h"
38
39#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
40#include "libmesh/inf_fe.h"
41#include "libmesh/fe_interface_macros.h"
42#endif
43
44namespace libMesh
45{
46
47FEAbstract::FEAbstract(const unsigned int d,
48 const FEType & fet) :
49 _fe_map( FEMap::build(fet) ),
50 dim(d),
51 calculations_started(false),
52 calculate_dual(false),
53 calculate_default_dual_coeff(true),
54 calculate_nothing(false),
55 calculate_map(false),
56 calculate_phi(false),
57 calculate_dphi(false),
58 calculate_d2phi(false),
59 calculate_curl_phi(false),
60 calculate_div_phi(false),
61 calculate_dphiref(false),
62 fe_type(fet),
63 _elem_type(INVALID_ELEM),
64 _elem(nullptr),
65 _elem_p_level(0),
66 _p_level(0),
67 qrule(nullptr),
68 shapes_on_quadrature(false),
69 _n_total_qp(0),
70 _add_p_level_in_reinit(fet.p_refinement)
71{
72}
73
74
75FEAbstract::~FEAbstract() = default;
76
77
78std::unique_ptr<FEAbstract> FEAbstract::build(const unsigned int dim,
79 const FEType & fet)
80{
81 switch (dim)
82 {
83 // 0D
84 case 0:
85 {
86 switch (fet.family)
87 {
88 case CLOUGH:
89 return std::make_unique<FE<0,CLOUGH>>(fet);
90
91 case HERMITE:
92 return std::make_unique<FE<0,HERMITE>>(fet);
93
94 case LAGRANGE:
95 return std::make_unique<FE<0,LAGRANGE>>(fet);
96
97 case LAGRANGE_VEC:
98 return std::make_unique<FE<0,LAGRANGE_VEC>>(fet);
99
100 case L2_LAGRANGE:
101 return std::make_unique<FE<0,L2_LAGRANGE>>(fet);
102
103 case L2_LAGRANGE_GLL:
104 return std::make_unique<FE<0,L2_LAGRANGE_GLL>>(fet);
105
106 case L2_LAGRANGE_VEC:
107 return std::make_unique<FE<0,L2_LAGRANGE_VEC>>(fet);
108
109 case HIERARCHIC_VEC:
110 return std::make_unique<FE<0,HIERARCHIC_VEC>>(fet);
111
112 case HIERARCHIC:
113 return std::make_unique<FE<0,HIERARCHIC>>(fet);
114
115 case L2_HIERARCHIC:
116 return std::make_unique<FE<0,L2_HIERARCHIC>>(fet);
117
119 return std::make_unique<FE<0,L2_HIERARCHIC_VEC>>(fet);
120
121 case SIDE_HIERARCHIC:
122 return std::make_unique<FE<0,SIDE_HIERARCHIC>>(fet);
123
124 case MONOMIAL:
125 return std::make_unique<FE<0,MONOMIAL>>(fet);
126
127 case MONOMIAL_VEC:
128 return std::make_unique<FE<0,MONOMIAL_VEC>>(fet);
129
130#ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
131 case SZABAB:
132 return std::make_unique<FE<0,SZABAB>>(fet);
133
134 case BERNSTEIN:
135 return std::make_unique<FE<0,BERNSTEIN>>(fet);
136
138 return std::make_unique<FE<0,RATIONAL_BERNSTEIN>>(fet);
139#endif
140
141 case XYZ:
142 return std::make_unique<FEXYZ<0>>(fet);
143
144 case SCALAR:
145 return std::make_unique<FEScalar<0>>(fet);
146
147 case NEDELEC_ONE:
148 return std::make_unique<FENedelecOne<0>>(fet);
149
150 case RAVIART_THOMAS:
151 return std::make_unique<FERaviartThomas<0>>(fet);
152
154 return std::make_unique<FEL2RaviartThomas<0>>(fet);
155
156 case SUBDIVISION:
157 return std::make_unique<FESubdivision>(fet);
158
159 default:
160 libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
161 }
162 }
163 // 1D
164 case 1:
165 {
166 switch (fet.family)
167 {
168 case CLOUGH:
169 return std::make_unique<FE<1,CLOUGH>>(fet);
170
171 case HERMITE:
172 return std::make_unique<FE<1,HERMITE>>(fet);
173
174 case LAGRANGE:
175 return std::make_unique<FE<1,LAGRANGE>>(fet);
176
177 case LAGRANGE_VEC:
178 return std::make_unique<FE<1,LAGRANGE_VEC>>(fet);
179
180 case L2_LAGRANGE:
181 return std::make_unique<FE<1,L2_LAGRANGE>>(fet);
182
183 case L2_LAGRANGE_GLL:
184 return std::make_unique<FE<1,L2_LAGRANGE_GLL>>(fet);
185
186 case L2_LAGRANGE_VEC:
187 return std::make_unique<FE<1,L2_LAGRANGE_VEC>>(fet);
188
189 case HIERARCHIC_VEC:
190 return std::make_unique<FE<1,HIERARCHIC_VEC>>(fet);
191
192 case HIERARCHIC:
193 return std::make_unique<FE<1,HIERARCHIC>>(fet);
194
195 case L2_HIERARCHIC:
196 return std::make_unique<FE<1,L2_HIERARCHIC>>(fet);
197
199 return std::make_unique<FE<1,L2_HIERARCHIC_VEC>>(fet);
200
201 case SIDE_HIERARCHIC:
202 return std::make_unique<FE<1,SIDE_HIERARCHIC>>(fet);
203
204 case MONOMIAL:
205 return std::make_unique<FE<1,MONOMIAL>>(fet);
206
207 case MONOMIAL_VEC:
208 return std::make_unique<FE<1,MONOMIAL_VEC>>(fet);
209
210#ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
211 case SZABAB:
212 return std::make_unique<FE<1,SZABAB>>(fet);
213
214 case BERNSTEIN:
215 return std::make_unique<FE<1,BERNSTEIN>>(fet);
216
218 return std::make_unique<FE<1,RATIONAL_BERNSTEIN>>(fet);
219#endif
220
221 case XYZ:
222 return std::make_unique<FEXYZ<1>>(fet);
223
224 case SCALAR:
225 return std::make_unique<FEScalar<1>>(fet);
226
227 case NEDELEC_ONE:
228 return std::make_unique<FENedelecOne<1>>(fet);
229
230 case RAVIART_THOMAS:
231 return std::make_unique<FERaviartThomas<1>>(fet);
232
234 return std::make_unique<FEL2RaviartThomas<1>>(fet);
235
236 case SUBDIVISION:
237 return std::make_unique<FESubdivision>(fet);
238
239 default:
240 libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
241 }
242 }
243
244
245 // 2D
246 case 2:
247 {
248 switch (fet.family)
249 {
250 case CLOUGH:
251 return std::make_unique<FE<2,CLOUGH>>(fet);
252
253 case HERMITE:
254 return std::make_unique<FE<2,HERMITE>>(fet);
255
256 case LAGRANGE:
257 return std::make_unique<FE<2,LAGRANGE>>(fet);
258
259 case LAGRANGE_VEC:
260 return std::make_unique<FE<2,LAGRANGE_VEC>>(fet);
261
262 case L2_LAGRANGE:
263 return std::make_unique<FE<2,L2_LAGRANGE>>(fet);
264
265 case L2_LAGRANGE_GLL:
266 return std::make_unique<FE<2,L2_LAGRANGE_GLL>>(fet);
267
268 case L2_LAGRANGE_VEC:
269 return std::make_unique<FE<2,L2_LAGRANGE_VEC>>(fet);
270
271 case HIERARCHIC_VEC:
272 return std::make_unique<FE<2,HIERARCHIC_VEC>>(fet);
273
274 case HIERARCHIC:
275 return std::make_unique<FE<2,HIERARCHIC>>(fet);
276
277 case L2_HIERARCHIC:
278 return std::make_unique<FE<2,L2_HIERARCHIC>>(fet);
279
281 return std::make_unique<FE<2,L2_HIERARCHIC_VEC>>(fet);
282
283 case SIDE_HIERARCHIC:
284 return std::make_unique<FE<2,SIDE_HIERARCHIC>>(fet);
285
286 case MONOMIAL:
287 return std::make_unique<FE<2,MONOMIAL>>(fet);
288
289 case MONOMIAL_VEC:
290 return std::make_unique<FE<2,MONOMIAL_VEC>>(fet);
291
292#ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
293 case SZABAB:
294 return std::make_unique<FE<2,SZABAB>>(fet);
295
296 case BERNSTEIN:
297 return std::make_unique<FE<2,BERNSTEIN>>(fet);
298
300 return std::make_unique<FE<2,RATIONAL_BERNSTEIN>>(fet);
301#endif
302
303 case XYZ:
304 return std::make_unique<FEXYZ<2>>(fet);
305
306 case SCALAR:
307 return std::make_unique<FEScalar<2>>(fet);
308
309 case NEDELEC_ONE:
310 return std::make_unique<FENedelecOne<2>>(fet);
311
312 case RAVIART_THOMAS:
313 return std::make_unique<FERaviartThomas<2>>(fet);
314
316 return std::make_unique<FEL2RaviartThomas<2>>(fet);
317
318 case SUBDIVISION:
319 return std::make_unique<FESubdivision>(fet);
320
321 default:
322 libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
323 }
324 }
325
326
327 // 3D
328 case 3:
329 {
330 switch (fet.family)
331 {
332 case CLOUGH:
333 libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D");
334
335 case HERMITE:
336 return std::make_unique<FE<3,HERMITE>>(fet);
337
338 case LAGRANGE:
339 return std::make_unique<FE<3,LAGRANGE>>(fet);
340
341 case LAGRANGE_VEC:
342 return std::make_unique<FE<3,LAGRANGE_VEC>>(fet);
343
344 case L2_LAGRANGE:
345 return std::make_unique<FE<3,L2_LAGRANGE>>(fet);
346
347 case L2_LAGRANGE_GLL:
348 return std::make_unique<FE<3,L2_LAGRANGE_GLL>>(fet);
349
350 case L2_LAGRANGE_VEC:
351 return std::make_unique<FE<3,L2_LAGRANGE_VEC>>(fet);
352
353 case HIERARCHIC_VEC:
354 return std::make_unique<FE<3,HIERARCHIC_VEC>>(fet);
355
356 case HIERARCHIC:
357 return std::make_unique<FE<3,HIERARCHIC>>(fet);
358
359 case L2_HIERARCHIC:
360 return std::make_unique<FE<3,L2_HIERARCHIC>>(fet);
361
363 return std::make_unique<FE<3,L2_HIERARCHIC_VEC>>(fet);
364
365 case SIDE_HIERARCHIC:
366 return std::make_unique<FE<3,SIDE_HIERARCHIC>>(fet);
367
368 case MONOMIAL:
369 return std::make_unique<FE<3,MONOMIAL>>(fet);
370
371 case MONOMIAL_VEC:
372 return std::make_unique<FE<3,MONOMIAL_VEC>>(fet);
373
374#ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
375 case SZABAB:
376 return std::make_unique<FE<3,SZABAB>>(fet);
377
378 case BERNSTEIN:
379 return std::make_unique<FE<3,BERNSTEIN>>(fet);
380
382 return std::make_unique<FE<3,RATIONAL_BERNSTEIN>>(fet);
383#endif
384
385 case XYZ:
386 return std::make_unique<FEXYZ<3>>(fet);
387
388 case SCALAR:
389 return std::make_unique<FEScalar<3>>(fet);
390
391 case NEDELEC_ONE:
392 return std::make_unique<FENedelecOne<3>>(fet);
393
394 case RAVIART_THOMAS:
395 return std::make_unique<FERaviartThomas<3>>(fet);
396
398 return std::make_unique<FEL2RaviartThomas<3>>(fet);
399
400 default:
401 libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
402 }
403 }
404
405 default:
406 libmesh_error_msg("Invalid dimension dim = " << dim);
407 }
408}
409
410
411
412void FEAbstract::get_refspace_nodes(const ElemType itemType, std::vector<Point> & nodes)
413{
414 const unsigned int n_nodes = Elem::type_to_n_nodes_map[itemType];
415 if (n_nodes == invalid_uint)
416 libmesh_error_msg("Number of nodes is not well-defined for " <<
417 Utility::enum_to_string(itemType));
418
419 nodes.resize(n_nodes);
420 switch(itemType)
421 {
422 case NODEELEM:
423 {
424 nodes[0] = Point (0.,0.,0.);
425 return;
426 }
427 case EDGE3:
428 {
429 nodes[2] = Point (0.,0.,0.);
430 libmesh_fallthrough();
431 }
432 case EDGE2:
433 {
434 nodes[0] = Point (-1.,0.,0.);
435 nodes[1] = Point (1.,0.,0.);
436 return;
437 }
438 case EDGE4: // not nested with EDGE3
439 {
440 nodes[0] = Point (-1.,0.,0.);
441 nodes[1] = Point (1.,0.,0.);
442 nodes[2] = Point (-1./3.,0.,0.);
443 nodes[3] = Point (1./3.,0.,0.);
444 return;
445 }
446 case TRI7:
447 {
448 nodes[6] = Point (1./3.,1./3.,0.);
449 libmesh_fallthrough();
450 }
451 case TRI6:
452 {
453 nodes[3] = Point (.5,0.,0.);
454 nodes[4] = Point (.5,.5,0.);
455 nodes[5] = Point (0.,.5,0.);
456 libmesh_fallthrough();
457 }
458 case TRI3:
459 case TRISHELL3:
460 {
461 nodes[0] = Point (0.,0.,0.);
462 nodes[1] = Point (1.,0.,0.);
463 nodes[2] = Point (0.,1.,0.);
464 return;
465 }
466 case QUAD9:
467 case QUADSHELL9:
468 {
469 nodes[8] = Point (0.,0.,0.);
470 libmesh_fallthrough();
471 }
472 case QUAD8:
473 case QUADSHELL8:
474 {
475 nodes[4] = Point (0.,-1.,0.);
476 nodes[5] = Point (1.,0.,0.);
477 nodes[6] = Point (0.,1.,0.);
478 nodes[7] = Point (-1.,0.,0.);
479 libmesh_fallthrough();
480 }
481 case QUAD4:
482 case QUADSHELL4:
483 {
484 nodes[0] = Point (-1.,-1.,0.);
485 nodes[1] = Point (1.,-1.,0.);
486 nodes[2] = Point (1.,1.,0.);
487 nodes[3] = Point (-1.,1.,0.);
488 return;
489 }
490 case TET14:
491 {
492 nodes[10] = Point (1/Real(3),1/Real(3),0.);
493 nodes[11] = Point (1/Real(3),0.,1/Real(3));
494 nodes[12] = Point (1/Real(3),1/Real(3),1/Real(3));
495 nodes[13] = Point (0.,1/Real(3),1/Real(3));
496 libmesh_fallthrough();
497 }
498 case TET10:
499 {
500 nodes[4] = Point (.5,0.,0.);
501 nodes[5] = Point (.5,.5,0.);
502 nodes[6] = Point (0.,.5,0.);
503 nodes[7] = Point (0.,0.,.5);
504 nodes[8] = Point (.5,0.,.5);
505 nodes[9] = Point (0.,.5,.5);
506 libmesh_fallthrough();
507 }
508 case TET4:
509 {
510 nodes[0] = Point (0.,0.,0.);
511 nodes[1] = Point (1.,0.,0.);
512 nodes[2] = Point (0.,1.,0.);
513 nodes[3] = Point (0.,0.,1.);
514 return;
515 }
516 case HEX27:
517 {
518 nodes[20] = Point (0.,0.,-1.);
519 nodes[21] = Point (0.,-1.,0.);
520 nodes[22] = Point (1.,0.,0.);
521 nodes[23] = Point (0.,1.,0.);
522 nodes[24] = Point (-1.,0.,0.);
523 nodes[25] = Point (0.,0.,1.);
524 nodes[26] = Point (0.,0.,0.);
525 libmesh_fallthrough();
526 }
527 case HEX20:
528 {
529 nodes[8] = Point (0.,-1.,-1.);
530 nodes[9] = Point (1.,0.,-1.);
531 nodes[10] = Point (0.,1.,-1.);
532 nodes[11] = Point (-1.,0.,-1.);
533 nodes[12] = Point (-1.,-1.,0.);
534 nodes[13] = Point (1.,-1.,0.);
535 nodes[14] = Point (1.,1.,0.);
536 nodes[15] = Point (-1.,1.,0.);
537 nodes[16] = Point (0.,-1.,1.);
538 nodes[17] = Point (1.,0.,1.);
539 nodes[18] = Point (0.,1.,1.);
540 nodes[19] = Point (-1.,0.,1.);
541 libmesh_fallthrough();
542 }
543 case HEX8:
544 {
545 nodes[0] = Point (-1.,-1.,-1.);
546 nodes[1] = Point (1.,-1.,-1.);
547 nodes[2] = Point (1.,1.,-1.);
548 nodes[3] = Point (-1.,1.,-1.);
549 nodes[4] = Point (-1.,-1.,1.);
550 nodes[5] = Point (1.,-1.,1.);
551 nodes[6] = Point (1.,1.,1.);
552 nodes[7] = Point (-1.,1.,1.);
553 return;
554 }
555 case PRISM21:
556 {
557 nodes[20] = Point (1/Real(3),1/Real(3),0);
558 libmesh_fallthrough();
559 }
560 case PRISM20:
561 {
562 nodes[18] = Point (1/Real(3),1/Real(3),-1);
563 nodes[19] = Point (1/Real(3),1/Real(3),1);
564 libmesh_fallthrough();
565 }
566 case PRISM18:
567 {
568 nodes[15] = Point (.5,0.,0.);
569 nodes[16] = Point (.5,.5,0.);
570 nodes[17] = Point (0.,.5,0.);
571 libmesh_fallthrough();
572 }
573 case PRISM15:
574 {
575 nodes[6] = Point (.5,0.,-1.);
576 nodes[7] = Point (.5,.5,-1.);
577 nodes[8] = Point (0.,.5,-1.);
578 nodes[9] = Point (0.,0.,0.);
579 nodes[10] = Point (1.,0.,0.);
580 nodes[11] = Point (0.,1.,0.);
581 nodes[12] = Point (.5,0.,1.);
582 nodes[13] = Point (.5,.5,1.);
583 nodes[14] = Point (0.,.5,1.);
584 libmesh_fallthrough();
585 }
586 case PRISM6:
587 {
588 nodes[0] = Point (0.,0.,-1.);
589 nodes[1] = Point (1.,0.,-1.);
590 nodes[2] = Point (0.,1.,-1.);
591 nodes[3] = Point (0.,0.,1.);
592 nodes[4] = Point (1.,0.,1.);
593 nodes[5] = Point (0.,1.,1.);
594 return;
595 }
596 case PYRAMID18:
597 {
598 // triangle centers
599 nodes[14] = Point (0., -2/Real(3),1/Real(3));
600 nodes[15] = Point (2/Real(3),0.,1/Real(3));
601 nodes[16] = Point (0.,2/Real(3),1/Real(3));
602 nodes[17] = Point (-2/Real(3),0.,1/Real(3));
603
604 libmesh_fallthrough();
605 }
606 case PYRAMID14:
607 {
608 // base center
609 nodes[13] = Point (0.,0.,0.);
610
611 libmesh_fallthrough();
612 }
613 case PYRAMID13:
614 {
615 // base midedge
616 nodes[5] = Point (0.,-1.,0.);
617 nodes[6] = Point (1.,0.,0.);
618 nodes[7] = Point (0.,1.,0.);
619 nodes[8] = Point (-1,0.,0.);
620
621 // lateral midedge
622 nodes[9] = Point (-.5,-.5,.5);
623 nodes[10] = Point (.5,-.5,.5);
624 nodes[11] = Point (.5,.5,.5);
625 nodes[12] = Point (-.5,.5,.5);
626
627 libmesh_fallthrough();
628 }
629 case PYRAMID5:
630 {
631 // base corners
632 nodes[0] = Point (-1.,-1.,0.);
633 nodes[1] = Point (1.,-1.,0.);
634 nodes[2] = Point (1.,1.,0.);
635 nodes[3] = Point (-1.,1.,0.);
636 // apex
637 nodes[4] = Point (0.,0.,1.);
638 return;
639 }
640
641 default:
642 libmesh_error_msg("ERROR: Unknown element type " << Utility::enum_to_string(itemType));
643 }
644}
645
646
647
648#ifdef LIBMESH_ENABLE_DEPRECATED
649bool FEAbstract::on_reference_element(const Point & p, const ElemType t, const Real eps)
650{
651 // Use Elem::on_reference_element() instead
652 libmesh_deprecated();
653
654 libmesh_assert_greater_equal (eps, 0.);
655
656 const Real xi = p(0);
657#if LIBMESH_DIM > 1
658 const Real eta = p(1);
659#else
660 const Real eta = 0.;
661#endif
662#if LIBMESH_DIM > 2
663 const Real zeta = p(2);
664#else
665 const Real zeta = 0.;
666#endif
667
668 switch (t)
669 {
670 case NODEELEM:
671 {
672 return (!xi && !eta && !zeta);
673 }
674 case EDGE2:
675 case EDGE3:
676 case EDGE4:
677 {
678 // The reference 1D element is [-1,1].
679 if ((xi >= -1.-eps) &&
680 (xi <= 1.+eps))
681 return true;
682
683 return false;
684 }
685
686
687 case TRI3:
688 case TRISHELL3:
689 case TRI6:
690 case TRI7:
691 {
692 // The reference triangle is isosceles
693 // and is bound by xi=0, eta=0, and xi+eta=1.
694 if ((xi >= 0.-eps) &&
695 (eta >= 0.-eps) &&
696 ((xi + eta) <= 1.+eps))
697 return true;
698
699 return false;
700 }
701
702
703 case QUAD4:
704 case QUADSHELL4:
705 case QUAD8:
706 case QUADSHELL8:
707 case QUAD9:
708 case QUADSHELL9:
709 {
710 // The reference quadrilateral element is [-1,1]^2.
711 if ((xi >= -1.-eps) &&
712 (xi <= 1.+eps) &&
713 (eta >= -1.-eps) &&
714 (eta <= 1.+eps))
715 return true;
716
717 return false;
718 }
719
720
721 case TET4:
722 case TET10:
723 case TET14:
724 {
725 // The reference tetrahedral is isosceles
726 // and is bound by xi=0, eta=0, zeta=0,
727 // and xi+eta+zeta=1.
728 if ((xi >= 0.-eps) &&
729 (eta >= 0.-eps) &&
730 (zeta >= 0.-eps) &&
731 ((xi + eta + zeta) <= 1.+eps))
732 return true;
733
734 return false;
735 }
736
737
738 case HEX8:
739 case HEX20:
740 case HEX27:
741 {
742 /*
743 if ((xi >= -1.) &&
744 (xi <= 1.) &&
745 (eta >= -1.) &&
746 (eta <= 1.) &&
747 (zeta >= -1.) &&
748 (zeta <= 1.))
749 return true;
750 */
751
752 // The reference hexahedral element is [-1,1]^3.
753 if ((xi >= -1.-eps) &&
754 (xi <= 1.+eps) &&
755 (eta >= -1.-eps) &&
756 (eta <= 1.+eps) &&
757 (zeta >= -1.-eps) &&
758 (zeta <= 1.+eps))
759 {
760 // libMesh::out << "Strange Point:\n";
761 // p.print();
762 return true;
763 }
764
765 return false;
766 }
767
768 case PRISM6:
769 case PRISM15:
770 case PRISM18:
771 case PRISM20:
772 case PRISM21:
773 {
774 // Figure this one out...
775 // inside the reference triangle with zeta in [-1,1]
776 if ((xi >= 0.-eps) &&
777 (eta >= 0.-eps) &&
778 (zeta >= -1.-eps) &&
779 (zeta <= 1.+eps) &&
780 ((xi + eta) <= 1.+eps))
781 return true;
782
783 return false;
784 }
785
786
787 case PYRAMID5:
788 case PYRAMID13:
789 case PYRAMID14:
790 case PYRAMID18:
791 {
792 // Check that the point is on the same side of all the faces
793 // by testing whether:
794 //
795 // n_i.(x - x_i) <= 0
796 //
797 // for each i, where:
798 // n_i is the outward normal of face i,
799 // x_i is a point on face i.
800 if ((-eta - 1. + zeta <= 0.+eps) &&
801 ( xi - 1. + zeta <= 0.+eps) &&
802 ( eta - 1. + zeta <= 0.+eps) &&
803 ( -xi - 1. + zeta <= 0.+eps) &&
804 ( zeta >= 0.-eps))
805 return true;
806
807 return false;
808 }
809
810#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
811 case INFHEX8:
812 case INFHEX16:
813 case INFHEX18:
814 {
815 // The reference infhex8 is a [-1,1]^3.
816 if ((xi >= -1.-eps) &&
817 (xi <= 1.+eps) &&
818 (eta >= -1.-eps) &&
819 (eta <= 1.+eps) &&
820 (zeta >= -1.-eps) &&
821 (zeta <= 1.+eps))
822 {
823 return true;
824 }
825 return false;
826 }
827
828 case INFPRISM6:
829 case INFPRISM12:
830 {
831 // inside the reference triangle with zeta in [-1,1]
832 if ((xi >= 0.-eps) &&
833 (eta >= 0.-eps) &&
834 (zeta >= -1.-eps) &&
835 (zeta <= 1.+eps) &&
836 ((xi + eta) <= 1.+eps))
837 {
838 return true;
839 }
840
841 return false;
842 }
843#endif
844
845 default:
846 libmesh_error_msg("ERROR: Unknown element type " << Utility::enum_to_string(t));
847 }
848
849 // If we get here then the point is _not_ in the
850 // reference element. Better return false.
851
852 return false;
853}
854#endif // LIBMESH_ENABLE_DEPRECATED
855
856
857
858void FEAbstract::print_JxW(std::ostream & os) const
859{
860 this->_fe_map->print_JxW(os);
861}
862
863
864
865void FEAbstract::print_xyz(std::ostream & os) const
866{
867 this->_fe_map->print_xyz(os);
868}
869
870
871void FEAbstract::print_info(std::ostream & os) const
872{
873 os << "phi[i][j]: Shape function i at quadrature pt. j" << std::endl;
874 this->print_phi(os);
875
876 os << "dphi[i][j]: Shape function i's gradient at quadrature pt. j" << std::endl;
877 this->print_dphi(os);
878
879 os << "XYZ locations of the quadrature pts." << std::endl;
880 this->print_xyz(os);
881
882 os << "Values of JxW at the quadrature pts." << std::endl;
883 this->print_JxW(os);
884}
885
886
887std::ostream & operator << (std::ostream & os, const FEAbstract & fe)
888{
889 fe.print_info(os);
890 return os;
891}
892
893
894
895#ifdef LIBMESH_ENABLE_AMR
896
897#ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
899 const Elem * elem)
900{
901 libmesh_assert(elem);
902
903 const unsigned int Dim = elem->dim();
904
905 // Only constrain elements in 2,3D.
906 if (Dim == 1)
907 return;
908
909 // Only constrain active and ancestor elements
910 if (elem->subactive())
911 return;
912
913
914#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
915 if (elem->infinite())
916 {
917 const FEType fe_t(elem->default_order(), FEMap::map_fe_type(*elem));
918
919 // expand the infinite_compute_constraint in its template-arguments.
920 switch(Dim)
921 {
922 case 2:
923 {
924 inf_fe_family_mapping_switch(2, inf_compute_node_constraints (constraints, elem) , ,; break;);
925 break;
926 }
927 case 3:
928 {
929 inf_fe_family_mapping_switch(3, inf_compute_node_constraints (constraints, elem) , ,; break;);
930 break;
931 }
932 default:
933 libmesh_error_msg("Invalid dim = " << Dim);
934 }
935 return;
936 }
937
938#endif
939 const FEFamily mapping_family = FEMap::map_fe_type(*elem);
940 const FEType fe_type(elem->default_side_order(), mapping_family);
941
942 // Pull objects out of the loop to reduce heap operations
943 std::vector<const Node *> my_nodes, parent_nodes;
944 std::unique_ptr<const Elem> my_side, parent_side;
945
946 // Look at the element faces. Check to see if we need to
947 // build constraints.
948 for (auto s : elem->side_index_range())
949 if (elem->neighbor_ptr(s) != nullptr &&
950 elem->neighbor_ptr(s) != remote_elem)
951 if (elem->neighbor_ptr(s)->level() < elem->level()) // constrain dofs shared between
952 { // this element and ones coarser
953 // than this element.
954 // Get pointers to the elements of interest and its parent.
955 const Elem * parent = elem->parent();
956
957 // This can't happen... Only level-0 elements have nullptr
958 // parents, and no level-0 elements can be at a higher
959 // level than their neighbors!
960 libmesh_assert(parent);
961
962 elem->build_side_ptr(my_side, s);
963 parent->build_side_ptr(parent_side, s);
964
965 const unsigned int n_side_nodes = my_side->n_nodes();
966
967 my_nodes.clear();
968 my_nodes.reserve (n_side_nodes);
969 parent_nodes.clear();
970 parent_nodes.reserve (n_side_nodes);
971
972 for (unsigned int n=0; n != n_side_nodes; ++n)
973 my_nodes.push_back(my_side->node_ptr(n));
974
975 for (unsigned int n=0; n != n_side_nodes; ++n)
976 parent_nodes.push_back(parent_side->node_ptr(n));
977
978 for (unsigned int my_side_n=0;
979 my_side_n < n_side_nodes;
980 my_side_n++)
981 {
982 // We can have an FE type that supports an order
983 // partially, such that sides do not support the same
984 // order. E.g. we say that a LAGRANGE PRISM21 supports
985 // "third" order to distinguish its shape functions from
986 // a PRISM18, but the QUAD9 sides will still only
987 // support second order.
988 FEType side_fe_type = fe_type;
989 const int side_max_order =
990 FEInterface::max_order(fe_type, my_side->type());
991
992 if ((int)fe_type.order > side_max_order)
993 side_fe_type.order = side_max_order;
994
995 // Do not use the p_level(), if any, that is inherited by the side.
996 libmesh_assert_less
997 (my_side_n,
998 FEInterface::n_dofs(side_fe_type, /*extra_order=*/0,
999 my_side.get()));
1000
1001 const Node * my_node = my_nodes[my_side_n];
1002
1003 // The support point of the DOF
1004 const Point & support_point = *my_node;
1005
1006 // Figure out where my node lies on their reference element.
1007 const Point mapped_point = FEMap::inverse_map(Dim-1,
1008 parent_side.get(),
1009 support_point);
1010
1011 // Compute the parent's side shape function values.
1012 for (unsigned int their_side_n=0;
1013 their_side_n < n_side_nodes;
1014 their_side_n++)
1015 {
1016 // Do not use the p_level(), if any, that is inherited by the side.
1017 libmesh_assert_less
1018 (their_side_n,
1019 FEInterface::n_dofs(side_fe_type,
1020 /*extra_order=*/0,
1021 parent_side.get()));
1022
1023 const Node * their_node = parent_nodes[their_side_n];
1024 libmesh_assert(their_node);
1025
1026 // Do not use the p_level(), if any, that is inherited by the side.
1027 const Real their_value = FEInterface::shape(side_fe_type,
1028 /*extra_order=*/0,
1029 parent_side.get(),
1030 their_side_n,
1031 mapped_point);
1032
1033 const Real their_mag = std::abs(their_value);
1034#ifdef DEBUG
1035 // Protect for the case u_i ~= u_j,
1036 // in which case i better equal j.
1037 if (their_mag > 0.999)
1038 {
1039 libmesh_assert_equal_to (my_node, their_node);
1040 libmesh_assert_less (std::abs(their_value - 1.), 0.001);
1041 }
1042 else
1043#endif
1044 // To make nodal constraints useful for constructing
1045 // sparsity patterns faster, we need to get EVERY
1046 // POSSIBLE constraint coupling identified, even if
1047 // there is no coupling in the isoparametric
1048 // Lagrange case.
1049 if (their_mag < 1.e-5)
1050 {
1051 // since we may be running this method concurrently
1052 // on multiple threads we need to acquire a lock
1053 // before modifying the shared constraint_row object.
1054 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1055
1056 // A reference to the constraint row.
1057 NodeConstraintRow & constraint_row = constraints[my_node].first;
1058
1059 constraint_row.emplace(their_node, 0.);
1060 }
1061 // To get nodal coordinate constraints right, only
1062 // add non-zero and non-identity values for Lagrange
1063 // basis functions.
1064 else // (1.e-5 <= their_mag <= .999)
1065 {
1066 // since we may be running this method concurrently
1067 // on multiple threads we need to acquire a lock
1068 // before modifying the shared constraint_row object.
1069 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1070
1071 // A reference to the constraint row.
1072 NodeConstraintRow & constraint_row = constraints[my_node].first;
1073
1074 constraint_row.emplace(their_node, their_value);
1075 }
1076 }
1077 }
1078 }
1079}
1080
1081#endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
1082
1083#endif // #ifdef LIBMESH_ENABLE_AMR
1084
1085
1086
1087#ifdef LIBMESH_ENABLE_PERIODIC
1088
1089#ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1091 const PeriodicBoundaries & boundaries,
1092 const MeshBase & mesh,
1093 const PointLocatorBase * point_locator,
1094 const Elem * elem)
1095{
1096 // Only bother if we truly have periodic boundaries
1097 if (boundaries.empty())
1098 return;
1099
1100 libmesh_assert(elem);
1101
1102 // Only constrain active elements with this method
1103 if (!elem->active())
1104 return;
1105
1106 const unsigned int Dim = elem->dim();
1107
1108 const FEFamily mapping_family = FEMap::map_fe_type(*elem);
1109 const FEType fe_type(elem->default_side_order(), mapping_family);
1110
1111 // Pull objects out of the loop to reduce heap operations
1112 std::vector<const Node *> my_nodes, neigh_nodes;
1113 std::unique_ptr<const Elem> my_side, neigh_side;
1114
1115 // Look at the element faces. Check to see if we need to
1116 // build constraints.
1117 std::vector<boundary_id_type> bc_ids;
1118 for (auto s : elem->side_index_range())
1119 {
1120 if (elem->neighbor_ptr(s))
1121 continue;
1122
1123 mesh.get_boundary_info().boundary_ids (elem, s, bc_ids);
1124 for (const auto & boundary_id : bc_ids)
1125 {
1126 const PeriodicBoundaryBase * periodic = boundaries.boundary(boundary_id);
1127 if (periodic)
1128 {
1129 libmesh_assert(point_locator);
1130
1131 // Get pointers to the element's neighbor.
1132 unsigned int s_neigh;
1133 const Elem * neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s, &s_neigh);
1134
1135 libmesh_error_msg_if
1136 (!neigh, "PeriodicBoundaries can't find a periodic neighbor for element " <<
1137 elem->id() << " side " << s);
1138
1139 // h refinement constraints:
1140 // constrain dofs shared between
1141 // this element and ones as coarse
1142 // as or coarser than this element.
1143 if (neigh->level() <= elem->level())
1144 {
1145#ifdef LIBMESH_ENABLE_AMR
1146 libmesh_assert(neigh->active());
1147#endif // #ifdef LIBMESH_ENABLE_AMR
1148
1149 elem->build_side_ptr(my_side, s);
1150 neigh->build_side_ptr(neigh_side, s_neigh);
1151
1152 const unsigned int n_side_nodes = my_side->n_nodes();
1153
1154 my_nodes.clear();
1155 my_nodes.reserve (n_side_nodes);
1156 neigh_nodes.clear();
1157 neigh_nodes.reserve (n_side_nodes);
1158
1159 for (unsigned int n=0; n != n_side_nodes; ++n)
1160 my_nodes.push_back(my_side->node_ptr(n));
1161
1162 for (unsigned int n=0; n != n_side_nodes; ++n)
1163 neigh_nodes.push_back(neigh_side->node_ptr(n));
1164
1165 // Make sure we're not adding recursive constraints
1166 // due to the redundancy in the way we add periodic
1167 // boundary constraints, or adding constraints to
1168 // nodes that already have AMR constraints
1169 std::vector<bool> skip_constraint(n_side_nodes, false);
1170
1171 for (unsigned int my_side_n=0;
1172 my_side_n < n_side_nodes;
1173 my_side_n++)
1174 {
1175 // Do not use the p_level(), if any, that is inherited by the side.
1176 libmesh_assert_less (my_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
1177
1178 const Node * my_node = my_nodes[my_side_n];
1179
1180 // If we've already got a constraint on this
1181 // node, then the periodic constraint is
1182 // redundant
1183 {
1184 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1185
1186 if (constraints.count(my_node))
1187 {
1188 skip_constraint[my_side_n] = true;
1189 continue;
1190 }
1191 }
1192
1193 // Compute the neighbors's side shape function values.
1194 for (unsigned int their_side_n=0;
1195 their_side_n < n_side_nodes;
1196 their_side_n++)
1197 {
1198 // Do not use the p_level(), if any, that is inherited by the side.
1199 libmesh_assert_less (their_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, neigh_side.get()));
1200
1201 const Node * their_node = neigh_nodes[their_side_n];
1202
1203 // If there's a constraint on an opposing node,
1204 // we need to see if it's constrained by
1205 // *our side* making any periodic constraint
1206 // on us recursive
1207 {
1208 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1209
1210 if (!constraints.count(their_node))
1211 continue;
1212
1213 const NodeConstraintRow & their_constraint_row =
1214 constraints[their_node].first;
1215
1216 for (unsigned int orig_side_n=0;
1217 orig_side_n < n_side_nodes;
1218 orig_side_n++)
1219 {
1220 // Do not use the p_level(), if any, that is inherited by the side.
1221 libmesh_assert_less (orig_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
1222
1223 const Node * orig_node = my_nodes[orig_side_n];
1224
1225 if (their_constraint_row.count(orig_node))
1226 skip_constraint[orig_side_n] = true;
1227 }
1228 }
1229 }
1230 }
1231 for (unsigned int my_side_n=0;
1232 my_side_n < n_side_nodes;
1233 my_side_n++)
1234 {
1235 // Do not use the p_level(), if any, that is inherited by the side.
1236 libmesh_assert_less (my_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
1237
1238 if (skip_constraint[my_side_n])
1239 continue;
1240
1241 const Node * my_node = my_nodes[my_side_n];
1242
1243 // Figure out where my node lies on their reference element.
1244 const Point neigh_point = periodic->get_corresponding_pos(*my_node);
1245
1246 // Figure out where my node lies on their reference element.
1247 const Point mapped_point =
1248 FEMap::inverse_map(Dim-1, neigh_side.get(),
1249 neigh_point);
1250
1251 for (unsigned int their_side_n=0;
1252 their_side_n < n_side_nodes;
1253 their_side_n++)
1254 {
1255 // Do not use the p_level(), if any, that is inherited by the side.
1256 libmesh_assert_less (their_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, neigh_side.get()));
1257
1258 const Node * their_node = neigh_nodes[their_side_n];
1259 libmesh_assert(their_node);
1260
1261 // Do not use the p_level(), if any, that is inherited by the side.
1262 const Real their_value = FEInterface::shape(fe_type,
1263 /*extra_order=*/0,
1264 neigh_side.get(),
1265 their_side_n,
1266 mapped_point);
1267
1268 // since we may be running this method concurrently
1269 // on multiple threads we need to acquire a lock
1270 // before modifying the shared constraint_row object.
1271 {
1272 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1273
1274 NodeConstraintRow & constraint_row =
1275 constraints[my_node].first;
1276
1277 constraint_row.emplace(their_node, their_value);
1278 }
1279 }
1280 }
1281 }
1282 }
1283 }
1284 }
1285}
1286#endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
1287
1288#endif // LIBMESH_ENABLE_PERIODIC
1289
1290
1292{
1293 if (this->shapes_on_quadrature)
1294 {
1295 libmesh_assert(this->qrule);
1296 libmesh_assert_equal_to(this->qrule->n_points(),
1297 this->_n_total_qp);
1298 }
1299 return this->_n_total_qp;
1300}
1301
1302} // namespace libMesh
unsigned int dim
dof_id_type id() const
Definition dof_object.h:833
This is the base class from which all geometric element types are derived.
Definition elem.h:96
bool active() const
Definition elem.h:3079
const Elem * parent() const
Definition elem.h:3168
virtual Order default_order() const =0
virtual unsigned short dim() const =0
unsigned int level() const
Definition elem.h:3212
static constexpr unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition elem.h:664
virtual Order default_side_order() const
Definition elem.h:1110
bool subactive() const
Definition elem.h:3097
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2736
virtual bool infinite() const =0
IntRange< unsigned short > side_index_range() const
Definition elem.h:2848
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
This class forms the foundation from which generic finite elements may be derived.
std::unique_ptr< FEMap > _fe_map
virtual ~FEAbstract()
Destructor.
FEAbstract(const unsigned int dim, const FEType &fet)
Constructor.
Definition fe_abstract.C:47
FEType fe_type
The finite element type for this object.
const unsigned int dim
The dimensionality of the object.
static void compute_node_constraints(NodeConstraints &constraints, const Elem *elem)
Computes the nodal constraint contributions (for non-conforming adapted meshes), using Lagrange geome...
void print_JxW(std::ostream &os) const
Prints the Jacobian times the weight for each quadrature point.
bool shapes_on_quadrature
A flag indicating if current data structures correspond to quadrature rule points.
virtual void print_dphi(std::ostream &os) const =0
Prints the value of each shape function's derivative at each quadrature point.
static void compute_periodic_node_constraints(NodeConstraints &constraints, const PeriodicBoundaries &boundaries, const MeshBase &mesh, const PointLocatorBase *point_locator, const Elem *elem)
Computes the node position constraint equation contributions (for meshes with periodic boundary condi...
virtual unsigned int n_quadrature_points() const
QBase * qrule
A pointer to the quadrature rule employed.
static bool on_reference_element(const Point &p, const ElemType t, const Real eps=TOLERANCE)
static std::unique_ptr< FEAbstract > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
Definition fe_abstract.C:78
virtual void print_phi(std::ostream &os) const =0
Prints the value of each shape function at each quadrature point.
unsigned int _n_total_qp
The total number of quadrature points for the current configuration.
void print_xyz(std::ostream &os) const
Prints the spatial location of each quadrature point (on the physical element).
void print_info(std::ostream &os) const
Prints all the relevant information about the current element.
static void get_refspace_nodes(const ElemType t, std::vector< Point > &nodes)
static Real shape(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const Point &p)
static unsigned int n_dofs(const unsigned int dim, const FEType &fe_t, const ElemType t)
static unsigned int max_order(const FEType &fe_t, const ElemType &el_t)
Class contained in FE that encapsulates mapping (i.e.
Definition fe_map.h:48
static FEFamily map_fe_type(const Elem &elem)
Definition fe_map.C:46
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition fe_map.C:1512
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
OrderWrapper order
The approximation order of the element (at 0 p-refinement level).
Definition fe_type.h:203
FEFamily family
The type of finite element.
Definition fe_type.h:228
This is the MeshBase class.
Definition mesh_base.h:81
The Node constraint storage format.
Definition dof_map.h:160
A Node is like a Point, but with more information.
Definition node.h:55
We're using a class instead of a typedef to allow forward declarations and future flexibility.
PeriodicBoundaryBase * boundary(boundary_id_type id)
const Elem * neighbor(boundary_id_type boundary_id, const PointLocatorBase &point_locator, const Elem *e, unsigned int side, unsigned int *neigh_side=nullptr) const
The base class for defining periodic boundaries.
virtual Point get_corresponding_pos(const Point &pt) const =0
This function should be overridden by derived classes to define how one finds corresponding nodes on ...
This is the base class for point locators.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
unsigned int n_points() const
Definition quadrature.h:131
MeshBase & mesh
spin_mutex spin_mtx
A convenient spin mutex object which can be used for obtaining locks.
Definition threads.C:30
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
std::map< const Node *, Real, std::less< const Node * >, Threads::scalable_allocator< std::pair< const Node *const, Real > > > NodeConstraintRow
A row of the Node constraint mapping.
Definition dof_map.h:148
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
std::ostream & operator<<(std::ostream &os, const OrderWrapper &order)
Overload stream operators.
Definition fe_type.h:182
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition libmesh.h:303
const RemoteElem * remote_elem
Definition remote_elem.C:57
@ L2_RAVIART_THOMAS
@ L2_HIERARCHIC_VEC
@ RATIONAL_BERNSTEIN
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const dof_id_type n_nodes
Definition tecplot_io.C:67