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)