libMesh
Loading...
Searching...
No Matches
fe_lagrange_shape_2D.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19// Local includes
20#include "libmesh/fe.h"
21#include "libmesh/elem.h"
22#include "libmesh/fe_lagrange_shape_1D.h"
23#include "libmesh/enum_to_string.h"
24#include "libmesh/face_c0polygon.h"
25
26// Anonymous namespace for functions shared by LAGRANGE and
27// L2_LAGRANGE implementations. Implementations appear at the bottom
28// of this file.
29namespace
30{
31using namespace libMesh;
32
33template <FEFamily T>
34Real fe_lagrange_2D_shape(const ElemType,
35 const Elem * elem,
36 const Order order,
37 const unsigned int i,
38 const Point & p);
39
40template <FEFamily T>
41Real fe_lagrange_2D_shape_deriv(const ElemType type,
42 const Elem * elem,
43 const Order order,
44 const unsigned int i,
45 const unsigned int j,
46 const Point & p);
47
48#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
49
50template <FEFamily T>
51Real fe_lagrange_2D_shape_second_deriv(const ElemType type,
52 const Elem * elem,
53 const Order order,
54 const unsigned int i,
55 const unsigned int j,
56 const Point & p);
57
58#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
59
60} // anonymous namespace
61
62
63
64namespace libMesh
65{
66
67
70
71
72template <>
74 const Order order,
75 const unsigned int i,
76 const Point & p)
77{
78 return fe_lagrange_2D_shape<LAGRANGE>(type, nullptr, order, i, p);
79}
80
81
82
83template <>
85 const Order order,
86 const unsigned int i,
87 const Point & p)
88{
89 return fe_lagrange_2D_shape<L2_LAGRANGE>(type, nullptr, order, i, p);
90}
91
92
93template <>
95 const Order order,
96 const unsigned int i,
97 const Point & p,
98 const bool add_p_level)
99{
100 libmesh_assert(elem);
101
102 // call the orientation-independent shape functions
103 return fe_lagrange_2D_shape<LAGRANGE>(elem->type(), elem, order + add_p_level*elem->p_level(), i, p);
104}
105
106
107
108template <>
110 const Order order,
111 const unsigned int i,
112 const Point & p,
113 const bool add_p_level)
114{
115 libmesh_assert(elem);
116
117 // call the orientation-independent shape functions
118 return fe_lagrange_2D_shape<L2_LAGRANGE>(elem->type(), elem, order + add_p_level*elem->p_level(), i, p);
119}
120
121
122template <>
124 const Elem * elem,
125 const unsigned int i,
126 const Point & p,
127 const bool add_p_level)
128{
129 libmesh_assert(elem);
130 return fe_lagrange_2D_shape<LAGRANGE>(elem->type(), elem, fet.order + add_p_level*elem->p_level(), i, p);
131}
132
133
134
135template <>
137 const Elem * elem,
138 const unsigned int i,
139 const Point & p,
140 const bool add_p_level)
141{
142 libmesh_assert(elem);
143 return fe_lagrange_2D_shape<L2_LAGRANGE>(elem->type(), elem, fet.order + add_p_level*elem->p_level(), i, p);
144}
145
146
147template <>
149 const Order order,
150 const unsigned int i,
151 const unsigned int j,
152 const Point & p)
153{
154 return fe_lagrange_2D_shape_deriv<LAGRANGE>(type, nullptr, order, i, j, p);
155}
156
157
158
159template <>
161 const Order order,
162 const unsigned int i,
163 const unsigned int j,
164 const Point & p)
165{
166 return fe_lagrange_2D_shape_deriv<L2_LAGRANGE>(type, nullptr, order, i, j, p);
167}
168
169
170
171template <>
173 const Order order,
174 const unsigned int i,
175 const unsigned int j,
176 const Point & p,
177 const bool add_p_level)
178{
179 libmesh_assert(elem);
180
181 // call the orientation-independent shape functions
182 return fe_lagrange_2D_shape_deriv<LAGRANGE>(elem->type(), elem, order + add_p_level*elem->p_level(), i, j, p);
183}
184
185
186
187template <>
189 const Order order,
190 const unsigned int i,
191 const unsigned int j,
192 const Point & p,
193 const bool add_p_level)
194{
195 libmesh_assert(elem);
196
197 // call the orientation-independent shape functions
198 return fe_lagrange_2D_shape_deriv<L2_LAGRANGE>(elem->type(), elem, order + add_p_level*elem->p_level(), i, j, p);
199}
200
201
202template <>
204 const Elem * elem,
205 const unsigned int i,
206 const unsigned int j,
207 const Point & p,
208 const bool add_p_level)
209{
210 libmesh_assert(elem);
211 return fe_lagrange_2D_shape_deriv<LAGRANGE>(elem->type(), elem, fet.order + add_p_level*elem->p_level(), i, j, p);
212}
213
214
215
216template <>
218 const Elem * elem,
219 const unsigned int i,
220 const unsigned int j,
221 const Point & p,
222 const bool add_p_level)
223{
224 libmesh_assert(elem);
225 return fe_lagrange_2D_shape_deriv<L2_LAGRANGE>(elem->type(), elem, fet.order + add_p_level*elem->p_level(), i, j, p);
226}
227
228
229
230#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
231
232template <>
234 const Order order,
235 const unsigned int i,
236 const unsigned int j,
237 const Point & p)
238{
239 return fe_lagrange_2D_shape_second_deriv<LAGRANGE>(type, nullptr, order, i, j, p);
240}
241
242
243
244template <>
246 const Order order,
247 const unsigned int i,
248 const unsigned int j,
249 const Point & p)
250{
251 return fe_lagrange_2D_shape_second_deriv<L2_LAGRANGE>(type, nullptr, order, i, j, p);
252}
253
254
255
256template <>
258 const Order order,
259 const unsigned int i,
260 const unsigned int j,
261 const Point & p,
262 const bool add_p_level)
263{
264 libmesh_assert(elem);
265
266 // call the orientation-independent shape functions
267 return fe_lagrange_2D_shape_second_deriv<LAGRANGE>(elem->type(), elem, order + add_p_level*elem->p_level(), i, j, p);
268}
269
270
271
272template <>
274 const Order order,
275 const unsigned int i,
276 const unsigned int j,
277 const Point & p,
278 const bool add_p_level)
279{
280 libmesh_assert(elem);
281
282 // call the orientation-independent shape functions
283 return fe_lagrange_2D_shape_second_deriv<L2_LAGRANGE>(elem->type(), elem, order + add_p_level*elem->p_level(), i, j, p);
284}
285
286
287template <>
289 const Elem * elem,
290 const unsigned int i,
291 const unsigned int j,
292 const Point & p,
293 const bool add_p_level)
294{
295 libmesh_assert(elem);
296 return fe_lagrange_2D_shape_second_deriv<LAGRANGE>(elem->type(), elem, fet.order + add_p_level*elem->p_level(), i, j, p);
297}
298
299
300
301template <>
303 const Elem * elem,
304 const unsigned int i,
305 const unsigned int j,
306 const Point & p,
307 const bool add_p_level)
308{
309 libmesh_assert(elem);
310 return fe_lagrange_2D_shape_second_deriv<L2_LAGRANGE>(elem->type(), elem, fet.order + add_p_level*elem->p_level(), i, j, p);
311}
312
313#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
314
315} // namespace libMesh
316
317
318
319
320// Anonymous namespace function definitions
321namespace
322{
323using namespace libMesh;
324
325template <FEFamily T>
326Real fe_lagrange_2D_shape(const ElemType type,
327 const Elem * elem,
328 const Order order,
329 const unsigned int i,
330 const Point & p)
331{
332#if LIBMESH_DIM > 1
333
334 switch (order)
335 {
336 // linear Lagrange shape functions
337 case FIRST:
338 {
339 switch (type)
340 {
341 case QUAD4:
342 case QUADSHELL4:
343 case QUAD8:
344 case QUADSHELL8:
345 case QUAD9:
346 case QUADSHELL9:
347 {
348 // Compute quad shape functions as a tensor-product
349 const Real xi = p(0);
350 const Real eta = p(1);
351
352 libmesh_assert_less (i, 4);
353
354 // 0 1 2 3
355 static const unsigned int i0[] = {0, 1, 1, 0};
356 static const unsigned int i1[] = {0, 0, 1, 1};
357
358 return (fe_lagrange_1D_linear_shape(i0[i], xi)*
359 fe_lagrange_1D_linear_shape(i1[i], eta));
360 }
361
362 case TRI3:
363 case TRISHELL3:
364 case TRI6:
365 case TRI7:
366 {
367 const Real zeta1 = p(0);
368 const Real zeta2 = p(1);
369 const Real zeta0 = 1. - zeta1 - zeta2;
370
371 libmesh_assert_less (i, 3);
372
373 switch(i)
374 {
375 case 0:
376 return zeta0;
377
378 case 1:
379 return zeta1;
380
381 case 2:
382 return zeta2;
383
384 default:
385 libmesh_error_msg("Invalid shape function index i = " << i);
386 }
387 }
388
389 case C0POLYGON:
390 {
391 // C0Polygon requires using newer FE APIs
392 if (!elem)
393 libmesh_error_msg("Code (see stack trace) used an outdated FE function overload.\n"
394 "Shape functions on a C0Polygon are not defined by its ElemType alone.");
395
396 libmesh_assert(elem->type() == C0POLYGON);
397
398 const C0Polygon & poly = *cast_ptr<const C0Polygon *>(elem);
399
400 // We can't use a small tolerance here, because in
401 // inverse_map() Newton might hand us intermediate
402 // iterates outside the polygon.
403 const auto [s, a, b] = poly.subtriangle_coordinates(p, 100);
404 if (s == invalid_uint)
405 return 0;
406 libmesh_assert_less(s, poly.n_subtriangles());
407
408 const auto subtri = poly.subtriangle(s);
409
410 // Avoid signed/unsigned comparison warnings
411 const int nodei = i;
412 if (nodei == subtri[0])
413 return 1-a-b;
414 if (nodei == subtri[1])
415 return a;
416 if (nodei == subtri[2])
417 return b;
418
419 // Basis function i is not supported on p's subtriangle
420 return 0;
421 }
422
423 default:
424 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
425 }
426 }
427
428
429 // quadratic Lagrange shape functions
430 case SECOND:
431 {
432 switch (type)
433 {
434 case QUAD8:
435 case QUADSHELL8:
436 {
437 const Real xi = p(0);
438 const Real eta = p(1);
439
440 libmesh_assert_less (i, 8);
441
442 switch (i)
443 {
444 case 0:
445 return .25*(1. - xi)*(1. - eta)*(-1. - xi - eta);
446
447 case 1:
448 return .25*(1. + xi)*(1. - eta)*(-1. + xi - eta);
449
450 case 2:
451 return .25*(1. + xi)*(1. + eta)*(-1. + xi + eta);
452
453 case 3:
454 return .25*(1. - xi)*(1. + eta)*(-1. - xi + eta);
455
456 case 4:
457 return .5*(1. - xi*xi)*(1. - eta);
458
459 case 5:
460 return .5*(1. + xi)*(1. - eta*eta);
461
462 case 6:
463 return .5*(1. - xi*xi)*(1. + eta);
464
465 case 7:
466 return .5*(1. - xi)*(1. - eta*eta);
467
468 default:
469 libmesh_error_msg("Invalid shape function index i = " << i);
470 }
471 }
472
473 case QUAD4:
474 libmesh_assert_msg(T == L2_LAGRANGE,
475 "High order on first order elements only supported for L2 families");
476 libmesh_fallthrough();
477 case QUAD9:
478 case QUADSHELL9:
479 {
480
481 // Compute quad shape functions as a tensor-product
482 const Real xi = p(0);
483 const Real eta = p(1);
484
485 libmesh_assert_less (i, 9);
486
487 // 0 1 2 3 4 5 6 7 8
488 static const unsigned int i0[] = {0, 1, 1, 0, 2, 1, 2, 0, 2};
489 static const unsigned int i1[] = {0, 0, 1, 1, 0, 2, 1, 2, 2};
490
491 return (fe_lagrange_1D_quadratic_shape(i0[i], xi)*
493 }
494
495 case TRI3:
496 libmesh_assert_msg(T == L2_LAGRANGE,
497 "High order on first order elements only supported for L2 families");
498 libmesh_fallthrough();
499 case TRI6:
500 case TRI7:
501 {
502 const Real zeta1 = p(0);
503 const Real zeta2 = p(1);
504 const Real zeta0 = 1. - zeta1 - zeta2;
505
506 libmesh_assert_less (i, 6);
507
508 switch(i)
509 {
510 case 0:
511 return 2.*zeta0*(zeta0-0.5);
512
513 case 1:
514 return 2.*zeta1*(zeta1-0.5);
515
516 case 2:
517 return 2.*zeta2*(zeta2-0.5);
518
519 case 3:
520 return 4.*zeta0*zeta1;
521
522 case 4:
523 return 4.*zeta1*zeta2;
524
525 case 5:
526 return 4.*zeta2*zeta0;
527
528 default:
529 libmesh_error_msg("Invalid shape function index i = " << i);
530 }
531 }
532
533 default:
534 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
535 }
536 }
537
538
539
540 // "cubic" (one cubic bubble) Lagrange shape functions on TRI7
541 case THIRD:
542 {
543 switch (type)
544 {
545 case TRI7:
546 {
547 const Real zeta1 = p(0);
548 const Real zeta2 = p(1);
549 const Real zeta0 = 1. - zeta1 - zeta2;
550 const Real bubble_27th = zeta0*zeta1*zeta2;
551
552 libmesh_assert_less (i, 7);
553
554 switch(i)
555 {
556 case 0:
557 return 2.*zeta0*(zeta0-0.5) + 3.*bubble_27th;
558
559 case 1:
560 return 2.*zeta1*(zeta1-0.5) + 3.*bubble_27th;
561
562 case 2:
563 return 2.*zeta2*(zeta2-0.5) + 3.*bubble_27th;
564
565 case 3:
566 return 4.*zeta0*zeta1 - 12.*bubble_27th;
567
568 case 4:
569 return 4.*zeta1*zeta2 - 12.*bubble_27th;
570
571 case 5:
572 return 4.*zeta2*zeta0 - 12.*bubble_27th;
573
574 case 6:
575 return 27.*bubble_27th;
576
577 default:
578 libmesh_error_msg("Invalid shape function index i = " << i);
579 }
580 }
581
582 default:
583 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
584 }
585 } // end case THIRD
586
587
588
589 // unsupported order
590 default:
591 libmesh_error_msg("ERROR: Unsupported 2D FE order: " << order);
592 }
593#else // LIBMESH_DIM > 1
594 libmesh_ignore(type, order, i, p);
595 libmesh_not_implemented();
596#endif
597}
598
599
600
601template <FEFamily T>
602Real fe_lagrange_2D_shape_deriv(const ElemType type,
603 const Elem * elem,
604 const Order order,
605 const unsigned int i,
606 const unsigned int j,
607 const Point & p)
608{
609#if LIBMESH_DIM > 1
610
611 libmesh_assert_less (j, 2);
612
613 switch (order)
614 {
615 // linear Lagrange shape functions
616 case FIRST:
617 {
618 switch (type)
619 {
620 case QUAD4:
621 case QUADSHELL4:
622 case QUAD8:
623 case QUADSHELL8:
624 case QUAD9:
625 case QUADSHELL9:
626 {
627 // Compute quad shape functions as a tensor-product
628 const Real xi = p(0);
629 const Real eta = p(1);
630
631 libmesh_assert_less (i, 4);
632
633 // 0 1 2 3
634 static const unsigned int i0[] = {0, 1, 1, 0};
635 static const unsigned int i1[] = {0, 0, 1, 1};
636
637 switch (j)
638 {
639 // d()/dxi
640 case 0:
641 return (fe_lagrange_1D_linear_shape_deriv(i0[i], 0, xi)*
642 fe_lagrange_1D_linear_shape (i1[i], eta));
643
644 // d()/deta
645 case 1:
646 return (fe_lagrange_1D_linear_shape (i0[i], xi)*
647 fe_lagrange_1D_linear_shape_deriv(i1[i], 0, eta));
648
649 default:
650 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
651 }
652 }
653
654 case TRI3:
655 case TRISHELL3:
656 case TRI6:
657 case TRI7:
658 {
659 libmesh_assert_less (i, 3);
660
661 const Real dzeta0dxi = -1.;
662 const Real dzeta1dxi = 1.;
663 const Real dzeta2dxi = 0.;
664
665 const Real dzeta0deta = -1.;
666 const Real dzeta1deta = 0.;
667 const Real dzeta2deta = 1.;
668
669 switch (j)
670 {
671 // d()/dxi
672 case 0:
673 {
674 switch(i)
675 {
676 case 0:
677 return dzeta0dxi;
678
679 case 1:
680 return dzeta1dxi;
681
682 case 2:
683 return dzeta2dxi;
684
685 default:
686 libmesh_error_msg("Invalid shape function index i = " << i);
687 }
688 }
689 // d()/deta
690 case 1:
691 {
692 switch(i)
693 {
694 case 0:
695 return dzeta0deta;
696
697 case 1:
698 return dzeta1deta;
699
700 case 2:
701 return dzeta2deta;
702
703 default:
704 libmesh_error_msg("Invalid shape function index i = " << i);
705 }
706 }
707 default:
708 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
709 }
710 }
711
712 case C0POLYGON:
713 {
714 // C0Polygon requires using newer FE APIs
715 if (!elem)
716 libmesh_error_msg("Code (see stack trace) used an outdated FE function overload.\n"
717 "Shape functions on a C0Polygon are not defined by its ElemType alone.");
718
719 libmesh_assert(elem->type() == C0POLYGON);
720
721 const C0Polygon & poly = *cast_ptr<const C0Polygon *>(elem);
722
723 // We can't use a small tolerance here, because in
724 // inverse_map() Newton might hand us intermediate
725 // iterates outside the polygon.
726 const auto [s, a, b] = poly.subtriangle_coordinates(p, 100);
727 if (s == invalid_uint)
728 return 0;
729 libmesh_assert_less(s, poly.n_subtriangles());
730
731 const auto subtri = poly.subtriangle(s);
732
733 // Find derivatives w.r.t. subtriangle barycentric
734 // coordinates
735 Real du_da = 0, du_db = 0;
736
737 // Avoid signed/unsigned comparison warnings
738 const int nodei = i;
739 if (nodei == subtri[0])
740 du_da = du_db = -1;
741 else if (nodei == subtri[1])
742 du_da = 1;
743 else if (nodei == subtri[2])
744 du_db = 1;
745 else
746 // Basis function i is not supported on p's subtriangle
747 return 0;
748
749 // We want to return derivatives with respect to xi and
750 // eta in master space for the polygon, but what we
751 // calculated above are with respect to xi and eta
752 // coordinates for a master *triangle*. We need to
753 // convert from one to the other.
754
755 const auto master_points = poly.master_subtriangle(s);
756
757 const Real dxi_da = master_points[1](0) - master_points[0](0);
758 const Real dxi_db = master_points[2](0) - master_points[0](0);
759 const Real deta_da = master_points[1](1) - master_points[0](1);
760 const Real deta_db = master_points[2](1) - master_points[0](1);
761 const Real jac = dxi_da*deta_db - dxi_db*deta_da;
762
763 switch (j)
764 {
765 // d()/dxi
766 case 0:
767 {
768 const Real da_dxi = deta_db / jac;
769 const Real db_dxi = -deta_da / jac;
770 return du_da*da_dxi + du_db*db_dxi;
771 }
772 // d()/deta
773 case 1:
774 {
775 const Real da_deta = -dxi_db / jac;
776 const Real db_deta = dxi_da / jac;
777 return du_da*da_deta + du_db*db_deta;
778 }
779 default:
780 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
781 }
782 }
783
784 default:
785 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
786 }
787 }
788
789
790 // quadratic Lagrange shape functions
791 case SECOND:
792 {
793 switch (type)
794 {
795 case QUAD8:
796 case QUADSHELL8:
797 {
798 const Real xi = p(0);
799 const Real eta = p(1);
800
801 libmesh_assert_less (i, 8);
802
803 switch (j)
804 {
805 // d/dxi
806 case 0:
807 switch (i)
808 {
809 case 0:
810 return .25*(1. - eta)*((1. - xi)*(-1.) +
811 (-1.)*(-1. - xi - eta));
812
813 case 1:
814 return .25*(1. - eta)*((1. + xi)*(1.) +
815 (1.)*(-1. + xi - eta));
816
817 case 2:
818 return .25*(1. + eta)*((1. + xi)*(1.) +
819 (1.)*(-1. + xi + eta));
820
821 case 3:
822 return .25*(1. + eta)*((1. - xi)*(-1.) +
823 (-1.)*(-1. - xi + eta));
824
825 case 4:
826 return .5*(-2.*xi)*(1. - eta);
827
828 case 5:
829 return .5*(1.)*(1. - eta*eta);
830
831 case 6:
832 return .5*(-2.*xi)*(1. + eta);
833
834 case 7:
835 return .5*(-1.)*(1. - eta*eta);
836
837 default:
838 libmesh_error_msg("Invalid shape function index i = " << i);
839 }
840
841 // d/deta
842 case 1:
843 switch (i)
844 {
845 case 0:
846 return .25*(1. - xi)*((1. - eta)*(-1.) +
847 (-1.)*(-1. - xi - eta));
848
849 case 1:
850 return .25*(1. + xi)*((1. - eta)*(-1.) +
851 (-1.)*(-1. + xi - eta));
852
853 case 2:
854 return .25*(1. + xi)*((1. + eta)*(1.) +
855 (1.)*(-1. + xi + eta));
856
857 case 3:
858 return .25*(1. - xi)*((1. + eta)*(1.) +
859 (1.)*(-1. - xi + eta));
860
861 case 4:
862 return .5*(1. - xi*xi)*(-1.);
863
864 case 5:
865 return .5*(1. + xi)*(-2.*eta);
866
867 case 6:
868 return .5*(1. - xi*xi)*(1.);
869
870 case 7:
871 return .5*(1. - xi)*(-2.*eta);
872
873 default:
874 libmesh_error_msg("Invalid shape function index i = " << i);
875 }
876
877 default:
878 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
879 }
880 }
881
882 case QUAD4:
883 libmesh_assert_msg(T == L2_LAGRANGE,
884 "High order on first order elements only supported for L2 families");
885 libmesh_fallthrough();
886 case QUAD9:
887 case QUADSHELL9:
888 {
889 // Compute quad shape functions as a tensor-product
890 const Real xi = p(0);
891 const Real eta = p(1);
892
893 libmesh_assert_less (i, 9);
894
895 // 0 1 2 3 4 5 6 7 8
896 static const unsigned int i0[] = {0, 1, 1, 0, 2, 1, 2, 0, 2};
897 static const unsigned int i1[] = {0, 0, 1, 1, 0, 2, 1, 2, 2};
898
899 switch (j)
900 {
901 // d()/dxi
902 case 0:
903 return (fe_lagrange_1D_quadratic_shape_deriv(i0[i], 0, xi)*
904 fe_lagrange_1D_quadratic_shape (i1[i], eta));
905
906 // d()/deta
907 case 1:
908 return (fe_lagrange_1D_quadratic_shape (i0[i], xi)*
910
911 default:
912 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
913 }
914 }
915
916 case TRI3:
917 libmesh_assert_msg(T == L2_LAGRANGE,
918 "High order on first order elements only supported for L2 families");
919 libmesh_fallthrough();
920 case TRI6:
921 case TRI7:
922 {
923 libmesh_assert_less (i, 6);
924
925 const Real zeta1 = p(0);
926 const Real zeta2 = p(1);
927 const Real zeta0 = 1. - zeta1 - zeta2;
928
929 const Real dzeta0dxi = -1.;
930 const Real dzeta1dxi = 1.;
931 const Real dzeta2dxi = 0.;
932
933 const Real dzeta0deta = -1.;
934 const Real dzeta1deta = 0.;
935 const Real dzeta2deta = 1.;
936
937 switch(j)
938 {
939 case 0:
940 {
941 switch(i)
942 {
943 case 0:
944 return (4.*zeta0-1.)*dzeta0dxi;
945
946 case 1:
947 return (4.*zeta1-1.)*dzeta1dxi;
948
949 case 2:
950 return (4.*zeta2-1.)*dzeta2dxi;
951
952 case 3:
953 return 4.*zeta1*dzeta0dxi + 4.*zeta0*dzeta1dxi;
954
955 case 4:
956 return 4.*zeta2*dzeta1dxi + 4.*zeta1*dzeta2dxi;
957
958 case 5:
959 return 4.*zeta2*dzeta0dxi + 4*zeta0*dzeta2dxi;
960
961 default:
962 libmesh_error_msg("Invalid shape function index i = " << i);
963 }
964 }
965
966 case 1:
967 {
968 switch(i)
969 {
970 case 0:
971 return (4.*zeta0-1.)*dzeta0deta;
972
973 case 1:
974 return (4.*zeta1-1.)*dzeta1deta;
975
976 case 2:
977 return (4.*zeta2-1.)*dzeta2deta;
978
979 case 3:
980 return 4.*zeta1*dzeta0deta + 4.*zeta0*dzeta1deta;
981
982 case 4:
983 return 4.*zeta2*dzeta1deta + 4.*zeta1*dzeta2deta;
984
985 case 5:
986 return 4.*zeta2*dzeta0deta + 4*zeta0*dzeta2deta;
987
988 default:
989 libmesh_error_msg("Invalid shape function index i = " << i);
990 }
991 }
992 default:
993 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
994 }
995 }
996
997 default:
998 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
999 }
1000 }
1001
1002
1003
1004 // "cubic" (one cubic bubble) Lagrange shape functions on TRI7
1005 case THIRD:
1006 {
1007 switch (type)
1008 {
1009 case TRI7:
1010 {
1011 libmesh_assert_less (i, 7);
1012
1013 const Real zeta1 = p(0);
1014 const Real zeta2 = p(1);
1015 const Real zeta0 = 1. - zeta1 - zeta2;
1016 // const Real bubble_27th = zeta0*zeta1*zeta2;
1017
1018 const Real dzeta0dxi = -1.;
1019 const Real dzeta1dxi = 1.;
1020 const Real dzeta2dxi = 0.;
1021 const Real dbubbledxi = zeta2 * (1. - 2.*zeta1 - zeta2);
1022
1023 const Real dzeta0deta = -1.;
1024 const Real dzeta1deta = 0.;
1025 const Real dzeta2deta = 1.;
1026 const Real dbubbledeta= zeta1 * (1. - zeta1 - 2.*zeta2);
1027
1028 switch(j)
1029 {
1030 case 0:
1031 {
1032 switch(i)
1033 {
1034 case 0:
1035 return (4.*zeta0-1.)*dzeta0dxi + 3.*dbubbledxi;
1036
1037 case 1:
1038 return (4.*zeta1-1.)*dzeta1dxi + 3.*dbubbledxi;
1039
1040 case 2:
1041 return (4.*zeta2-1.)*dzeta2dxi + 3.*dbubbledxi;
1042
1043 case 3:
1044 return 4.*zeta1*dzeta0dxi + 4.*zeta0*dzeta1dxi - 12.*dbubbledxi;
1045
1046 case 4:
1047 return 4.*zeta2*dzeta1dxi + 4.*zeta1*dzeta2dxi - 12.*dbubbledxi;
1048
1049 case 5:
1050 return 4.*zeta2*dzeta0dxi + 4*zeta0*dzeta2dxi - 12.*dbubbledxi;
1051
1052 case 6:
1053 return 27.*dbubbledxi;
1054
1055 default:
1056 libmesh_error_msg("Invalid shape function index i = " << i);
1057 }
1058 }
1059
1060 case 1:
1061 {
1062 switch(i)
1063 {
1064 case 0:
1065 return (4.*zeta0-1.)*dzeta0deta + 3.*dbubbledeta;
1066
1067 case 1:
1068 return (4.*zeta1-1.)*dzeta1deta + 3.*dbubbledeta;
1069
1070 case 2:
1071 return (4.*zeta2-1.)*dzeta2deta + 3.*dbubbledeta;
1072
1073 case 3:
1074 return 4.*zeta1*dzeta0deta + 4.*zeta0*dzeta1deta - 12.*dbubbledeta;
1075
1076 case 4:
1077 return 4.*zeta2*dzeta1deta + 4.*zeta1*dzeta2deta - 12.*dbubbledeta;
1078
1079 case 5:
1080 return 4.*zeta2*dzeta0deta + 4*zeta0*dzeta2deta - 12.*dbubbledeta;
1081
1082 case 6:
1083 return 27.*dbubbledeta;
1084
1085 default:
1086 libmesh_error_msg("Invalid shape function index i = " << i);
1087 }
1088 }
1089 default:
1090 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
1091 }
1092 }
1093
1094 default:
1095 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
1096 }
1097 } // end case THIRD
1098
1099
1100
1101 // unsupported order
1102 default:
1103 libmesh_error_msg("ERROR: Unsupported 2D FE order: " << order);
1104 }
1105#else // LIBMESH_DIM > 1
1106 libmesh_ignore(type, order, i, j, p);
1107 libmesh_not_implemented();
1108#endif
1109}
1110
1111
1112
1113#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1114
1115template <FEFamily T>
1116Real fe_lagrange_2D_shape_second_deriv(const ElemType type,
1117 const Elem *,
1118 const Order order,
1119 const unsigned int i,
1120 const unsigned int j,
1121 const Point & p)
1122{
1123#if LIBMESH_DIM > 1
1124
1125 // j = 0 ==> d^2 phi / dxi^2
1126 // j = 1 ==> d^2 phi / dxi deta
1127 // j = 2 ==> d^2 phi / deta^2
1128 libmesh_assert_less (j, 3);
1129
1130 switch (order)
1131 {
1132 // linear Lagrange shape functions
1133 case FIRST:
1134 {
1135 switch (type)
1136 {
1137 case QUAD4:
1138 case QUADSHELL4:
1139 case QUAD8:
1140 case QUADSHELL8:
1141 case QUAD9:
1142 case QUADSHELL9:
1143 {
1144 // Compute quad shape functions as a tensor-product
1145 const Real xi = p(0);
1146 const Real eta = p(1);
1147
1148 libmesh_assert_less (i, 4);
1149
1150 // 0 1 2 3
1151 static const unsigned int i0[] = {0, 1, 1, 0};
1152 static const unsigned int i1[] = {0, 0, 1, 1};
1153
1154 switch (j)
1155 {
1156 // d^2() / dxi^2
1157 case 0:
1158 return 0.;
1159
1160 // d^2() / dxi deta
1161 case 1:
1162 return (fe_lagrange_1D_linear_shape_deriv(i0[i], 0, xi)*
1163 fe_lagrange_1D_linear_shape_deriv(i1[i], 0, eta));
1164
1165 // d^2() / deta^2
1166 case 2:
1167 return 0.;
1168
1169 default:
1170 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
1171 }
1172 }
1173
1174 // All second derivatives for linear triangles are zero.
1175 case TRI3:
1176 case TRISHELL3:
1177 case TRI6:
1178 case TRI7:
1179
1180 // All second derivatives for piecewise-linear polygons are
1181 // zero or dirac-type distributions, but we can't put the
1182 // latter in a Real, so beware when integrating...
1183 case C0POLYGON:
1184 {
1185 return 0.;
1186 }
1187
1188 default:
1189 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
1190
1191 } // end switch (type)
1192 } // end case FIRST
1193
1194
1195 // quadratic Lagrange shape functions
1196 case SECOND:
1197 {
1198 switch (type)
1199 {
1200 case QUAD8:
1201 case QUADSHELL8:
1202 {
1203 const Real xi = p(0);
1204 const Real eta = p(1);
1205
1206 libmesh_assert_less (j, 3);
1207
1208 switch (j)
1209 {
1210 // d^2() / dxi^2
1211 case 0:
1212 {
1213 switch (i)
1214 {
1215 case 0:
1216 case 1:
1217 return 0.5*(1.-eta);
1218
1219 case 2:
1220 case 3:
1221 return 0.5*(1.+eta);
1222
1223 case 4:
1224 return eta - 1.;
1225
1226 case 5:
1227 case 7:
1228 return 0.0;
1229
1230 case 6:
1231 return -1. - eta;
1232
1233 default:
1234 libmesh_error_msg("Invalid shape function index i = " << i);
1235 }
1236 }
1237
1238 // d^2() / dxi deta
1239 case 1:
1240 {
1241 switch (i)
1242 {
1243 case 0:
1244 return 0.25*( 1. - 2.*xi - 2.*eta);
1245
1246 case 1:
1247 return 0.25*(-1. - 2.*xi + 2.*eta);
1248
1249 case 2:
1250 return 0.25*( 1. + 2.*xi + 2.*eta);
1251
1252 case 3:
1253 return 0.25*(-1. + 2.*xi - 2.*eta);
1254
1255 case 4:
1256 return xi;
1257
1258 case 5:
1259 return -eta;
1260
1261 case 6:
1262 return -xi;
1263
1264 case 7:
1265 return eta;
1266
1267 default:
1268 libmesh_error_msg("Invalid shape function index i = " << i);
1269 }
1270 }
1271
1272 // d^2() / deta^2
1273 case 2:
1274 {
1275 switch (i)
1276 {
1277 case 0:
1278 case 3:
1279 return 0.5*(1.-xi);
1280
1281 case 1:
1282 case 2:
1283 return 0.5*(1.+xi);
1284
1285 case 4:
1286 case 6:
1287 return 0.0;
1288
1289 case 5:
1290 return -1.0 - xi;
1291
1292 case 7:
1293 return xi - 1.0;
1294
1295 default:
1296 libmesh_error_msg("Invalid shape function index i = " << i);
1297 }
1298 }
1299
1300 default:
1301 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
1302 } // end switch (j)
1303 } // end case QUAD8
1304
1305 case QUAD4:
1306 libmesh_assert_msg(T == L2_LAGRANGE,
1307 "High order on first order elements only supported for L2 families");
1308 libmesh_fallthrough();
1309 case QUAD9:
1310 case QUADSHELL9:
1311 {
1312 // Compute QUAD9 second derivatives as tensor product
1313 const Real xi = p(0);
1314 const Real eta = p(1);
1315
1316 libmesh_assert_less (i, 9);
1317
1318 // 0 1 2 3 4 5 6 7 8
1319 static const unsigned int i0[] = {0, 1, 1, 0, 2, 1, 2, 0, 2};
1320 static const unsigned int i1[] = {0, 0, 1, 1, 0, 2, 1, 2, 2};
1321
1322 switch (j)
1323 {
1324 // d^2() / dxi^2
1325 case 0:
1326 return (fe_lagrange_1D_quadratic_shape_second_deriv(i0[i], 0, xi)*
1327 fe_lagrange_1D_quadratic_shape (i1[i], eta));
1328
1329 // d^2() / dxi deta
1330 case 1:
1331 return (fe_lagrange_1D_quadratic_shape_deriv(i0[i], 0, xi)*
1333
1334 // d^2() / deta^2
1335 case 2:
1336 return (fe_lagrange_1D_quadratic_shape (i0[i], xi)*
1338
1339 default:
1340 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
1341 } // end switch (j)
1342 } // end case QUAD9
1343
1344 case TRI3:
1345 libmesh_assert_msg(T == L2_LAGRANGE,
1346 "High order on first order elements only supported for L2 families");
1347 libmesh_fallthrough();
1348 case TRI6:
1349 case TRI7:
1350 {
1351 const Real dzeta0dxi = -1.;
1352 const Real dzeta1dxi = 1.;
1353 const Real dzeta2dxi = 0.;
1354
1355 const Real dzeta0deta = -1.;
1356 const Real dzeta1deta = 0.;
1357 const Real dzeta2deta = 1.;
1358
1359 libmesh_assert_less (j, 3);
1360
1361 switch (j)
1362 {
1363 // d^2() / dxi^2
1364 case 0:
1365 {
1366 switch (i)
1367 {
1368 case 0:
1369 return 4.*dzeta0dxi*dzeta0dxi;
1370
1371 case 1:
1372 return 4.*dzeta1dxi*dzeta1dxi;
1373
1374 case 2:
1375 return 4.*dzeta2dxi*dzeta2dxi;
1376
1377 case 3:
1378 return 8.*dzeta0dxi*dzeta1dxi;
1379
1380 case 4:
1381 return 8.*dzeta1dxi*dzeta2dxi;
1382
1383 case 5:
1384 return 8.*dzeta0dxi*dzeta2dxi;
1385
1386 default:
1387 libmesh_error_msg("Invalid shape function index i = " << i);
1388 }
1389 }
1390
1391 // d^2() / dxi deta
1392 case 1:
1393 {
1394 switch (i)
1395 {
1396 case 0:
1397 return 4.*dzeta0dxi*dzeta0deta;
1398
1399 case 1:
1400 return 4.*dzeta1dxi*dzeta1deta;
1401
1402 case 2:
1403 return 4.*dzeta2dxi*dzeta2deta;
1404
1405 case 3:
1406 return 4.*dzeta1deta*dzeta0dxi + 4.*dzeta0deta*dzeta1dxi;
1407
1408 case 4:
1409 return 4.*dzeta2deta*dzeta1dxi + 4.*dzeta1deta*dzeta2dxi;
1410
1411 case 5:
1412 return 4.*dzeta2deta*dzeta0dxi + 4.*dzeta0deta*dzeta2dxi;
1413
1414 default:
1415 libmesh_error_msg("Invalid shape function index i = " << i);
1416 }
1417 }
1418
1419 // d^2() / deta^2
1420 case 2:
1421 {
1422 switch (i)
1423 {
1424 case 0:
1425 return 4.*dzeta0deta*dzeta0deta;
1426
1427 case 1:
1428 return 4.*dzeta1deta*dzeta1deta;
1429
1430 case 2:
1431 return 4.*dzeta2deta*dzeta2deta;
1432
1433 case 3:
1434 return 8.*dzeta0deta*dzeta1deta;
1435
1436 case 4:
1437 return 8.*dzeta1deta*dzeta2deta;
1438
1439 case 5:
1440 return 8.*dzeta0deta*dzeta2deta;
1441
1442 default:
1443 libmesh_error_msg("Invalid shape function index i = " << i);
1444 }
1445 }
1446
1447 default:
1448 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
1449 } // end switch (j)
1450 } // end case TRI6+TRI7
1451
1452 default:
1453 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
1454 }
1455 } // end case SECOND
1456
1457
1458
1459 // "cubic" (one cubic bubble) Lagrange shape functions on TRI7
1460 case THIRD:
1461 {
1462 switch (type)
1463 {
1464 case TRI3:
1465 libmesh_assert_msg(T == L2_LAGRANGE,
1466 "High order on first order elements only supported for L2 families");
1467 libmesh_fallthrough();
1468 case TRI6:
1469 case TRI7:
1470 {
1471 const Real zeta1 = p(0);
1472 const Real zeta2 = p(1);
1473 // const Real zeta0 = 1. - zeta1 - zeta2;
1474
1475 const Real dzeta0dxi = -1.;
1476 const Real dzeta1dxi = 1.;
1477 const Real dzeta2dxi = 0.;
1478 // const Real dbubbledxi = zeta2 * (1. - 2.*zeta1 - zeta2);
1479 const Real d2bubbledxi2 = -2. * zeta2;
1480
1481 const Real dzeta0deta = -1.;
1482 const Real dzeta1deta = 0.;
1483 const Real dzeta2deta = 1.;
1484 // const Real dbubbledeta= zeta1 * (1. - zeta1 - 2.*zeta2);
1485 const Real d2bubbledeta2 = -2. * zeta1;
1486
1487 const Real d2bubbledxideta = (1. - 2.*zeta1 - 2.*zeta2);
1488
1489 libmesh_assert_less (j, 3);
1490
1491 switch (j)
1492 {
1493 // d^2() / dxi^2
1494 case 0:
1495 {
1496 switch (i)
1497 {
1498 case 0:
1499 return 4.*dzeta0dxi*dzeta0dxi + 3.*d2bubbledxi2;
1500
1501 case 1:
1502 return 4.*dzeta1dxi*dzeta1dxi + 3.*d2bubbledxi2;
1503
1504 case 2:
1505 return 4.*dzeta2dxi*dzeta2dxi + 3.*d2bubbledxi2;
1506
1507 case 3:
1508 return 8.*dzeta0dxi*dzeta1dxi - 12.*d2bubbledxi2;
1509
1510 case 4:
1511 return 8.*dzeta1dxi*dzeta2dxi - 12.*d2bubbledxi2;
1512
1513 case 5:
1514 return 8.*dzeta0dxi*dzeta2dxi - 12.*d2bubbledxi2;
1515
1516 case 6:
1517 return 27.*d2bubbledxi2;
1518
1519 default:
1520 libmesh_error_msg("Invalid shape function index i = " << i);
1521 }
1522 }
1523
1524 // d^2() / dxi deta
1525 case 1:
1526 {
1527 switch (i)
1528 {
1529 case 0:
1530 return 4.*dzeta0dxi*dzeta0deta + 3.*d2bubbledxideta;
1531
1532 case 1:
1533 return 4.*dzeta1dxi*dzeta1deta + 3.*d2bubbledxideta;
1534
1535 case 2:
1536 return 4.*dzeta2dxi*dzeta2deta + 3.*d2bubbledxideta;
1537
1538 case 3:
1539 return 4.*dzeta1deta*dzeta0dxi + 4.*dzeta0deta*dzeta1dxi - 12.*d2bubbledxideta;
1540
1541 case 4:
1542 return 4.*dzeta2deta*dzeta1dxi + 4.*dzeta1deta*dzeta2dxi - 12.*d2bubbledxideta;
1543
1544 case 5:
1545 return 4.*dzeta2deta*dzeta0dxi + 4.*dzeta0deta*dzeta2dxi - 12.*d2bubbledxideta;
1546
1547 case 6:
1548 return 27.*d2bubbledxideta;
1549
1550 default:
1551 libmesh_error_msg("Invalid shape function index i = " << i);
1552 }
1553 }
1554
1555 // d^2() / deta^2
1556 case 2:
1557 {
1558 switch (i)
1559 {
1560 case 0:
1561 return 4.*dzeta0deta*dzeta0deta + 3.*d2bubbledeta2;
1562
1563 case 1:
1564 return 4.*dzeta1deta*dzeta1deta + 3.*d2bubbledeta2;
1565
1566 case 2:
1567 return 4.*dzeta2deta*dzeta2deta + 3.*d2bubbledeta2;
1568
1569 case 3:
1570 return 8.*dzeta0deta*dzeta1deta - 12.*d2bubbledeta2;
1571
1572 case 4:
1573 return 8.*dzeta1deta*dzeta2deta - 12.*d2bubbledeta2;
1574
1575 case 5:
1576 return 8.*dzeta0deta*dzeta2deta - 12.*d2bubbledeta2;
1577
1578 case 6:
1579 return 27.*d2bubbledeta2;
1580
1581 default:
1582 libmesh_error_msg("Invalid shape function index i = " << i);
1583 }
1584 }
1585
1586 default:
1587 libmesh_error_msg("ERROR: Invalid derivative index j = " << j);
1588 } // end switch (j)
1589 } // end case TRI6+TRI7
1590
1591 default:
1592 libmesh_error_msg("ERROR: Unsupported 2D element type: " << Utility::enum_to_string(type));
1593 }
1594 } // end case THIRD
1595
1596 // unsupported order
1597 default:
1598 libmesh_error_msg("ERROR: Unsupported 2D FE order: " << order);
1599
1600 } // end switch (order)
1601
1602#else // LIBMESH_DIM > 1
1603 libmesh_ignore(type, order, i, j, p);
1604 libmesh_not_implemented();
1605#endif
1606}
1607
1608#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1609
1610} // anonymous namespace
The C0Polygon is an element in 2D with an arbitrary (but fixed) number of first-order (EDGE2) sides.
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual ElemType type() const =0
unsigned int p_level() const
Definition elem.h:3125
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
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
virtual std::array< Point, 3 > master_subtriangle(unsigned int i) const
virtual std::array< int, 3 > subtriangle(unsigned int i) const
unsigned int n_subtriangles() const
std::tuple< unsigned int, Real, Real > subtriangle_coordinates(const Point &p, Real tol=TOLERANCE *TOLERANCE) const
static const Real b
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
Real fe_lagrange_1D_quadratic_shape(const unsigned int i, const Real xi)
LIBMESH_DEFAULT_VECTORIZED_FE(template<>Real FE< 0, BERNSTEIN)
Real fe_lagrange_1D_quadratic_shape_second_deriv(const unsigned int i, const unsigned int libmesh_dbg_var(j), const Real)
Real fe_lagrange_1D_quadratic_shape_deriv(const unsigned int i, const unsigned int libmesh_dbg_var(j), const Real xi)
ElemType
Defines an enum for geometric element types.
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
Real fe_lagrange_1D_linear_shape(const unsigned int i, const Real xi)
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
Real fe_lagrange_1D_linear_shape_deriv(const unsigned int i, const unsigned int libmesh_dbg_var(j), const Real)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real