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"
36unsigned int cube_side(
const Point & p);
38Point cube_side_point(
unsigned int sidenum,
const Point & interior_point);
40std::array<unsigned int, 4> oriented_prism_nodes(
const Elem & elem,
41 unsigned int face_num);
43std::array<unsigned int, 3> oriented_tet_nodes(
const Elem & elem,
44 unsigned int face_num);
47Real fe_hierarchic_3D_shape(
const Elem * elem,
51 const bool add_p_level);
54Real fe_hierarchic_3D_shape_deriv(
const Elem * elem,
59 const bool add_p_level);
61#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
64Real fe_hierarchic_3D_shape_second_deriv(
const Elem * elem,
69 const bool add_p_level);
80 return std::min(std::min(elem->
point(a),elem->
point(
b)),
85template <
unsigned int N_nodes>
86unsigned 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];
101 for (
auto i :
IntRange<unsigned
int>(nodebegin, nodebegin+N_nodes))
102 if (pn == &elem.point(i))
110void 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));
166void 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;
764void 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);
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)
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);
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)
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,
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)
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);
2074 libmesh_not_implemented();
2082 const unsigned int i,
2083 const unsigned int j,
2085 const bool add_p_level)
2101unsigned 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)
2131Point cube_side_point(
unsigned int sidenum,
const Point & p)
2169void 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)
2179 {return elem.point(v1)<elem.point(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] };
2193void 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]);
2216std::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());
2234std::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());
2248template <FEFamily T>
2249Real fe_hierarchic_3D_shape(
const Elem * elem,
2251 const unsigned int i,
2253 const bool add_p_level)
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;
2404 const Real crossfunc = std::pow(crossval, basisorder);
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];
2469 libmesh_not_implemented();
2475template <FEFamily T>
2476Real 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
2490template <FEFamily T>
2491Real 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)
void ErrorVector unsigned int
This is the base class from which all geometric element types are derived.
virtual Node *& set_node(const unsigned int i)
const Point & point(const unsigned int i) const
bool positive_edge_orientation(const unsigned int i) const
bool positive_face_orientation(const unsigned int i) const
const Node * node_ptr(const unsigned int i) const
virtual ElemType type() const =0
unsigned int p_level() const
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
OrderWrapper order
The approximation order of the element (at 0 p-refinement level).
A specific instantiation of the FEBase class.
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
A Node is like a Point, but with more information.
A Point defines a location in LIBMESH_DIM dimensional Real space.
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
The QUAD4 is an element in 2D composed of 4 nodes.
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the edge to element node numbers.
The Tri3 is an element in 2D composed of 3 nodes.
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
const unsigned char tetrahedral_number_column[]
const unsigned char tetrahedral_number_row[]
const unsigned char prism_number_triangle[]
LIBMESH_DEFAULT_VECTORIZED_FE(template<>Real FE< 0, BERNSTEIN)
const unsigned char prism_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...
ElemType
Defines an enum for geometric element types.
void libmesh_ignore(const Args &...)
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))
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
const unsigned char triangular_number_row[]
const unsigned char cube_number_row[]
const unsigned char cube_number_page[]
const unsigned char cube_number_column[]
const unsigned char square_number_row[]
const unsigned char square_number_column[]
const unsigned char triangular_number_column[]
const unsigned char tetrahedral_number_page[]
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real