libMesh
fe_lagrange_shape_2D.C
Go to the documentation of this file.
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/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.
29 namespace
30 {
31 using namespace libMesh;
32 
33 template <FEFamily T>
34 Real fe_lagrange_2D_shape(const ElemType,
35  const Elem * elem,
36  const Order order,
37  const unsigned int i,
38  const Point & p);
39 
40 template <FEFamily T>
41 Real 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 
50 template <FEFamily T>
51 Real 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 
64 namespace libMesh
65 {
66 
67 
70 
71 
72 template <>
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 
83 template <>
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 
93 template <>
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 
108 template <>
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 
122 template <>
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 
135 template <>
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 
147 template <>
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 
159 template <>
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 
171 template <>
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 
187 template <>
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 
202 template <>
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 
216 template <>
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 
232 template <>
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 
244 template <>
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 
256 template <>
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 
272 template <>
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 
287 template <>
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 
301 template <>
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
321 namespace
322 {
323 using namespace libMesh;
324 
325 template <FEFamily T>
326 Real 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)*
492  fe_lagrange_1D_quadratic_shape(i1[i], eta));
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 
601 template <FEFamily T>
602 Real 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)*
909  fe_lagrange_1D_quadratic_shape_deriv(i1[i], 0, eta));
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 
1115 template <FEFamily T>
1116 Real 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)*
1332  fe_lagrange_1D_quadratic_shape_deriv(i1[i], 0, eta));
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
Real fe_lagrange_1D_quadratic_shape_second_deriv(const unsigned int i, const unsigned int libmesh_dbg_var(j), const Real)
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
Real fe_lagrange_1D_linear_shape_deriv(const unsigned int i, const unsigned int libmesh_dbg_var(j), const Real)
ElemType
Defines an enum for geometric element types.
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
Real fe_lagrange_1D_quadratic_shape_deriv(const unsigned int i, const unsigned int libmesh_dbg_var(j), 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:310
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
Real fe_lagrange_1D_quadratic_shape(const unsigned int i, const Real xi)
std::tuple< unsigned int, Real, Real > subtriangle_coordinates(const Point &p, Real tol=TOLERANCE *TOLERANCE) const
Definition: face_polygon.C:356
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
unsigned int p_level() const
Definition: elem.h:3108
OrderWrapper order
The approximation order of the element.
Definition: fe_type.h:215
The libMesh namespace provides an interface to certain functionality in the library.
LIBMESH_DEFAULT_VECTORIZED_FE(template<>Real FE< 0, BERNSTEIN)
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
std::string enum_to_string(const T e)
The C0Polygon is an element in 2D with an arbitrary (but fixed) number of first-order (EDGE2) sides...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
Real fe_lagrange_1D_linear_shape(const unsigned int i, const Real xi)