20 #include "libmesh/fe.h"    21 #include "libmesh/elem.h"    22 #include "libmesh/number_lookups.h"    23 #include "libmesh/enum_to_string.h"    24 #include "libmesh/cell_tet4.h"     25 #include "libmesh/cell_prism6.h"    26 #include "libmesh/face_tri3.h"     27 #include "libmesh/face_quad4.h"    36 unsigned int cube_side(
const Point & p);
    38 Point cube_side_point(
unsigned int sidenum, 
const Point & interior_point);
    40 std::array<unsigned int, 4> oriented_prism_nodes(
const Elem & elem,
    41                                                  unsigned int face_num);
    43 std::array<unsigned int, 3> oriented_tet_nodes(
const Elem & elem,
    44                                                unsigned int face_num);
    47 Real fe_hierarchic_3D_shape(
const Elem * elem,
    51                             const bool add_p_level);
    54 Real fe_hierarchic_3D_shape_deriv(
const Elem * elem,
    59                                   const bool add_p_level);
    61 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES    64 Real fe_hierarchic_3D_shape_second_deriv(
const Elem * elem,
    69                                          const bool add_p_level);
    71 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES    80   return std::min(std::min(elem->
point(a),elem->
point(b)),
    85 template <
unsigned int N_nodes>
    86 unsigned int remap_node(
unsigned int n,
    88                         unsigned int nodebegin)
    90   std::array<const Point *, N_nodes> points;
    93     points[i] = &elem.
point(nodebegin+i);
    95   std::sort(points.begin(), points.end(),
    99   const Point * pn = points[n-nodebegin];
   102     if (pn == &elem.
point(i))
   110 void cube_remap(
unsigned int & side_i,
   112                 unsigned int totalorder,
   118     side_i = remap_node<4>(side_i, side, 0);
   122   else if (side_i < 4u*totalorder)
   124       unsigned int side_node = (side_i - 4)/(totalorder-1)+4;
   125       side_node = remap_node<4>(side_node, side, 4);
   126       side_i = ((side_i - 4) % (totalorder - 1)) 
   127         + 4 + (side_node-4)*(totalorder-1);
   135       unsigned int min_side_node = remap_node<4>(0, side, 0);
   136       const bool flip = (side.point(min_side_node) < side.point((min_side_node+1)%4));
   138       switch (min_side_node) {
   141           std::swap(sidep(0), sidep(1));
   144         sidep(0) = -sidep(0);
   146           std::swap(sidep(0), sidep(1));
   149         sidep(0) = -sidep(0);
   150         sidep(1) = -sidep(1);
   152           std::swap(sidep(0), sidep(1));
   155         sidep(1) = -sidep(1);
   157           std::swap(sidep(0), sidep(1));
   166 void cube_indices(
const Elem * elem,
   167                   const unsigned int totalorder,
   168                   const unsigned int i,
   187   const unsigned int e = totalorder - 1u;
   189   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
   191   Real xi_saved = xi, eta_saved = eta, zeta_saved = zeta;
   252   else if (i < 8 + 2*e)
   261   else if (i < 8 + 3*e)
   270   else if (i < 8 + 4*e)
   279   else if (i < 8 + 5*e)
   288   else if (i < 8 + 6*e)
   297   else if (i < 8 + 7*e)
   306   else if (i < 8 + 8*e)
   315   else if (i < 8 + 9*e)
   324   else if (i < 8 + 10*e)
   333   else if (i < 8 + 11*e)
   342   else if (i < 8 + 12*e)
   351   else if (i < 8 + 12*e + e*e)
   353       unsigned int basisnum = i - 8 - 12*e;
   357       const Point min_point = get_min_point(elem, 1, 2, 0, 3);
   359       if (elem->
point(0) == min_point)
   373       else if (elem->
point(3) == min_point)
   387       else if (elem->
point(2) == min_point)
   401       else if (elem->
point(1) == min_point)
   418   else if (i < 8 + 12*e + 2*e*e)
   420       unsigned int basisnum = i - 8 - 12*e - e*e;
   424       const Point min_point = get_min_point(elem, 0, 1, 5, 4);
   426       if (elem->
point(0) == min_point)
   440       else if (elem->
point(1) == min_point)
   454       else if (elem->
point(5) == min_point)
   468       else if (elem->
point(4) == min_point)
   485   else if (i < 8 + 12*e + 3*e*e)
   487       unsigned int basisnum = i - 8 - 12*e - 2*e*e;
   491       const Point min_point = get_min_point(elem, 1, 2, 6, 5);
   493       if (elem->
point(1) == min_point)
   507       else if (elem->
point(2) == min_point)
   521       else if (elem->
point(6) == min_point)
   535       else if (elem->
point(5) == min_point)
   552   else if (i < 8 + 12*e + 4*e*e)
   554       unsigned int basisnum = i - 8 - 12*e - 3*e*e;
   558       const Point min_point = get_min_point(elem, 2, 3, 7, 6);
   560       if (elem->
point(3) == min_point)
   574       else if (elem->
point(7) == min_point)
   588       else if (elem->
point(6) == min_point)
   602       else if (elem->
point(2) == min_point)
   619   else if (i < 8 + 12*e + 5*e*e)
   621       unsigned int basisnum = i - 8 - 12*e - 4*e*e;
   625       const Point min_point = get_min_point(elem, 3, 0, 4, 7);
   627       if (elem->
point(0) == min_point)
   641       else if (elem->
point(4) == min_point)
   655       else if (elem->
point(7) == min_point)
   669       else if (elem->
point(3) == min_point)
   686   else if (i < 8 + 12*e + 6*e*e)
   688       unsigned int basisnum = i - 8 - 12*e - 5*e*e;
   692       const Point min_point = get_min_point(elem, 4, 5, 6, 7);
   694       if (elem->
point(4) == min_point)
   708       else if (elem->
point(5) == min_point)
   722       else if (elem->
point(6) == min_point)
   736       else if (elem->
point(7) == min_point)
   756       unsigned int basisnum = i - 8 - 12*e - 6*e*e;
   764 void prism_indices(
const Elem * elem,
   765                    const unsigned int totalorder,
   766                    const unsigned int i,
   772   const unsigned int e = totalorder - 1u;
   774   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+2u)/2u);
   776   Point xi_eta_saved = xi_eta;
   777   Real zeta_saved = zeta;
   811   else if (i < 6 + 3*e)
   818   else if (i < 6 + 6*e)
   820       i01 = (i - 6 - 3*e)/e; 
   821       i2 = (i - 6 - 3*e)%e+2; 
   827   else if (i < 6 + 9*e)
   834   else if (i < 6 + 9*e + e*e)
   836       unsigned int basisnum = i - 6 - 9*e;
   840       const Real xe_scale = 1 - xi_eta_saved(1);
   843       const Real xe_fraction = (xe_scale==0) ?
   844         0 : xi_eta_saved(0)/xe_scale;
   849       const Point min_point = get_min_point(elem, 0, 1, 3, 4);
   851       if (elem->
point(0) == min_point)
   864               zeta = 2*xe_fraction-1;
   865               xi_eta(0) = (zeta_saved+1)*xe_scale/2;
   868       else if (elem->
point(3) == min_point)
   875               zeta = 1-2*xe_fraction;
   876               xi_eta(0) = (zeta_saved+1)*xe_scale/2;
   886       else if (elem->
point(1) == min_point)
   893               zeta = 2*xe_fraction-1;
   894               xi_eta(0) = (1-zeta_saved)*xe_scale/2;
   901               xi_eta(0) = (1-xe_fraction)*xe_scale;
   904       else if (elem->
point(4) == min_point)
   911               xi_eta(0) = (1-xe_fraction)*xe_scale;
   919               zeta = 1-2*xe_fraction;
   920               xi_eta(0) = (1-zeta_saved)*xe_scale/2;
   925   else if (i < 6 + 9*e + 2*e*e)
   927       unsigned int basisnum = i - 6 - 9*e - e*e;
   931       const Real xe_scale = xi_eta_saved(0) + xi_eta_saved(1);
   934       const Real xe_fraction = (xe_scale==0) ?
   935         0 : xi_eta_saved(0)/xe_scale;
   940       const Point min_point = get_min_point(elem, 1, 2, 4, 5);
   942       if (elem->
point(1) == min_point)
   955               zeta = 2*xe_fraction-1;
   956               const Real xe = (zeta_saved+1)/2;
   957               xi_eta(1) = xe*xe_scale;
   958               xi_eta(0) = xe_scale - xi_eta(1);
   961       else if (elem->
point(4) == min_point)
   968               zeta = 1-2*xe_fraction;
   969               const Real xe = (zeta_saved+1)/2;
   970               xi_eta(1) = xe*xe_scale;
   971               xi_eta(0) = xe_scale - xi_eta(1);
   981       else if (elem->
point(2) == min_point)
   988               zeta = 2*xe_fraction-1;
   989               const Real xe = (1-zeta_saved)/2;
   990               xi_eta(1) = xe*xe_scale;
   991               xi_eta(0) = xe_scale - xi_eta(1);
   998               const Real xe = (1-xe_fraction);
   999               xi_eta(1) = xe*xe_scale;
  1000               xi_eta(0) = xe_scale - xi_eta(1);
  1003       else if (elem->
point(5) == min_point)
  1011               const Real xe = (1-xe_fraction);
  1012               xi_eta(1) = xe*xe_scale;
  1013               xi_eta(0) = xe_scale - xi_eta(1);
  1020               zeta = 1-2*xe_fraction;
  1021               const Real xe = (1-zeta_saved)/2;
  1022               xi_eta(1) = xe*xe_scale;
  1023               xi_eta(0) = xe_scale - xi_eta(1);
  1028   else if (i < 6 + 9*e + 3*e*e)
  1030       unsigned int basisnum = i - 6 - 9*e - 2*e*e;
  1034       const Real xe_scale = 1 - xi_eta_saved(0);
  1037       const Real xe_fraction = (xe_scale==0) ?
  1038         0 : (xe_scale - xi_eta_saved(1))/xe_scale;
  1043       const Point min_point = get_min_point(elem, 0, 2, 3, 5);
  1045       if (elem->
point(2) == min_point)
  1058               zeta = 2*xe_fraction-1;
  1059               const Real xe = (zeta_saved+1)/2;
  1060               xi_eta(1) = xe_scale - xe*xe_scale;
  1063       else if (elem->
point(5) == min_point)
  1070               zeta = 1-2*xe_fraction;
  1071               const Real xe = (zeta_saved+1)/2;
  1072               xi_eta(1) = xe_scale - xe*xe_scale;
  1082       else if (elem->
point(0) == min_point)
  1089               zeta = 2*xe_fraction-1;
  1090               const Real xe = (1-zeta_saved)/2;
  1091               xi_eta(1) = xe_scale - xe*xe_scale;
  1098               const Real xe = (1-xe_fraction);
  1099               xi_eta(1) = xe_scale - xe*xe_scale;
  1102       else if (elem->
point(3) == min_point)
  1110               const Real xe = (1-xe_fraction);
  1111               xi_eta(1) = xe_scale - xe*xe_scale;
  1118               zeta = 1-2*xe_fraction;
  1119               const Real xe = (1-zeta_saved)/2;
  1120               xi_eta(1) = xe_scale - xe*xe_scale;
  1125   else if (i < 6 + 9*e + 3*e*e + e*(e-1)/2)
  1128       i01 = i - 3 - 6*e - 3*e*e;
  1132   else if (i < 6 + 9*e + 3*e*e + e*(e-1))
  1135       i01 = i - 3 - 6*e - 3*e*e - e*(e-1)/2;
  1143       unsigned int basisnum = i - 6 - 9*e - 3*e*e - e*(e-1);
  1149 #endif // LIBMESH_DIM > 2  1170   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1182   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1194   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1203                              const unsigned int i,
  1205                              const bool add_p_level)
  1207   return fe_hierarchic_3D_shape<HIERARCHIC>(elem, order, i, p, add_p_level);
  1214                              const unsigned int i,
  1216                              const bool add_p_level)
  1218   return fe_hierarchic_3D_shape<HIERARCHIC>(elem, fet.
order, i, p, add_p_level);
  1227                                 const unsigned int i,
  1229                                 const bool add_p_level)
  1231   return fe_hierarchic_3D_shape<L2_HIERARCHIC>(elem, order, i, p, add_p_level);
  1238                                 const unsigned int i,
  1240                                 const bool add_p_level)
  1242   return fe_hierarchic_3D_shape<L2_HIERARCHIC>(elem, fet.
order, i, p, add_p_level);
  1250                                   const unsigned int i,
  1252                                   const bool add_p_level)
  1254 #if LIBMESH_DIM == 3  1258   const Order totalorder = order + add_p_level*elem->
p_level();
  1264         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
  1265         libmesh_assert_less(i, 6*dofs_per_side);
  1267         const unsigned int sidenum = cube_side(p);
  1269           return std::numeric_limits<Real>::quiet_NaN();
  1271         const unsigned int dof_offset = sidenum * dofs_per_side;
  1276         if (i >= dof_offset + dofs_per_side) 
  1279         if (totalorder == 0) 
  1282         unsigned int side_i = i - dof_offset;
  1284         std::unique_ptr<const Elem> side = elem->
build_side_ptr(sidenum);
  1286         Point sidep = cube_side_point(sidenum, p);
  1288         cube_remap(side_i, *side, totalorder, sidep);
  1295         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+2u)/2u;
  1296         libmesh_assert_less(i, 4*dofs_per_side);
  1298         const Real zeta[4] = { 
Real(1.) - p(0) - p(1) - p(2), p(0), p(1), p(2) };
  1300         unsigned int face_num = 0;
  1301         if (zeta[0] > zeta[3] &&
  1302             zeta[1] > zeta[3] &&
  1307         else if (zeta[0] > zeta[2] &&
  1308                  zeta[1] > zeta[2] &&
  1313         else if (zeta[1] > zeta[0] &&
  1314                  zeta[2] > zeta[0] &&
  1323                             zeta[2] > zeta[1] &&
  1328         if (i < face_num * dofs_per_side ||
  1329             i >= (face_num+1) * dofs_per_side)
  1332         if (totalorder == 0)
  1335         const std::array<unsigned int, 3> face_vertex =
  1336           oriented_tet_nodes(*elem, face_num);
  1343         Elem & e = 
const_cast<Elem &
>(*elem);
  1348         const unsigned int basisnum = i - face_num*dofs_per_side;
  1350         Point sidep {zeta[face_vertex[1]], zeta[face_vertex[2]]};
  1353                                           basisnum, sidep, 
false);
  1359         const unsigned int dofs_per_quad = (totalorder+1u)*(totalorder+1u);
  1360         const unsigned int dofs_per_tri = (totalorder+1u)*(totalorder+2u)/2u;
  1361         libmesh_assert_less(i, 3*dofs_per_quad + 2*dofs_per_tri);
  1367         Elem * side = &quad;
  1368         unsigned int dofs_on_side = dofs_per_quad;
  1371         Elem & e = 
const_cast<Elem &
>(*elem);
  1381         unsigned int face_num = 0;
  1382         unsigned int i_offset = 0;
  1385         const Real zeta[3] = { 
Real(1.) - p(0) - p(1), p(0), p(1) };
  1388         const Real zmid = 1 - std::abs(p(2));
  1390         if (zeta[1] > zeta[2] && zeta[0] > zeta[2] &&
  1396         else if (zeta[1] > zeta[0] && zeta[2] > zeta[0] &&
  1400             i_offset = dofs_per_quad;
  1402         else if (zeta[0] > zeta[1] && zeta[2] > zeta[1] &&
  1406             i_offset = 2*dofs_per_quad;
  1408         else if (p(2) + 1 < 3*zeta[0] &&
  1409                  p(2) + 1 < 3*zeta[1] &&
  1410                  p(2) + 1 < 3*zeta[2]) 
  1413             i_offset = 3*dofs_per_quad;
  1414             dofs_on_side = dofs_per_tri;
  1417         else if (1 - p(2) < 3*zeta[0] &&
  1418                  1 - p(2) < 3*zeta[1] &&
  1419                  1 - p(2) < 3*zeta[2]) 
  1422             i_offset = dofs_per_tri + 3*dofs_per_quad;
  1423             dofs_on_side = dofs_per_tri;
  1428             libmesh_error_msg(
"Evaluating SIDE_HIERARCHIC right between two Prism faces?");
  1432             i >= i_offset + dofs_on_side)
  1435         if (totalorder == 0)
  1438         const std::array<unsigned int, 4> face_vertex =
  1439           oriented_prism_nodes(*elem, face_num);
  1444         if (face_vertex[3] < 21)
  1447         if (face_num == 0 || face_num == 4)
  1448           sidep = {zeta[face_vertex[1]%3], zeta[face_vertex[2]%3]};
  1454             auto coord_val = [p](
int v1, 
int v2){
  1457               else if (v2-v1 == -3)
  1459               else if (v1%3 == 0 && v2%3 == 1)
  1461               else if (v2%3 == 0 && v1%3 == 1)
  1463               else if (v1%3 == 1 && v2%3 == 2)
  1465               else if (v2%3 == 1 && v1%3 == 2)
  1467               else if (v1%3 == 2 && v2%3 == 0)
  1469               else if (v2%3 == 2 && v1%3 == 0)
  1475             sidep = {coord_val(face_vertex[0], face_vertex[1]),
  1476                      coord_val(face_vertex[0], face_vertex[3])};
  1479         const unsigned int basisnum = i - i_offset;
  1482                                           basisnum, sidep, 
false);
  1490 #else // LIBMESH_DIM != 3  1492   libmesh_not_implemented();
  1500                                   const unsigned int i,
  1502                                   const bool add_p_level)
  1515   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1528   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1541   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1550                                    const unsigned int i,
  1551                                    const unsigned int j,
  1553                                    const bool add_p_level)
  1555   return fe_hierarchic_3D_shape_deriv<HIERARCHIC>(elem, order, i, j, p, add_p_level);
  1562                                    const unsigned int i,
  1563                                    const unsigned int j,
  1565                                    const bool add_p_level)
  1567   return fe_hierarchic_3D_shape_deriv<HIERARCHIC>(elem, fet.
order, i, j, p, add_p_level);
  1575                                       const unsigned int i,
  1576                                       const unsigned int j,
  1578                                       const bool add_p_level)
  1580   return fe_hierarchic_3D_shape_deriv<L2_HIERARCHIC>(elem, order, i, j, p, add_p_level);
  1587                                       const unsigned int i,
  1588                                       const unsigned int j,
  1590                                       const bool add_p_level)
  1592   return fe_hierarchic_3D_shape_deriv<L2_HIERARCHIC>(elem, fet.
order, i, j, p, add_p_level);
  1600                                         const unsigned int i,
  1601                                         const unsigned int j,
  1603                                         const bool add_p_level)
  1605 #if LIBMESH_DIM == 3  1609   const Order totalorder = order + add_p_level*elem->
p_level();
  1611   if (totalorder == 0) 
  1622         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
  1623         libmesh_assert_less(i, 6*dofs_per_side);
  1625         const unsigned int sidenum = cube_side(p);
  1627           return std::numeric_limits<Real>::quiet_NaN();
  1629         const unsigned int dof_offset = sidenum * dofs_per_side;
  1634         if (i >= dof_offset + dofs_per_side) 
  1637         unsigned int side_i = i - dof_offset;
  1639         std::unique_ptr<const Elem> side = elem->
build_side_ptr(sidenum);
  1641         Point sidep = cube_side_point(sidenum, p);
  1643         cube_remap(side_i, *side, totalorder, sidep);
  1647         unsigned int sidej = 100;
  1727             libmesh_error_msg(
"Invalid derivative index j = " << j);
  1731                                                  side_i, sidej, sidep,
  1746 #else // LIBMESH_DIM != 3  1748   libmesh_not_implemented();
  1756                                         const unsigned int i,
  1757                                         const unsigned int j,
  1759                                         const bool add_p_level)
  1765 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES  1774   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1787   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1800   libmesh_error_msg(
"Hierarchic shape functions require an Elem for edge/face orientation.");
  1809                                           const unsigned int i,
  1810                                           const unsigned int j,
  1812                                           const bool add_p_level)
  1814   return fe_hierarchic_3D_shape_second_deriv<HIERARCHIC>(elem, order, i, j, p, add_p_level);
  1822                                           const unsigned int i,
  1823                                           const unsigned int j,
  1825                                           const bool add_p_level)
  1827   return fe_hierarchic_3D_shape_second_deriv<HIERARCHIC>(elem, fet.
order, i, j, p, add_p_level);
  1835                                              const unsigned int i,
  1836                                              const unsigned int j,
  1838                                              const bool add_p_level)
  1840   return fe_hierarchic_3D_shape_second_deriv<L2_HIERARCHIC>(elem, order, i, j, p, add_p_level);
  1847                                              const unsigned int i,
  1848                                              const unsigned int j,
  1850                                              const bool add_p_level)
  1852   return fe_hierarchic_3D_shape_second_deriv<L2_HIERARCHIC>(elem, fet.
order, i, j, p, add_p_level);
  1859                                                const unsigned int i,
  1860                                                const unsigned int j,
  1862                                                const bool add_p_level)
  1864 #if LIBMESH_DIM == 3  1868   const Order totalorder = order + add_p_level*elem->
p_level();
  1870   if (totalorder == 0) 
  1882         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
  1883         libmesh_assert_less(i, 6*dofs_per_side);
  1885         const unsigned int sidenum = cube_side(p);
  1887           return std::numeric_limits<Real>::quiet_NaN();
  1889         const unsigned int dof_offset = sidenum * dofs_per_side;
  1894         if (i >= dof_offset + dofs_per_side) 
  1897         unsigned int side_i = i - dof_offset;
  1899         std::unique_ptr<const Elem> side = elem->
build_side_ptr(sidenum);
  1901         Point sidep = cube_side_point(sidenum, p);
  1903         cube_remap(side_i, *side, totalorder, sidep);
  1907         unsigned int sidej = 100;
  2051             libmesh_error_msg(
"Invalid derivative index j = " << j);
  2072 #else // LIBMESH_DIM != 3  2074   libmesh_not_implemented();
  2082                                                const unsigned int i,
  2083                                                const unsigned int j,
  2085                                                const bool add_p_level)
  2090 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES  2101 unsigned int cube_side (
const Point & p)
  2103   const Real xi = p(0), eta = p(1), zeta = p(2);
  2104   const Real absxi   = std::abs(xi),
  2105              abseta  = std::abs(eta),
  2106              abszeta = std::abs(zeta);
  2107   const Real maxabs_xi_eta   = std::max(absxi, abseta),
  2108              maxabs_xi_zeta  = std::max(absxi, abszeta),
  2109              maxabs_eta_zeta = std::max(abseta, abszeta);
  2111   if (zeta < -maxabs_xi_eta)
  2113   else if (eta < -maxabs_xi_zeta)
  2115   else if (xi > maxabs_eta_zeta)
  2117   else if (eta > maxabs_xi_zeta)
  2119   else if (xi < -maxabs_eta_zeta)
  2121   else if (zeta > maxabs_xi_eta)
  2131 Point cube_side_point(
unsigned int sidenum, 
const Point & p)
  2169 void orient_quad(
const Elem & elem,
  2170                  std::array<unsigned int, 4> & face_vertex)
  2176   const unsigned int min_pt =
  2177     std::min_element(face_vertex.begin(), face_vertex.end(),
  2178                      [&elem](
auto v1, 
auto v2)
  2180     face_vertex.begin();
  2183   if (elem.
point(face_vertex[(min_pt+3)%4]) <
  2184       elem.
point(face_vertex[(min_pt+1)%4]))
  2185     face_vertex = { face_vertex[min_pt], face_vertex[(min_pt+3)%4],
  2186                     face_vertex[(min_pt+2)%4], face_vertex[(min_pt+1)%4] };
  2188     face_vertex = { face_vertex[min_pt], face_vertex[(min_pt+1)%4],
  2189                     face_vertex[(min_pt+2)%4], face_vertex[(min_pt+3)%4] };
  2193 void orient_triangle(
const Elem & elem,
  2194                      unsigned int * face_vertex)
  2203   bool lastcheck = 
true;
  2204   if (elem.
point(face_vertex[0]) > elem.
point(face_vertex[1]))
  2206       std::swap(face_vertex[0], face_vertex[1]);
  2209   if (elem.
point(face_vertex[1]) > elem.
point(face_vertex[2]))
  2210     std::swap(face_vertex[1], face_vertex[2]);
  2211   if (lastcheck && elem.
point(face_vertex[0]) > elem.
point(face_vertex[1]))
  2212     std::swap(face_vertex[0], face_vertex[1]);
  2216 std::array<unsigned int, 4> oriented_prism_nodes(
const Elem & elem,
  2217                                                  unsigned int face_num)
  2219   std::array<unsigned int, 4> face_vertex
  2225   if (face_num > 0 && face_num < 4)
  2226     orient_quad(elem, face_vertex);
  2228     orient_triangle(elem, face_vertex.data());
  2234 std::array<unsigned int, 3> oriented_tet_nodes(
const Elem & elem,
  2235                                                unsigned int face_num)
  2237   std::array<unsigned int, 3> face_vertex
  2242   orient_triangle(elem, face_vertex.data());
  2248 template <FEFamily T>
  2249 Real fe_hierarchic_3D_shape(
const Elem * elem,
  2251                             const unsigned int i,
  2253                             const bool add_p_level)
  2255 #if LIBMESH_DIM == 3  2260   const Order totalorder = order + add_p_level*elem->
p_level();
  2267       libmesh_fallthrough();
  2270         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
  2277         unsigned int i0, i1, i2;
  2279         cube_indices(elem, totalorder, i, xi, eta, zeta, i0, i1, i2);
  2289       libmesh_fallthrough();
  2292       libmesh_fallthrough();
  2296         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+2u)/2u);
  2301         Point xi_eta {p(0),p(1)};
  2304         unsigned int i01, i2;
  2306         prism_indices(elem, totalorder, i, xi_eta, zeta, i01, i2);
  2313         Elem & e = 
const_cast<Elem &
>(*elem);
  2338             if (i01 > 2 && i01 < 3u*totalorder)
  2341                 const bool odd_basis = ((i01-1)%(totalorder-1))%2;
  2344                     const int tri_edge = (i01-3)/(totalorder-1);
  2347                     if (tri.
point(tri_edge) > tri.
point((tri_edge+1)%3))
  2363       libmesh_fallthrough();
  2366       libmesh_fallthrough();
  2369         const Real zeta[4] = { 1 - p(0) - p(1) - p(2), p(0), p(1), p(2) };
  2376         else if (i < 6u*totalorder - 2u)
  2378             const unsigned int edge_num = (i - 4) / (totalorder - 1u);
  2380             const unsigned int basisorder = i - 2 - ((totalorder - 1u) * edge_num);
  2391             const Real crossval = zeta[edgevertex0] + zeta[edgevertex1];
  2392             const Real edgenumerator = zeta[edgevertex1] - zeta[edgevertex0];
  2396                 unsigned int basisfactorial = 1.;
  2397                 for (
unsigned int n=2; n <= basisorder; ++n)
  2398                   basisfactorial *= n;
  2400                 return std::pow(edgenumerator, basisorder) / basisfactorial;
  2403             const Real edgeval = edgenumerator / crossval;
  2406             return flip * crossfunc *
  2408                                       basisorder, edgeval);
  2412         else if (i < 2u*totalorder*totalorder + 2u)
  2414             const int dofs_per_face = (totalorder - 1u) * (totalorder - 2u) / 2;
  2415             const int face_num = (i - (6u*totalorder - 2u)) / dofs_per_face;
  2417             const std::array<unsigned int, 3> face_vertex =
  2418               oriented_tet_nodes(*elem, face_num);
  2419             const Real zeta0 = zeta[face_vertex[0]],
  2420                        zeta1 = zeta[face_vertex[1]],
  2421                        zeta2 = zeta[face_vertex[2]];
  2423             const unsigned int basisnum =
  2425               (totalorder - 1u) * 6 -
  2426               (dofs_per_face * face_num);
  2433             for (
unsigned int n = 0; n != exp0; ++n)
  2435             for (
unsigned int n = 0; n != exp1; ++n)
  2444             const unsigned int basisnum = i - 2u*totalorder*totalorder - 2u;
  2452             for (
unsigned int n = 0; n != exp0; ++n)
  2453               returnval *= zeta[0];
  2454             for (
unsigned int n = 0; n != exp1; ++n)
  2455               returnval *= zeta[1];
  2456             for (
unsigned int n = 0; n != exp2; ++n)
  2457               returnval *= zeta[2];
  2458             returnval *= zeta[3];
  2467 #else // LIBMESH_DIM != 3  2469   libmesh_not_implemented();
  2475 template <FEFamily T>
  2476 Real fe_hierarchic_3D_shape_deriv(
const Elem * elem,
  2478                                   const unsigned int i,
  2479                                   const unsigned int j,
  2481                                   const bool add_p_level)
  2488 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES  2490 template <FEFamily T>
  2491 Real fe_hierarchic_3D_shape_second_deriv(
const Elem * elem,
  2493                                          const unsigned int i,
  2494                                          const unsigned int j,
  2496                                          const bool add_p_level)
  2502 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES 
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
  The Tri3 is an element in 2D composed of 3 nodes. 
const unsigned char prism_number_page[]
ElemType
Defines an enum for geometric element types. 
Order
defines an enum for polynomial orders. 
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the  node of the  side to element node numbers. 
virtual Node *& set_node(const unsigned int i)
A Node is like a Point, but with more information. 
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
  The QUAD4 is an element in 2D composed of 4 nodes. 
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the  node of the  side to element node numbers. 
const unsigned char prism_number_triangle[]
This is the base class from which all geometric element types are derived. 
const unsigned char triangular_number_row[]
const unsigned char tetrahedral_number_column[]
const unsigned char cube_number_column[]
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
OrderWrapper order
The approximation order of the element. 
The libMesh namespace provides an interface to certain functionality in the library. 
const unsigned char tetrahedral_number_row[]
const unsigned char cube_number_row[]
const unsigned char tetrahedral_number_page[]
OutputShape fe_fdm_deriv(const Elem *elem, const Order order, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level, OutputShape(*shape_func)(const Elem *, const Order, const unsigned int, const Point &, const bool))
Helper functions for finite differenced derivatives in cases where analytical calculations haven't be...
const unsigned char square_number_column[]
const unsigned char cube_number_page[]
LIBMESH_DEFAULT_VECTORIZED_FE(template<>Real FE< 0, BERNSTEIN)
A specific instantiation of the FEBase class. 
void libmesh_ignore(const Args &...)
bool positive_edge_orientation(const unsigned int i) const
OutputShape fe_fdm_second_deriv(const Elem *elem, const Order order, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level, OutputShape(*deriv_func)(const Elem *, const Order, const unsigned int, const unsigned int, const Point &, const bool))
std::string enum_to_string(const T e)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const unsigned char triangular_number_column[]
const Node * node_ptr(const unsigned int i) const
const unsigned char square_number_row[]
bool positive_face_orientation(const unsigned int i) const
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the  node of the  edge to element node numbers. 
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space. 
const Point & point(const unsigned int i) const
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)