LCOV - code coverage report
Current view: top level - src/fe - fe_hierarchic_shape_3D.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4343 (6ea38c) with base 8c3130 Lines: 752 828 90.8 %
Date: 2026-10-13 21:47:33 Functions: 36 54 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : // Local includes
      20             : #include "libmesh/fe.h"
      21             : #include "libmesh/elem.h"
      22             : #include "libmesh/number_lookups.h"
      23             : #include "libmesh/enum_to_string.h"
      24             : #include "libmesh/cell_tet4.h" // We need edge_nodes_map
      25             : #include "libmesh/face_tri3.h" // Faster to construct these on the stack
      26             : #include "libmesh/face_quad4.h"
      27             : 
      28             : // Anonymous namespace for functions shared by HIERARCHIC and
      29             : // L2_HIERARCHIC implementations. Implementations appear at the bottom
      30             : // of this file.
      31             : namespace
      32             : {
      33             : using namespace libMesh;
      34             : 
      35             : unsigned int cube_side(const Point & p);
      36             : 
      37             : Point cube_side_point(unsigned int sidenum, const Point & interior_point);
      38             : 
      39             : template <FEFamily T>
      40             : Real fe_hierarchic_3D_shape(const Elem * elem,
      41             :                             const Order order,
      42             :                             const unsigned int i,
      43             :                             const Point & p,
      44             :                             const bool add_p_level);
      45             : 
      46             : template <FEFamily T>
      47             : Real fe_hierarchic_3D_shape_deriv(const Elem * elem,
      48             :                                   const Order order,
      49             :                                   const unsigned int i,
      50             :                                   const unsigned int j,
      51             :                                   const Point & p,
      52             :                                   const bool add_p_level);
      53             : 
      54             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
      55             : 
      56             : template <FEFamily T>
      57             : Real fe_hierarchic_3D_shape_second_deriv(const Elem * elem,
      58             :                                          const Order order,
      59             :                                          const unsigned int i,
      60             :                                          const unsigned int j,
      61             :                                          const Point & p,
      62             :                                          const bool add_p_level);
      63             : 
      64             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
      65             : 
      66             : #if LIBMESH_DIM > 2
      67             : // Remap non-face-nodes based on point ordering
      68             : template <unsigned int N_nodes>
      69    60725016 : unsigned int remap_node(unsigned int n,
      70             :                         const Elem & elem,
      71             :                         unsigned int nodebegin)
      72             : {
      73             :   std::array<const Point *, N_nodes> points;
      74             : 
      75   303625080 :   for (auto i : IntRange<unsigned int>(0, N_nodes))
      76   263088224 :     points[i] = &elem.point(nodebegin+i);
      77             : 
      78     5047040 :   std::sort(points.begin(), points.end(),
      79    28448840 :             [](const Point * a, const Point * b)
      80   313884136 :             { return *a < *b; });
      81             : 
      82    60725016 :   const Point * pn = points[n-nodebegin];
      83             : 
      84   151812540 :   for (auto i : IntRange<unsigned int>(nodebegin, nodebegin+N_nodes))
      85   164430140 :     if (pn == &elem.point(i))
      86     5047040 :       return i;
      87             : 
      88           0 :   libmesh_assert(false);
      89           0 :   return libMesh::invalid_uint;
      90             : }
      91             : 
      92             : 
      93    88992834 : void cube_remap(unsigned int & side_i,
      94             :                 const Elem & elem,
      95             :                 unsigned int sidenum,
      96             :                 const Elem & side,
      97             :                 unsigned int totalorder,
      98             :                 Point & sidep)
      99             : {
     100             :   // "vertex" nodes are now decoupled from vertices, so we have
     101             :   // to order them consistently otherwise
     102    88992834 :   if (side_i < 4)
     103    17967096 :     side_i = remap_node<4>(side_i, side, 0);
     104             : 
     105             :   // And "edge" nodes are decoupled from edges, so we have to
     106             :   // reorder them too!
     107    71025738 :   else if (side_i < 4u*totalorder)
     108             :     {
     109    42757920 :       unsigned int side_node = (side_i - 4)/(totalorder-1)+4;
     110    42757920 :       side_node = remap_node<4>(side_node, side, 4);
     111    49867040 :       side_i = ((side_i - 4) % (totalorder - 1)) // old local edge_i
     112    42757920 :         + 4 + (side_node-4)*(totalorder-1);
     113             :     }
     114             : 
     115             :   // Interior dofs in 2D don't care about where xi/eta point in
     116             :   // physical space, but here we need them to match from both
     117             :   // sides of a face!
     118             :   else
     119             :     {
     120             :       // The side numbers its nodes as the side node map of elem does.
     121             :       // Rotate the least node to the origin, then flip about the
     122             :       // diagonal through it if its lesser neighbor is its predecessor
     123    28267818 :       const unsigned int orientation = elem.face_orientation(sidenum);
     124    28267818 :       const unsigned int min_side_node = orientation / 2;
     125    28267818 :       const bool flip = orientation % 2;
     126             : 
     127    28267818 :       switch (min_side_node) {
     128     3752036 :       case 0:
     129     3752036 :         if (flip)
     130      157319 :           std::swap(sidep(0), sidep(1));
     131      312044 :         break;
     132     6531006 :       case 1:
     133     6531006 :         sidep(0) = -sidep(0);
     134     6531006 :         if (!flip)
     135      250609 :           std::swap(sidep(0), sidep(1));
     136      543947 :         break;
     137     7038408 :       case 2:
     138     7038408 :         sidep(0) = -sidep(0);
     139     7038408 :         sidep(1) = -sidep(1);
     140     7038408 :         if (flip)
     141      197284 :           std::swap(sidep(0), sidep(1));
     142      585520 :         break;
     143    10946368 :       case 3:
     144    10946368 :         sidep(1) = -sidep(1);
     145    10946368 :         if (!flip)
     146      387266 :           std::swap(sidep(0), sidep(1));
     147      909033 :         break;
     148           0 :       default:
     149           0 :         libmesh_error();
     150             :       }
     151             :     }
     152    88992834 : }
     153             : 
     154             : 
     155   974545994 : void cube_indices(const Elem * elem,
     156             :                   const unsigned int totalorder,
     157             :                   const unsigned int i,
     158             :                   Real & xi, Real & eta, Real & zeta,
     159             :                   unsigned int & i0,
     160             :                   unsigned int & i1,
     161             :                   unsigned int & i2)
     162             : {
     163             :   // The only way to make any sense of this
     164             :   // is to look at the mgflo/mg2/mgf documentation
     165             :   // and make the cut-out cube!
     166             :   // Example i0 and i1 values for totalorder = 3:
     167             :   // FIXME - these examples are incorrect now that we've got truly
     168             :   // hierarchic basis functions
     169             :   //     Nodes                         0  1  2  3  4  5  6  7  8  8  9  9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 20 20 21 21 21 21 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 26 26 26 26
     170             :   //     DOFS                          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 18 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 60 62 63
     171             :   // static const unsigned int i0[] = {0, 1, 1, 0, 0, 1, 1, 0, 2, 3, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 3, 1, 1, 2, 3, 0, 0, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3};
     172             :   // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 3, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 3, 1, 1, 2, 3, 2, 2, 3, 3, 0, 0, 0, 0, 2, 3, 2, 3, 1, 1, 1, 1, 2, 3, 2, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3};
     173             :   // static const unsigned int i2[] = {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3};
     174             : 
     175             :   // the number of DoFs per edge appears everywhere:
     176   974545994 :   const unsigned int e = totalorder - 1u;
     177             : 
     178    78858204 :   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
     179             : 
     180   974545994 :   Real xi_saved = xi, eta_saved = eta, zeta_saved = zeta;
     181             : 
     182             :   // Vertices:
     183   974545994 :   if (i == 0)
     184             :     {
     185    18358646 :       i0 = 0;
     186    18358646 :       i1 = 0;
     187    18358646 :       i2 = 0;
     188             :     }
     189   154755322 :   else if (i == 1)
     190             :     {
     191    18357244 :       i0 = 1;
     192    18357244 :       i1 = 0;
     193    18357244 :       i2 = 0;
     194             :     }
     195   151793708 :   else if (i == 2)
     196             :     {
     197    18357738 :       i0 = 1;
     198    18357738 :       i1 = 1;
     199    18357738 :       i2 = 0;
     200             :     }
     201   148831866 :   else if (i == 3)
     202             :     {
     203    18359140 :       i0 = 0;
     204    18359140 :       i1 = 1;
     205    18359140 :       i2 = 0;
     206             :     }
     207   145870552 :   else if (i == 4)
     208             :     {
     209    18360094 :       i0 = 0;
     210    18360094 :       i1 = 0;
     211    18360094 :       i2 = 1;
     212             :     }
     213   142908462 :   else if (i == 5)
     214             :     {
     215    18358692 :       i0 = 1;
     216    18358692 :       i1 = 0;
     217    18358692 :       i2 = 1;
     218             :     }
     219   139945844 :   else if (i == 6)
     220             :     {
     221    18359186 :       i0 = 1;
     222    18359186 :       i1 = 1;
     223    18359186 :       i2 = 1;
     224             :     }
     225   136982998 :   else if (i == 7)
     226             :     {
     227    18360588 :       i0 = 0;
     228    18360588 :       i1 = 1;
     229    18360588 :       i2 = 1;
     230             :     }
     231             :   // Edge 0
     232   827674666 :   else if (i < 8 + e)
     233             :     {
     234    27552752 :       i0 = i - 6;
     235    27552752 :       i1 = 0;
     236    27552752 :       i2 = 0;
     237    27552752 :       if (elem->positive_edge_orientation(0))
     238      400914 :         xi = -xi_saved;
     239             :     }
     240             :   // Edge 1
     241   800121914 :   else if (i < 8 + 2*e)
     242             :     {
     243    27551036 :       i0 = 1;
     244    27551036 :       i1 = i - e - 6;
     245    27551036 :       i2 = 0;
     246    27551036 :       if (elem->positive_edge_orientation(1))
     247    19533788 :         eta = -eta_saved;
     248             :     }
     249             :   // Edge 2
     250   772570878 :   else if (i < 8 + 3*e)
     251             :     {
     252    27554082 :       i0 = i - 2*e - 6;
     253    27554082 :       i1 = 1;
     254    27554082 :       i2 = 0;
     255    27554082 :       if (!elem->positive_edge_orientation(2))
     256      403174 :         xi = -xi_saved;
     257             :     }
     258             :   // Edge 3
     259   745016796 :   else if (i < 8 + 4*e)
     260             :     {
     261    27555658 :       i0 = 0;
     262    27555658 :       i1 = i - 3*e - 6;
     263    27555658 :       i2 = 0;
     264    27555658 :       if (elem->positive_edge_orientation(3))
     265    19528120 :         eta = -eta_saved;
     266             :     }
     267             :   // Edge 4
     268   717461138 :   else if (i < 8 + 5*e)
     269             :     {
     270    27556818 :       i0 = 0;
     271    27556818 :       i1 = 0;
     272    27556818 :       i2 = i - 4*e - 6;
     273    27556818 :       if (elem->positive_edge_orientation(4))
     274    19562650 :         zeta = -zeta_saved;
     275             :     }
     276             :   // Edge 5
     277   689904320 :   else if (i < 8 + 6*e)
     278             :     {
     279    27552196 :       i0 = 1;
     280    27552196 :       i1 = 0;
     281    27552196 :       i2 = i - 5*e - 6;
     282    27552196 :       if (elem->positive_edge_orientation(5))
     283    19571400 :         zeta = -zeta_saved;
     284             :     }
     285             :   // Edge 6
     286   662352124 :   else if (i < 8 + 7*e)
     287             :     {
     288    27553526 :       i0 = 1;
     289    27553526 :       i1 = 1;
     290    27553526 :       i2 = i - 6*e - 6;
     291    27553526 :       if (elem->positive_edge_orientation(6))
     292    19579660 :         zeta = -zeta_saved;
     293             :     }
     294             :   // Edge 7
     295   634798598 :   else if (i < 8 + 8*e)
     296             :     {
     297    27558148 :       i0 = 0;
     298    27558148 :       i1 = 1;
     299    27558148 :       i2 = i - 7*e - 6;
     300    27558148 :       if (elem->positive_edge_orientation(7))
     301    19570910 :         zeta = -zeta_saved;
     302             :     }
     303             :   // Edge 8
     304   607240450 :   else if (i < 8 + 9*e)
     305             :     {
     306    27557592 :       i0 = i - 8*e - 6;
     307    27557592 :       i1 = 0;
     308    27557592 :       i2 = 1;
     309    27557592 :       if (elem->positive_edge_orientation(8))
     310      409730 :         xi = -xi_saved;
     311             :     }
     312             :   // Edge 9
     313   579682858 :   else if (i < 8 + 10*e)
     314             :     {
     315    27555876 :       i0 = 1;
     316    27555876 :       i1 = i - 9*e - 6;
     317    27555876 :       i2 = 1;
     318    27555876 :       if (elem->positive_edge_orientation(9))
     319    19538912 :         eta = -eta_saved;
     320             :     }
     321             :   // Edge 10
     322   552126982 :   else if (i < 8 + 11*e)
     323             :     {
     324    27558922 :       i0 = i - 10*e - 6;
     325    27558922 :       i1 = 1;
     326    27558922 :       i2 = 1;
     327    27558922 :       if (!elem->positive_edge_orientation(10))
     328      411990 :         xi = -xi_saved;
     329             :     }
     330             :   // Edge 11
     331   524568060 :   else if (i < 8 + 12*e)
     332             :     {
     333    27560498 :       i0 = 0;
     334    27560498 :       i1 = i - 11*e - 6;
     335    27560498 :       i2 = 1;
     336    27560498 :       if (elem->positive_edge_orientation(11))
     337    19533244 :         eta = -eta_saved;
     338             :     }
     339             :   // Faces
     340   497007562 :   else if (i < 8 + 12*e + 6*e*e)
     341             :     {
     342   355220604 :       const unsigned int face = (i - 8 - 12*e) / (e*e);
     343   355220604 :       const unsigned int basisnum = (i - 8 - 12*e) % (e*e);
     344             : 
     345             :       // The face's own frame has its origin at the least vertex and its
     346             :       // first axis toward that vertex's lesser neighbor, so every element
     347             :       // sharing the face agrees on it. The origin sits at -1 along both
     348             :       // axes, so the in-face coordinates are projections onto them.
     349             :       const std::vector<unsigned int> v =
     350   384011484 :         elem->oriented_face_vertices(face);
     351   355220604 :       const Point origin = elem->master_point(v[0]);
     352   355220604 :       const Point first = (elem->master_point(v[1]) - origin) / 2;
     353   355220604 :       const Point second = (elem->master_point(v[3]) - origin) / 2;
     354    28790880 :       const Point p_saved(xi_saved, eta_saved, zeta_saved);
     355             : 
     356   355220604 :       Real * const coord[3] = {&xi, &eta, &zeta};
     357   355220604 :       unsigned int * const index[3] = {&i0, &i1, &i2};
     358             : 
     359  1420882416 :       for (const auto d : make_range(3u))
     360  1065661812 :         if (first(d) != 0)
     361             :           {
     362   355220604 :             *index[d] = square_number_row[basisnum] + 2;
     363   384011484 :             *coord[d] = p_saved * first;
     364             :           }
     365   710441208 :         else if (second(d) != 0)
     366             :           {
     367   355220604 :             *index[d] = square_number_column[basisnum] + 2;
     368   384011484 :             *coord[d] = p_saved * second;
     369             :           }
     370             :         else
     371             :           // The vertex mode that is 1 on this face
     372   355220604 :           *index[d] = (origin(d) > 0);
     373             :     }
     374             : 
     375             :   // Internal DoFs
     376             :   else
     377             :     {
     378   141786958 :       unsigned int basisnum = i - 8 - 12*e - 6*e*e;
     379   141786958 :       i0 = cube_number_column[basisnum] + 2;
     380   141786958 :       i1 = cube_number_row[basisnum] + 2;
     381   141786958 :       i2 = cube_number_page[basisnum] + 2;
     382             :     }
     383   974545994 : }
     384             : 
     385             : 
     386             : // Order the barycentric coordinates of triangular prism face \p face_num
     387             : // by the face's vertices. The triangle interior basis is not symmetric
     388             : // in them, so both elements sharing the face must order them alike.
     389    57351816 : void orient_triangle_coords(const Elem & elem,
     390             :                             const unsigned int face_num,
     391             :                             const Point & xi_eta_saved,
     392             :                             Point & xi_eta)
     393             : {
     394             :   const std::vector<unsigned int> face_vertex =
     395    57351816 :     elem.oriented_face_vertices(face_num);
     396             : 
     397    57351816 :   const Real barycentric[3] = {1 - xi_eta_saved(0) - xi_eta_saved(1),
     398    10242216 :                                xi_eta_saved(0),
     399    57351816 :                                xi_eta_saved(1)};
     400             : 
     401             :   // The face's least vertex takes the place of the triangle's vertex 0, so xi and eta are the
     402             :   // barycentric coordinates of the next two vertices in the face's order. Face 4's vertices
     403             :   // 3-5 lie above vertices 0-2, so % 3 maps the vertices of either face to the triangle's.
     404    57351816 :   xi_eta(0) = barycentric[face_vertex[1] % 3];
     405    57351816 :   xi_eta(1) = barycentric[face_vertex[2] % 3];
     406    57351816 : }
     407             : 
     408             : 
     409   955370748 : void prism_indices(const Elem * elem,
     410             :                    const unsigned int totalorder,
     411             :                    const unsigned int i,
     412             :                    Point & xi_eta, Real & zeta,
     413             :                    unsigned int & i01,
     414             :                    unsigned int & i2)
     415             : {
     416             :   // the number of DoFs per edge appears everywhere:
     417   955370748 :   const unsigned int e = totalorder - 1u;
     418             : 
     419    85295454 :   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+2u)/2u);
     420             : 
     421   955370748 :   Point xi_eta_saved = xi_eta;
     422   955370748 :   Real zeta_saved = zeta;
     423             : 
     424             :   // Vertices:
     425   955370748 :   if (i == 0)
     426             :     {
     427    25320466 :       i01 = 0;
     428    25320466 :       i2 = 0;
     429             :     }
     430   166070340 :   else if (i == 1)
     431             :     {
     432    25318256 :       i01 = 1;
     433    25318256 :       i2 = 0;
     434             :     }
     435   161549876 :   else if (i == 2)
     436             :     {
     437    25316670 :       i01 = 2;
     438    25316670 :       i2 = 0;
     439             :     }
     440   157029828 :   else if (i == 3)
     441             :     {
     442    25320706 :       i01 = 0;
     443    25320706 :       i2 = 1;
     444             :     }
     445   152509260 :   else if (i == 4)
     446             :     {
     447    25318496 :       i01 = 1;
     448    25318496 :       i2 = 1;
     449             :     }
     450   147988796 :   else if (i == 5)
     451             :     {
     452    25316910 :       i01 = 2;
     453    25316910 :       i2 = 1;
     454             :     }
     455             :   // Edges 0,1,2 (vertices 6,7,8)
     456   803459244 :   else if (i < 6 + 3*e)
     457             :     {
     458             :       // The TRI code will handle any flips here
     459   123395400 :       i01 = i - 3;
     460   123395400 :       i2 = 0;
     461             :     }
     462             :   // Edge 3,4,5 (vertices 9,10,11)
     463   680063844 :   else if (i < 6 + 6*e)
     464             :     {
     465   123505776 :       i01 = (i - 6 - 3*e)/e; // which tri DoF are we?
     466   123505776 :       i2 = (i - 6 - 3*e)%e+2; // edge DoF? +2 to skip endpoints
     467             :       // EDGE evaluations don't flip, so handle that here
     468   123505776 :       if (elem->positive_edge_orientation(i01+3))
     469   123175096 :         zeta = -zeta;
     470             :     }
     471             :   // Edge 6,7,8 (vertices 12,13,14)
     472   556558068 :   else if (i < 6 + 9*e)
     473             :     {
     474             :       // The TRI code will handle any flips here
     475   123397272 :       i01 = i - 3 - 6*e;
     476   123397272 :       i2 = 1;
     477             :     }
     478             :   // Faces 1, 2, 3 (nodes 15, 16, 17), the quadrilaterals
     479   433160796 :   else if (i < 6 + 9*e + 3*e*e)
     480             :     {
     481   295542216 :       const unsigned int face = (i - 6 - 9*e) / (e*e) + 1;
     482   295542216 :       const unsigned int basisnum = (i - 6 - 9*e) % (e*e);
     483             : 
     484             :       // indexes in edge numbering
     485   295542216 :       const unsigned int s0 = square_number_row[basisnum] + 2;
     486   295542216 :       const unsigned int s1 = square_number_column[basisnum] + 2;
     487             : 
     488             :       // The face's side node map runs along triangle edge face-1 from
     489             :       // n0 to n1, then up to the top triangle and back. Its own frame has
     490             :       // its origin at the least vertex and its first axis toward that
     491             :       // vertex's lesser neighbor, so every element sharing the face
     492             :       // agrees on it.
     493   295542216 :       const unsigned int n0 = elem->local_side_node(face, 0),
     494   295542216 :                          n1 = elem->local_side_node(face, 1);
     495             :       const std::vector<unsigned int> v =
     496   321929412 :         elem->oriented_face_vertices(face);
     497             : 
     498             :       // The first axis runs along zeta: the edge takes the column mode
     499   295542216 :       const bool swap = (v[0] < 3) != (v[1] < 3);
     500   295542216 :       i01 = (swap ? s1 : s0) + 1 + (face-1)*e; // edge to triangle side numbering
     501   295542216 :       i2 = swap ? s0 : s1;
     502             : 
     503             :       // The origin is on the top triangle
     504   295542216 :       if (v[0] >= 3)
     505   294895420 :         zeta = -zeta_saved;
     506             : 
     507             :       // The origin is at the far end of the edge: reflect the triangle by
     508             :       // exchanging the barycentric coordinates of the edge's vertices
     509   295542216 :       if (v[0] % 3 == n1 % 3)
     510             :         {
     511   160502448 :           Real barycentric[3] = {1 - xi_eta_saved(0) - xi_eta_saved(1),
     512    27924800 :                                  xi_eta_saved(0),
     513   160502448 :                                  xi_eta_saved(1)};
     514   160502448 :           std::swap(barycentric[n0 % 3], barycentric[n1 % 3]);
     515   160502448 :           xi_eta(0) = barycentric[1];
     516   160502448 :           xi_eta(1) = barycentric[2];
     517             :         }
     518             :     }
     519             :   // Face 0, node 18 - node order due to hierarchic numbering
     520   137618580 :   else if (i < 6 + 9*e + 3*e*e + e*(e-1)/2)
     521             :     {
     522    28675644 :       i01 = i - 3 - 6*e - 3*e*e;
     523    28675644 :       i2 = 0;
     524    28675644 :       orient_triangle_coords(*elem, 0, xi_eta_saved, xi_eta);
     525             :     }
     526             :   // Face 4
     527   108942936 :   else if (i < 6 + 9*e + 3*e*e + e*(e-1))
     528             :     {
     529    28676172 :       i01 = i - 3 - 6*e - 3*e*e - e*(e-1)/2;
     530    28676172 :       i2 = 1;
     531    28676172 :       orient_triangle_coords(*elem, 4, xi_eta_saved, xi_eta);
     532             :     }
     533             :   // Internal DoFs
     534             :   else
     535             :     {
     536             :       // We won't bother with any internal DoF reordering / flipping;
     537             :       // that's fine unless we ever get to 4D.
     538    80266764 :       unsigned int basisnum = i - 6 - 9*e - 3*e*e - e*(e-1);
     539    80266764 :       i01 = prism_number_triangle[basisnum] + 3 + 3*e;
     540    80266764 :       i2 = prism_number_page[basisnum] + 2;
     541             :     }
     542   955370748 : }
     543             : 
     544             : #endif // LIBMESH_DIM > 2
     545             : 
     546             : } // end anonymous namespace
     547             : 
     548             : 
     549             : 
     550             : namespace libMesh
     551             : {
     552             : 
     553             : 
     554   124758451 : LIBMESH_DEFAULT_VECTORIZED_FE(3,HIERARCHIC)
     555   134368094 : LIBMESH_DEFAULT_VECTORIZED_FE(3,L2_HIERARCHIC)
     556    97033343 : LIBMESH_DEFAULT_VECTORIZED_FE(3,SIDE_HIERARCHIC)
     557             : 
     558             : 
     559             : template <>
     560           0 : Real FE<3,HIERARCHIC>::shape(const ElemType,
     561             :                              const Order,
     562             :                              const unsigned int,
     563             :                              const Point &)
     564             : {
     565           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
     566             :   return 0.;
     567             : }
     568             : 
     569             : 
     570             : 
     571             : template <>
     572           0 : Real FE<3,L2_HIERARCHIC>::shape(const ElemType,
     573             :                                 const Order,
     574             :                                 const unsigned int,
     575             :                                 const Point &)
     576             : {
     577           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
     578             :   return 0.;
     579             : }
     580             : 
     581             : 
     582             : 
     583             : template <>
     584           0 : Real FE<3,SIDE_HIERARCHIC>::shape(const ElemType,
     585             :                                   const Order,
     586             :                                   const unsigned int,
     587             :                                   const Point &)
     588             : {
     589           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
     590             :   return 0.;
     591             : }
     592             : 
     593             : 
     594             : 
     595             : template <>
     596  1140188348 : Real FE<3,HIERARCHIC>::shape(const Elem * elem,
     597             :                              const Order order,
     598             :                              const unsigned int i,
     599             :                              const Point & p,
     600             :                              const bool add_p_level)
     601             : {
     602  1140188348 :   return fe_hierarchic_3D_shape<HIERARCHIC>(elem, order, i, p, add_p_level);
     603             : }
     604             : 
     605             : 
     606             : template <>
     607           0 : Real FE<3,HIERARCHIC>::shape(const FEType fet,
     608             :                              const Elem * elem,
     609             :                              const unsigned int i,
     610             :                              const Point & p,
     611             :                              const bool add_p_level)
     612             : {
     613           0 :   return fe_hierarchic_3D_shape<HIERARCHIC>(elem, fet.order, i, p, add_p_level);
     614             : }
     615             : 
     616             : 
     617             : 
     618             : 
     619             : template <>
     620  1520145288 : Real FE<3,L2_HIERARCHIC>::shape(const Elem * elem,
     621             :                                 const Order order,
     622             :                                 const unsigned int i,
     623             :                                 const Point & p,
     624             :                                 const bool add_p_level)
     625             : {
     626  1520145288 :   return fe_hierarchic_3D_shape<L2_HIERARCHIC>(elem, order, i, p, add_p_level);
     627             : }
     628             : 
     629             : 
     630             : template <>
     631           0 : Real FE<3,L2_HIERARCHIC>::shape(const FEType fet,
     632             :                                 const Elem * elem,
     633             :                                 const unsigned int i,
     634             :                                 const Point & p,
     635             :                                 const bool add_p_level)
     636             : {
     637           0 :   return fe_hierarchic_3D_shape<L2_HIERARCHIC>(elem, fet.order, i, p, add_p_level);
     638             : }
     639             : 
     640             : 
     641             : 
     642             : template <>
     643  4529357029 : Real FE<3,SIDE_HIERARCHIC>::shape(const Elem * elem,
     644             :                                   const Order order,
     645             :                                   const unsigned int i,
     646             :                                   const Point & p,
     647             :                                   const bool add_p_level)
     648             : {
     649             : #if LIBMESH_DIM == 3
     650   376761768 :   libmesh_assert(elem);
     651  4529357029 :   const ElemType type = elem->type();
     652             : 
     653  4906118797 :   const Order totalorder = order + add_p_level*elem->p_level();
     654             : 
     655  4529357029 :   switch (type)
     656             :     {
     657    41575248 :     case HEX27:
     658             :       {
     659   500333274 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
     660    41575248 :         libmesh_assert_less(i, 6*dofs_per_side);
     661             : 
     662   500333274 :         const unsigned int sidenum = cube_side(p);
     663   500333274 :         if (sidenum > 5)
     664       25920 :           return std::numeric_limits<Real>::quiet_NaN();
     665             : 
     666   499903326 :         const unsigned int dof_offset = sidenum * dofs_per_side;
     667             : 
     668   499903326 :         if (i < dof_offset) // i is on a previous side
     669    17119013 :           return 0;
     670             : 
     671   293517049 :         if (i >= dof_offset + dofs_per_side) // i is on a later side
     672    17227987 :           return 0;
     673             : 
     674    86646501 :         if (totalorder == 0) // special case since raw HIERARCHIC lacks CONSTANTs
     675       14264 :           return 1;
     676             : 
     677    86478594 :         unsigned int side_i = i - dof_offset;
     678             : 
     679    86478594 :         std::unique_ptr<const Elem> side = elem->build_side_ptr(sidenum);
     680             : 
     681    86478594 :         Point sidep = cube_side_point(sidenum, p);
     682             : 
     683    86478594 :         cube_remap(side_i, *elem, sidenum, *side, totalorder, sidep);
     684             : 
     685    86478594 :         return FE<2,HIERARCHIC>::shape(side.get(), order, side_i, sidep, add_p_level);
     686    72102466 :       }
     687             : 
     688   240081920 :     case TET14:
     689             :       {
     690  2884736640 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+2u)/2u;
     691   240081920 :         libmesh_assert_less(i, 4*dofs_per_side);
     692             : 
     693  2884736640 :         const Real zeta[4] = { Real(1.) - p(0) - p(1) - p(2), p(0), p(1), p(2) };
     694             : 
     695   240081920 :         unsigned int face_num = 0;
     696  2884736640 :         if (zeta[0] > zeta[3] &&
     697   992688136 :             zeta[1] > zeta[3] &&
     698    79217916 :             zeta[2] > zeta[3])
     699             :           {
     700    60007536 :             face_num = 0;
     701             :           }
     702  2163466560 :         else if (zeta[0] > zeta[2] &&
     703   750599560 :                  zeta[1] > zeta[2] &&
     704    60010416 :                  zeta[3] > zeta[2])
     705             :           {
     706    60010416 :             face_num = 1;
     707             :           }
     708  1442858576 :         else if (zeta[1] > zeta[0] &&
     709   721207504 :                  zeta[2] > zeta[0] &&
     710    59987424 :                  zeta[3] > zeta[0])
     711             :           {
     712    59987424 :             face_num = 2;
     713             :           }
     714             :         else
     715             :           {
     716             :             // We'd better not be right between two faces
     717    60076544 :             libmesh_assert (zeta[0] > zeta[1] &&
     718             :                             zeta[2] > zeta[1] &&
     719             :                             zeta[3] > zeta[1]);
     720    60076544 :             face_num = 3;
     721             :           }
     722             : 
     723  2884736640 :         if (i < face_num * dofs_per_side ||
     724  1802742588 :             i >= (face_num+1) * dofs_per_side)
     725   180061440 :           return 0;
     726             : 
     727   721184160 :         if (totalorder == 0)
     728      178112 :           return 1;
     729             : 
     730             :         const std::vector<unsigned int> face_vertex =
     731   778887144 :           elem->oriented_face_vertices(face_num);
     732             : 
     733             :         // We only need a Tri3 to evaluate L2_HIERARCHIC on the affine
     734             :         // master element
     735   119684736 :         Tri3 side;
     736             : 
     737             :         // We pinky swear not to modify these nodes
     738    59842368 :         Elem & e = const_cast<Elem &>(*elem);
     739   719044776 :         side.set_node(0, e.node_ptr(face_vertex[0]));
     740   719044776 :         side.set_node(1, e.node_ptr(face_vertex[1]));
     741   719044776 :         side.set_node(2, e.node_ptr(face_vertex[2]));
     742             : 
     743   719044776 :         const unsigned int basisnum = i - face_num*dofs_per_side;
     744             : 
     745   719044776 :         Point sidep {zeta[face_vertex[1]], zeta[face_vertex[2]]};
     746             : 
     747   719044776 :         return FE<2,L2_HIERARCHIC>::shape(&side, totalorder,
     748    59842368 :                                           basisnum, sidep, false);
     749             :       }
     750             : 
     751    95104600 :     case PRISM20:
     752             :     case PRISM21:
     753             :       {
     754  1144287115 :         const unsigned int dofs_per_quad = (totalorder+1u)*(totalorder+1u);
     755  1144287115 :         const unsigned int dofs_per_tri = (totalorder+1u)*(totalorder+2u)/2u;
     756    95104600 :         libmesh_assert_less(i, 3*dofs_per_quad + 2*dofs_per_tri);
     757             : 
     758             :         // We only need a Tri3 or Quad4 to evaluate L2_HIERARCHIC on
     759             :         // the affine master element
     760   190209200 :         Tri3 tri;
     761   190209200 :         Quad4 quad;
     762    95104600 :         Elem * side = &quad;
     763    95104600 :         unsigned int dofs_on_side = dofs_per_quad;
     764             : 
     765             :         // We pinky swear not to modify the nodes we'll point to
     766    95104600 :         Elem & e = const_cast<Elem &>(*elem);
     767             : 
     768    95104600 :         Point sidep;
     769             : 
     770             :         // Face number calculation is tricky - the ordering of side
     771             :         // nodes on Prisms does *not* match the ordering of sides!
     772             :         // (the mid-triangle side nodes were added "later")
     773             :         // Here face_num will be the numbering that matches the side
     774             :         // number, but i_offset will have to consider the nodal
     775             :         // ordering.
     776    95104600 :         unsigned int face_num = 0;
     777    95104600 :         unsigned int i_offset = 0;
     778             : 
     779             :         // Triangular coordinates
     780  1144287115 :         const Real zeta[3] = { Real(1.) - p(0) - p(1), p(0), p(1) };
     781             : 
     782             :         // Closeness to midplane
     783  1144287115 :         const Real zmid = 1 - std::abs(p(2));
     784             : 
     785  1144287115 :         if (zeta[1] > zeta[2] && zeta[0] > zeta[2] &&
     786   377613345 :             zmid > 3*zeta[2]) // face 1, quad
     787             :           {
     788    21012280 :             face_num = 1;
     789    21012280 :             i_offset = 0;
     790             :           }
     791   891497900 :         else if (zeta[1] > zeta[0] && zeta[2] > zeta[0] &&
     792   378143710 :                  zmid > 3*zeta[0]) // face 2, quad
     793             :           {
     794    21012280 :             face_num = 2;
     795    21012280 :             i_offset = dofs_per_quad;
     796             :           }
     797   638853620 :         else if (zeta[0] > zeta[1] && zeta[2] > zeta[1] &&
     798   376661480 :                  zmid > 3*zeta[1]) // face 3, quad
     799             :           {
     800    21012280 :             face_num = 3;
     801   252934150 :             i_offset = 2*dofs_per_quad;
     802             :           }
     803   586705960 :         else if (p(2) + 1 < 3*zeta[0] &&
     804   402016570 :                  p(2) + 1 < 3*zeta[1] &&
     805   193260030 :                  p(2) + 1 < 3*zeta[2]) // face 0, tri
     806             :           {
     807    16097100 :             face_num = 0;
     808   193260030 :             i_offset = 3*dofs_per_quad;
     809    16097100 :             dofs_on_side = dofs_per_tri;
     810    16097100 :             side = &tri;
     811             :           }
     812   369348220 :         else if (1 - p(2) < 3*zeta[0] &&
     813   208630100 :                  1 - p(2) < 3*zeta[1] &&
     814   192659440 :                  1 - p(2) < 3*zeta[2]) // face 4, tri
     815             :           {
     816    15970660 :             face_num = 4;
     817   192659440 :             i_offset = dofs_per_tri + 3*dofs_per_quad;
     818    15970660 :             dofs_on_side = dofs_per_tri;
     819    15970660 :             side = &tri;
     820             :           }
     821             :         else
     822             :           {
     823           0 :             libmesh_error_msg("Evaluating SIDE_HIERARCHIC right between two Prism faces?");
     824             :           }
     825             : 
     826  1144287115 :         if (i < i_offset ||
     827   663248625 :             i >= i_offset + dofs_on_side)
     828    75535040 :           return 0;
     829             : 
     830   235450955 :         if (totalorder == 0)
     831        1400 :           return 1;
     832             : 
     833             :         const std::vector<unsigned int> face_vertex =
     834   255001500 :           elem->oriented_face_vertices(face_num);
     835             : 
     836   255001500 :         side->set_node(0, e.node_ptr(face_vertex[0]));
     837   255001500 :         side->set_node(1, e.node_ptr(face_vertex[1]));
     838   255001500 :         side->set_node(2, e.node_ptr(face_vertex[2]));
     839   255001500 :         if (face_vertex.size() > 3)
     840   194216130 :           side->set_node(3, e.node_ptr(face_vertex[3]));
     841             : 
     842   235433340 :         if (face_num == 0 || face_num == 4)
     843    56121930 :           sidep = {zeta[face_vertex[1]%3], zeta[face_vertex[2]%3]};
     844             :         else
     845             :           {
     846             :             // Transform a coordinate from the master prism to the
     847             :             // master quad, based on two vertex indices defining the
     848             :             // coordinate's direction
     849   358622820 :             auto coord_val = [p](int v1, int v2){
     850   358622820 :               if (v2-v1 == 3)
     851    78513840 :                 return p(2);
     852   280108980 :               else if (v2-v1 == -3)
     853   100797570 :                 return -p(2);
     854   179311410 :               else if (v1%3 == 0 && v2%3 == 1)
     855    31965930 :                 return 2*p(0)-1;
     856   147345480 :               else if (v2%3 == 0 && v1%3 == 1)
     857    27804540 :                 return 1-2*p(0);
     858   119540940 :               else if (v1%3 == 1 && v2%3 == 2)
     859    31432920 :                 return p(1)-p(0);
     860    88108020 :               else if (v2%3 == 1 && v1%3 == 2)
     861    28303320 :                 return p(0)-p(1);
     862    59804700 :               else if (v1%3 == 2 && v2%3 == 0)
     863    20748270 :                 return 1-2*p(1);
     864    39056430 :               else if (v2%3 == 2 && v1%3 == 0)
     865    39056430 :                 return 2*p(1)-1;
     866             :               else
     867           0 :                 libmesh_error();
     868   179311410 :             };
     869             : 
     870   209120850 :             sidep = {coord_val(face_vertex[0], face_vertex[1]),
     871    29809440 :                      coord_val(face_vertex[0], face_vertex[3])};
     872             :           }
     873             : 
     874   235433340 :         const unsigned int basisnum = i - i_offset;
     875             : 
     876   235433340 :         return FE<2,L2_HIERARCHIC>::shape(side, totalorder,
     877    19568160 :                                           basisnum, sidep, false);
     878             :       }
     879             : 
     880             : 
     881           0 :     default:
     882           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
     883             :     }
     884             : 
     885             : #else // LIBMESH_DIM != 3
     886             :   libmesh_ignore(elem, order, i, p, add_p_level);
     887             :   libmesh_not_implemented();
     888             : #endif
     889             : }
     890             : 
     891             : 
     892             : template <>
     893           0 : Real FE<3,SIDE_HIERARCHIC>::shape(const FEType fet,
     894             :                                   const Elem * elem,
     895             :                                   const unsigned int i,
     896             :                                   const Point & p,
     897             :                                   const bool add_p_level)
     898             : {
     899           0 :   return FE<3,SIDE_HIERARCHIC>::shape(elem,fet.order, i, p, add_p_level);
     900             : }
     901             : 
     902             : 
     903             : template <>
     904           0 : Real FE<3,HIERARCHIC>::shape_deriv(const ElemType,
     905             :                                    const Order,
     906             :                                    const unsigned int,
     907             :                                    const unsigned int,
     908             :                                    const Point & )
     909             : {
     910           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
     911             :   return 0.;
     912             : }
     913             : 
     914             : 
     915             : 
     916             : template <>
     917           0 : Real FE<3,L2_HIERARCHIC>::shape_deriv(const ElemType,
     918             :                                       const Order,
     919             :                                       const unsigned int,
     920             :                                       const unsigned int,
     921             :                                       const Point & )
     922             : {
     923           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
     924             :   return 0.;
     925             : }
     926             : 
     927             : 
     928             : 
     929             : template <>
     930           0 : Real FE<3,SIDE_HIERARCHIC>::shape_deriv(const ElemType,
     931             :                                         const Order,
     932             :                                         const unsigned int,
     933             :                                         const unsigned int,
     934             :                                         const Point & )
     935             : {
     936           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
     937             :   return 0.;
     938             : }
     939             : 
     940             : 
     941             : 
     942             : template <>
     943   421855626 : Real FE<3,HIERARCHIC>::shape_deriv(const Elem * elem,
     944             :                                    const Order order,
     945             :                                    const unsigned int i,
     946             :                                    const unsigned int j,
     947             :                                    const Point & p,
     948             :                                    const bool add_p_level)
     949             : {
     950   808746099 :   return fe_hierarchic_3D_shape_deriv<HIERARCHIC>(elem, order, i, j, p, add_p_level);
     951             : }
     952             : 
     953             : 
     954             : template <>
     955           0 : Real FE<3,HIERARCHIC>::shape_deriv(const FEType fet,
     956             :                                    const Elem * elem,
     957             :                                    const unsigned int i,
     958             :                                    const unsigned int j,
     959             :                                    const Point & p,
     960             :                                    const bool add_p_level)
     961             : {
     962           0 :   return fe_hierarchic_3D_shape_deriv<HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
     963             : }
     964             : 
     965             : 
     966             : 
     967             : template <>
     968   695091552 : Real FE<3,L2_HIERARCHIC>::shape_deriv(const Elem * elem,
     969             :                                       const Order order,
     970             :                                       const unsigned int i,
     971             :                                       const unsigned int j,
     972             :                                       const Point & p,
     973             :                                       const bool add_p_level)
     974             : {
     975  1333177182 :   return fe_hierarchic_3D_shape_deriv<L2_HIERARCHIC>(elem, order, i, j, p, add_p_level);
     976             : }
     977             : 
     978             : 
     979             : template <>
     980           0 : Real FE<3,L2_HIERARCHIC>::shape_deriv(const FEType fet,
     981             :                                       const Elem * elem,
     982             :                                       const unsigned int i,
     983             :                                       const unsigned int j,
     984             :                                       const Point & p,
     985             :                                       const bool add_p_level)
     986             : {
     987           0 :   return fe_hierarchic_3D_shape_deriv<L2_HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
     988             : }
     989             : 
     990             : 
     991             : 
     992             : template <>
     993  2042311680 : Real FE<3,SIDE_HIERARCHIC>::shape_deriv(const Elem * elem,
     994             :                                         const Order order,
     995             :                                         const unsigned int i,
     996             :                                         const unsigned int j,
     997             :                                         const Point & p,
     998             :                                         const bool add_p_level)
     999             : {
    1000             : #if LIBMESH_DIM == 3
    1001   170192640 :   libmesh_assert(elem);
    1002  2042311680 :   const ElemType type = elem->type();
    1003             : 
    1004  2212504320 :   const Order totalorder = order + add_p_level*elem->p_level();
    1005             : 
    1006  2042311680 :   if (totalorder == 0) // special case since raw HIERARCHIC lacks CONSTANTs
    1007       62400 :     return 0; // constants have zero derivative
    1008             : 
    1009  2041562880 :   switch (type)
    1010             :     {
    1011    19448640 :     case HEX27:
    1012             :       {
    1013             :         // I need to debug the p>2 case here...
    1014   233383680 :         if (totalorder > 2)
    1015   228355200 :           return fe_fdm_deriv(elem, order, i, j, p, add_p_level, FE<3,SIDE_HIERARCHIC>::shape);
    1016             : 
    1017     5028480 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
    1018      419040 :         libmesh_assert_less(i, 6*dofs_per_side);
    1019             : 
    1020     5028480 :         const unsigned int sidenum = cube_side(p);
    1021     5028480 :         if (sidenum > 5)
    1022           0 :           return std::numeric_limits<Real>::quiet_NaN();
    1023             : 
    1024     5028480 :         const unsigned int dof_offset = sidenum * dofs_per_side;
    1025             : 
    1026     5028480 :         if (i < dof_offset) // i is on a previous side
    1027      174600 :           return 0;
    1028             : 
    1029     2933280 :         if (i >= dof_offset + dofs_per_side) // i is on a later side
    1030      174600 :           return 0;
    1031             : 
    1032      838080 :         unsigned int side_i = i - dof_offset;
    1033             : 
    1034      838080 :         std::unique_ptr<const Elem> side = elem->build_side_ptr(sidenum);
    1035             : 
    1036      838080 :         Point sidep = cube_side_point(sidenum, p);
    1037             : 
    1038      838080 :         cube_remap(side_i, *elem, sidenum, *side, totalorder, sidep);
    1039             : 
    1040             :         // What direction on the side corresponds to the derivative
    1041             :         // direction we want?
    1042       69840 :         unsigned int sidej = 100;
    1043             : 
    1044             :         // Do we need a -1 here to flip that direction?
    1045       69840 :         Real f = 1.;
    1046             : 
    1047             :         switch (j)
    1048             :           {
    1049      279360 :           case 0: // d()/dxi
    1050             :             {
    1051             :               switch (sidenum)
    1052             :                 {
    1053        3880 :                 case 0:
    1054        3880 :                   sidej = 1;
    1055        3880 :                   break;
    1056        7760 :                 case 1:
    1057        3880 :                   sidej = 0;
    1058        7760 :                   break;
    1059        3880 :                 case 2:
    1060        3880 :                   return 0;
    1061       46560 :                 case 3:
    1062        3880 :                   sidej = 0;
    1063        3880 :                   f = -1;
    1064       46560 :                   break;
    1065        3880 :                 case 4:
    1066        3880 :                   return 0;
    1067        7760 :                 case 5:
    1068        3880 :                   sidej = 0;
    1069        7760 :                   break;
    1070           0 :                 default:
    1071           0 :                   libmesh_error();
    1072             :                 }
    1073       15520 :               break;
    1074             :             }
    1075      279360 :           case 1: // d()/deta
    1076             :             {
    1077             :               switch (sidenum)
    1078             :                 {
    1079        3880 :                 case 0:
    1080        3880 :                   sidej = 0;
    1081        3880 :                   break;
    1082        3880 :                 case 1:
    1083        3880 :                   return 0;
    1084        3880 :                 case 2:
    1085        3880 :                   sidej = 0;
    1086        3880 :                   break;
    1087        3880 :                 case 3:
    1088        3880 :                   return 0;
    1089       46560 :                 case 4:
    1090        3880 :                   sidej = 0;
    1091        3880 :                   f = -1;
    1092       46560 :                   break;
    1093        7760 :                 case 5:
    1094        3880 :                   sidej = 1;
    1095        7760 :                   break;
    1096           0 :                 default:
    1097           0 :                   libmesh_error();
    1098             :                 }
    1099       15520 :               break;
    1100             :             }
    1101      279360 :           case 2: // d()/dzeta
    1102             :             {
    1103             :               switch (sidenum)
    1104             :                 {
    1105        3880 :                 case 0:
    1106        3880 :                   return 0;
    1107       15520 :                 case 1:
    1108             :                 case 2:
    1109             :                 case 3:
    1110             :                 case 4:
    1111       15520 :                   sidej = 1;
    1112       15520 :                   break;
    1113        3880 :                 case 5:
    1114        3880 :                   return 0;
    1115           0 :                 default:
    1116           0 :                   libmesh_error();
    1117             :                 }
    1118       15520 :               break;
    1119             :             }
    1120             : 
    1121           0 :           default:
    1122           0 :             libmesh_error_msg("Invalid derivative index j = " << j);
    1123             :           }
    1124             : 
    1125      558720 :         return f * FE<2,HIERARCHIC>::shape_deriv(side.get(), order,
    1126             :                                                  side_i, sidej, sidep,
    1127      558720 :                                                  add_p_level);
    1128      698400 :       }
    1129             : 
    1130  1808179200 :     case TET14:
    1131             :     case PRISM20:
    1132             :     case PRISM21:
    1133             :       {
    1134  1808179200 :         return fe_fdm_deriv(elem, order, i, j, p, add_p_level, FE<3,SIDE_HIERARCHIC>::shape);
    1135             :       }
    1136             : 
    1137           0 :     default:
    1138           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    1139             :     }
    1140             : 
    1141             : #else // LIBMESH_DIM != 3
    1142             :   libmesh_ignore(elem, order, i, j, p, add_p_level);
    1143             :   libmesh_not_implemented();
    1144             : #endif
    1145             : }
    1146             : 
    1147             : 
    1148             : template <>
    1149           0 : Real FE<3,SIDE_HIERARCHIC>::shape_deriv(const FEType fet,
    1150             :                                         const Elem * elem,
    1151             :                                         const unsigned int i,
    1152             :                                         const unsigned int j,
    1153             :                                         const Point & p,
    1154             :                                         const bool add_p_level)
    1155             : {
    1156           0 :   return FE<3,SIDE_HIERARCHIC>::shape_deriv(elem, fet.order, i, j, p, add_p_level);
    1157             : }
    1158             : 
    1159             : 
    1160             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1161             : 
    1162             : template <>
    1163           0 : Real FE<3,HIERARCHIC>::shape_second_deriv(const ElemType,
    1164             :                                           const Order,
    1165             :                                           const unsigned int,
    1166             :                                           const unsigned int,
    1167             :                                           const Point & )
    1168             : {
    1169           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1170             :   return 0.;
    1171             : }
    1172             : 
    1173             : 
    1174             : 
    1175             : template <>
    1176           0 : Real FE<3,L2_HIERARCHIC>::shape_second_deriv(const ElemType,
    1177             :                                              const Order,
    1178             :                                              const unsigned int,
    1179             :                                              const unsigned int,
    1180             :                                              const Point & )
    1181             : {
    1182           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1183             :   return 0.;
    1184             : }
    1185             : 
    1186             : 
    1187             : 
    1188             : template <>
    1189           0 : Real FE<3,SIDE_HIERARCHIC>::shape_second_deriv(const ElemType,
    1190             :                                                const Order,
    1191             :                                                const unsigned int,
    1192             :                                                const unsigned int,
    1193             :                                                const Point & )
    1194             : {
    1195           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1196             :   return 0.;
    1197             : }
    1198             : 
    1199             : 
    1200             : 
    1201             : template <>
    1202   156002052 : Real FE<3,HIERARCHIC>::shape_second_deriv(const Elem * elem,
    1203             :                                           const Order order,
    1204             :                                           const unsigned int i,
    1205             :                                           const unsigned int j,
    1206             :                                           const Point & p,
    1207             :                                           const bool add_p_level)
    1208             : {
    1209   299079726 :   return fe_hierarchic_3D_shape_second_deriv<HIERARCHIC>(elem, order, i, j, p, add_p_level);
    1210             : }
    1211             : 
    1212             : 
    1213             : 
    1214             : template <>
    1215           0 : Real FE<3,HIERARCHIC>::shape_second_deriv(const FEType fet,
    1216             :                                           const Elem * elem,
    1217             :                                           const unsigned int i,
    1218             :                                           const unsigned int j,
    1219             :                                           const Point & p,
    1220             :                                           const bool add_p_level)
    1221             : {
    1222           0 :   return fe_hierarchic_3D_shape_second_deriv<HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
    1223             : }
    1224             : 
    1225             : 
    1226             : 
    1227             : template <>
    1228   252148476 : Real FE<3,L2_HIERARCHIC>::shape_second_deriv(const Elem * elem,
    1229             :                                              const Order order,
    1230             :                                              const unsigned int i,
    1231             :                                              const unsigned int j,
    1232             :                                              const Point & p,
    1233             :                                              const bool add_p_level)
    1234             : {
    1235   483628464 :   return fe_hierarchic_3D_shape_second_deriv<L2_HIERARCHIC>(elem, order, i, j, p, add_p_level);
    1236             : }
    1237             : 
    1238             : 
    1239             : template <>
    1240           0 : Real FE<3,L2_HIERARCHIC>::shape_second_deriv(const FEType fet,
    1241             :                                              const Elem * elem,
    1242             :                                              const unsigned int i,
    1243             :                                              const unsigned int j,
    1244             :                                              const Point & p,
    1245             :                                              const bool add_p_level)
    1246             : {
    1247           0 :   return fe_hierarchic_3D_shape_second_deriv<L2_HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
    1248             : }
    1249             : 
    1250             : 
    1251             : template <>
    1252   826168320 : Real FE<3,SIDE_HIERARCHIC>::shape_second_deriv(const Elem * elem,
    1253             :                                                const Order order,
    1254             :                                                const unsigned int i,
    1255             :                                                const unsigned int j,
    1256             :                                                const Point & p,
    1257             :                                                const bool add_p_level)
    1258             : {
    1259             : #if LIBMESH_DIM == 3
    1260    68847360 :   libmesh_assert(elem);
    1261   826168320 :   const ElemType type = elem->type();
    1262             : 
    1263   895015680 :   const Order totalorder = order + add_p_level*elem->p_level();
    1264             : 
    1265   826168320 :   if (totalorder == 0) // special case since raw HIERARCHIC lacks CONSTANTs
    1266      124800 :     return 0; // constants have zero derivative
    1267             : 
    1268   824670720 :   switch (type)
    1269             :     {
    1270     8449920 :     case HEX27:
    1271             :       {
    1272             :         // I need to debug the p>2 case here...
    1273   101399040 :         if (totalorder > 2)
    1274    91342080 :           return fe_fdm_second_deriv(elem, order, i, j, p, add_p_level,
    1275     7611840 :                                      FE<3,SIDE_HIERARCHIC>::shape_deriv);
    1276             : 
    1277    10056960 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
    1278      838080 :         libmesh_assert_less(i, 6*dofs_per_side);
    1279             : 
    1280    10056960 :         const unsigned int sidenum = cube_side(p);
    1281    10056960 :         if (sidenum > 5)
    1282           0 :           return std::numeric_limits<Real>::quiet_NaN();
    1283             : 
    1284    10056960 :         const unsigned int dof_offset = sidenum * dofs_per_side;
    1285             : 
    1286    10056960 :         if (i < dof_offset) // i is on a previous side
    1287      349200 :           return 0;
    1288             : 
    1289     5866560 :         if (i >= dof_offset + dofs_per_side) // i is on a later side
    1290      349200 :           return 0;
    1291             : 
    1292     1676160 :         unsigned int side_i = i - dof_offset;
    1293             : 
    1294     1676160 :         std::unique_ptr<const Elem> side = elem->build_side_ptr(sidenum);
    1295             : 
    1296     1676160 :         Point sidep = cube_side_point(sidenum, p);
    1297             : 
    1298     1676160 :         cube_remap(side_i, *elem, sidenum, *side, totalorder, sidep);
    1299             : 
    1300             :         // What second derivative or mixed derivative on the side
    1301             :         // corresponds to the xi/eta/zeta mix we were asked for?
    1302      139680 :         unsigned int sidej = 100;
    1303             : 
    1304             :         // Do we need a -1 here to flip the final derivative value?
    1305      139680 :         Real f = 1.;
    1306             : 
    1307             :         switch (j)
    1308             :           {
    1309      279360 :           case 0: // d^2()/dxi^2
    1310             :             {
    1311             :               switch (sidenum)
    1312             :                 {
    1313        3880 :                 case 0:
    1314        3880 :                   sidej = 2;
    1315        3880 :                   break;
    1316        7760 :                 case 1:
    1317        3880 :                   sidej = 0;
    1318        7760 :                   break;
    1319        3880 :                 case 2:
    1320        3880 :                   return 0;
    1321        7760 :                 case 3:
    1322        3880 :                   sidej = 0;
    1323        7760 :                   break;
    1324        3880 :                 case 4:
    1325        3880 :                   return 0;
    1326        7760 :                 case 5:
    1327        3880 :                   sidej = 0;
    1328        7760 :                   break;
    1329           0 :                 default:
    1330           0 :                   libmesh_error();
    1331             :                 }
    1332       15520 :               break;
    1333             :             }
    1334      279360 :           case 1: // d^2()/dxideta
    1335             :             {
    1336             :               switch (sidenum)
    1337             :                 {
    1338        3880 :                 case 0:
    1339        3880 :                   sidej = 1;
    1340        3880 :                   break;
    1341       15520 :                 case 1:
    1342             :                 case 2:
    1343             :                 case 3:
    1344             :                 case 4:
    1345       15520 :                   return 0;
    1346        3880 :                 case 5:
    1347        3880 :                   sidej = 1;
    1348        3880 :                   break;
    1349           0 :                 default:
    1350           0 :                   libmesh_error();
    1351             :                 }
    1352        7760 :               break;
    1353             :             }
    1354      279360 :           case 2: // d^2()/deta^2
    1355             :             {
    1356             :               switch (sidenum)
    1357             :                 {
    1358        3880 :                 case 0:
    1359        3880 :                   sidej = 0;
    1360        3880 :                   break;
    1361        3880 :                 case 1:
    1362        3880 :                   return 0;
    1363        3880 :                 case 2:
    1364        3880 :                   sidej = 0;
    1365        3880 :                   break;
    1366        3880 :                 case 3:
    1367        3880 :                   return 0;
    1368        3880 :                 case 4:
    1369        3880 :                   sidej = 0;
    1370        3880 :                   break;
    1371        3880 :                 case 5:
    1372        3880 :                   sidej = 2;
    1373        3880 :                   break;
    1374           0 :                 default:
    1375           0 :                   libmesh_error();
    1376             :                 }
    1377       15520 :               break;
    1378             :             }
    1379      279360 :           case 3: // d^2()/dxidzeta
    1380             :             {
    1381             :               switch (sidenum)
    1382             :                 {
    1383        3880 :                 case 0:
    1384        3880 :                   return 0;
    1385        3880 :                 case 1:
    1386        3880 :                   sidej = 1;
    1387        3880 :                   break;
    1388        3880 :                 case 2:
    1389        3880 :                   return 0;
    1390        3880 :                 case 3:
    1391        3880 :                   sidej = 1;
    1392        3880 :                   f = -1;
    1393        3880 :                   break;
    1394        7760 :                 case 4:
    1395             :                 case 5:
    1396        7760 :                   return 0;
    1397           0 :                 default:
    1398           0 :                   libmesh_error();
    1399             :                 }
    1400        7760 :               break;
    1401             :             }
    1402      279360 :           case 4: // d^2()/detadzeta
    1403             :             {
    1404             :               switch (sidenum)
    1405             :                 {
    1406        7760 :                 case 0:
    1407             :                 case 1:
    1408        7760 :                   return 0;
    1409        3880 :                 case 2:
    1410        3880 :                   sidej = 1;
    1411        3880 :                   break;
    1412        3880 :                 case 3:
    1413        3880 :                   return 0;
    1414        3880 :                 case 4:
    1415        3880 :                   sidej = 1;
    1416        3880 :                   f = -1;
    1417        3880 :                   break;
    1418        3880 :                 case 5:
    1419        3880 :                   return 0;
    1420           0 :                 default:
    1421           0 :                   libmesh_error();
    1422             :                 }
    1423        7760 :               break;
    1424             :             }
    1425      279360 :           case 5: // d^2()/dzeta^2
    1426             :             {
    1427             :               switch (sidenum)
    1428             :                 {
    1429        3880 :                 case 0:
    1430        3880 :                   return 0;
    1431       15520 :                 case 1:
    1432             :                 case 2:
    1433             :                 case 3:
    1434             :                 case 4:
    1435       15520 :                   sidej = 2;
    1436       15520 :                   break;
    1437        3880 :                 case 5:
    1438        3880 :                   return 0;
    1439           0 :                 default:
    1440           0 :                   libmesh_error();
    1441             :                 }
    1442       15520 :               break;
    1443             :             }
    1444             : 
    1445           0 :           default:
    1446           0 :             libmesh_error_msg("Invalid derivative index j = " << j);
    1447             :           }
    1448             : 
    1449      838080 :         return f * FE<2,HIERARCHIC>::shape_second_deriv(side.get(),
    1450             :                                                         order, side_i,
    1451             :                                                         sidej, sidep,
    1452      838080 :                                                         add_p_level);
    1453     1396800 :       }
    1454             : 
    1455   723271680 :     case TET14:
    1456             :     case PRISM20:
    1457             :     case PRISM21:
    1458             :       {
    1459   723271680 :         return fe_fdm_second_deriv(elem, order, i, j, p, add_p_level,
    1460   723271680 :                                    FE<3,SIDE_HIERARCHIC>::shape_deriv);
    1461             :       }
    1462             : 
    1463           0 :     default:
    1464           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    1465             :     }
    1466             : 
    1467             : #else // LIBMESH_DIM != 3
    1468             :   libmesh_ignore(elem, order, i, j, p, add_p_level);
    1469             :   libmesh_not_implemented();
    1470             : #endif
    1471             : }
    1472             : 
    1473             : 
    1474             : template <>
    1475           0 : Real FE<3,SIDE_HIERARCHIC>::shape_second_deriv(const FEType fet,
    1476             :                                                const Elem * elem,
    1477             :                                                const unsigned int i,
    1478             :                                                const unsigned int j,
    1479             :                                                const Point & p,
    1480             :                                                const bool add_p_level)
    1481             : {
    1482           0 :   return FE<3,SIDE_HIERARCHIC>::shape_second_deriv(elem, fet.order, i, j, p, add_p_level);
    1483             : }
    1484             : 
    1485             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
    1486             : 
    1487             : } // namespace libMesh
    1488             : 
    1489             : 
    1490             : 
    1491             : namespace
    1492             : {
    1493             : using namespace libMesh;
    1494             : 
    1495             : 
    1496   515418714 : unsigned int cube_side (const Point & p)
    1497             : {
    1498   515418714 :   const Real xi = p(0), eta = p(1), zeta = p(2);
    1499   515418714 :   const Real absxi   = std::abs(xi),
    1500   515418714 :              abseta  = std::abs(eta),
    1501   515418714 :              abszeta = std::abs(zeta);
    1502   515418714 :   const Real maxabs_xi_eta   = std::max(absxi, abseta),
    1503   515418714 :              maxabs_xi_zeta  = std::max(absxi, abszeta),
    1504   515418714 :              maxabs_eta_zeta = std::max(abseta, abszeta);
    1505             : 
    1506   515418714 :   if (zeta < -maxabs_xi_eta)
    1507     7151148 :     return 0;
    1508   429516196 :   else if (eta < -maxabs_xi_zeta)
    1509     7171126 :     return 1;
    1510   343477936 :   else if (xi > maxabs_eta_zeta)
    1511     7188558 :     return 2;
    1512   257348620 :   else if (eta > maxabs_xi_zeta)
    1513     7158032 :     return 3;
    1514   171597400 :   else if (xi < -maxabs_eta_zeta)
    1515     7006032 :     return 4;
    1516    86307298 :   else if (zeta > maxabs_xi_eta)
    1517    85877350 :     return 5;
    1518             : 
    1519             :   // We need to be able to return invalid values for cases where
    1520             :   // mixed FE are being evaluated together on edges and vertices
    1521       25920 :   return 65535;
    1522             : }
    1523             : 
    1524             : 
    1525             : 
    1526    88992834 : Point cube_side_point(unsigned int sidenum, const Point & p)
    1527             : {
    1528     7397584 :   Point sidep;
    1529             : 
    1530    88992834 :   switch (sidenum)
    1531             :     {
    1532    14834316 :     case 0:
    1533    14834316 :       sidep(0) = p(1);
    1534    14834316 :       sidep(1) = p(0);
    1535    14834316 :       break;
    1536    14866568 :     case 1:
    1537    14866568 :       sidep(0) = p(0);
    1538    14866568 :       sidep(1) = p(2);
    1539    14866568 :       break;
    1540    14873064 :     case 2:
    1541    14873064 :       sidep(0) = p(1);
    1542    14873064 :       sidep(1) = p(2);
    1543    14873064 :       break;
    1544    14818788 :     case 3:
    1545    14818788 :       sidep(0) = -p(0);
    1546    14818788 :       sidep(1) = p(2);
    1547    14818788 :       break;
    1548    14750670 :     case 4:
    1549    14750670 :       sidep(0) = -p(1);
    1550    14750670 :       sidep(1) = p(2);
    1551    14750670 :       break;
    1552    14849428 :     case 5:
    1553    14849428 :       sidep(0) = p(0);
    1554    14849428 :       sidep(1) = p(1);
    1555    14849428 :       break;
    1556           0 :     default:
    1557           0 :       libmesh_error();
    1558             :     }
    1559             : 
    1560    88992834 :   return sidep;
    1561             : }
    1562             : 
    1563             : 
    1564             : 
    1565             : template <FEFamily T>
    1566  2660333636 : Real fe_hierarchic_3D_shape(const Elem * elem,
    1567             :                             const Order order,
    1568             :                             const unsigned int i,
    1569             :                             const Point & p,
    1570             :                             const bool add_p_level)
    1571             : {
    1572             : #if LIBMESH_DIM == 3
    1573             : 
    1574   218716468 :   libmesh_assert(elem);
    1575  2660333636 :   const ElemType type = elem->type();
    1576             : 
    1577  2879050104 :   const Order totalorder = order + add_p_level*elem->p_level();
    1578             : 
    1579  2441617168 :   switch (type)
    1580             :     {
    1581   912816426 :     case HEX8:
    1582             :     case HEX20:
    1583    17128636 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 2);
    1584             :       libmesh_fallthrough();
    1585             :     case HEX27:
    1586             :       {
    1587    78858204 :         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
    1588             : 
    1589             :         // Compute hex shape functions as a tensor-product
    1590   974545994 :         Real xi   = p(0);
    1591   974545994 :         Real eta  = p(1);
    1592   974545994 :         Real zeta = p(2);
    1593             : 
    1594             :         unsigned int i0, i1, i2;
    1595             : 
    1596   974545994 :         cube_indices(elem, totalorder, i, xi, eta, zeta, i0, i1, i2);
    1597             : 
    1598  1053404198 :         return (FE<1,T>::shape(EDGE3, totalorder, i0, xi)*
    1599  1053404198 :                 FE<1,T>::shape(EDGE3, totalorder, i1, eta)*
    1600  1053404198 :                 FE<1,T>::shape(EDGE3, totalorder, i2, zeta));
    1601             :       }
    1602             : 
    1603   886578588 :     case PRISM6:
    1604             :     case PRISM15:
    1605    16503294 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 2);
    1606             :       libmesh_fallthrough();
    1607             :     case PRISM18:
    1608    19362150 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 3);
    1609             :       libmesh_fallthrough();
    1610             :     case PRISM20:
    1611             :     case PRISM21:
    1612             :       {
    1613    85295454 :         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+2u)/2u);
    1614             : 
    1615             :         // Compute prism shape functions as a tensor-product.
    1616             :         // Non-const here, because prism_indices might need to do some
    1617             :         // flips before evaluating edge or face DoFs
    1618   955370748 :         Point xi_eta {p(0),p(1)};
    1619   955370748 :         Real zeta = p(2);
    1620             : 
    1621             :         unsigned int i01, i2;
    1622             : 
    1623   955370748 :         prism_indices(elem, totalorder, i, xi_eta, zeta, i01, i2);
    1624             : 
    1625             :         // We'll use the 2D Tri to handle any basis function flipping
    1626             :         // needed in xi/eta for triangle face+edge bases.
    1627    85295454 :         Tri3 tri;
    1628             : 
    1629             :         // We pinky swear not to modify these nodes
    1630    85295454 :         Elem & e = const_cast<Elem &>(*elem);
    1631   955370748 :         if (i2 == 0)
    1632             :           {
    1633    40714860 :             tri.set_node(0, e.node_ptr(0));
    1634    20357430 :             tri.set_node(1, e.node_ptr(1));
    1635    20357430 :             tri.set_node(2, e.node_ptr(2));
    1636             :           }
    1637   727344312 :         else if (i2 == 1)
    1638             :           {
    1639    40714860 :             tri.set_node(0, e.node_ptr(3));
    1640    20357430 :             tri.set_node(1, e.node_ptr(4));
    1641    20357430 :             tri.set_node(2, e.node_ptr(5));
    1642             :           }
    1643             :         else
    1644             :           {
    1645             :             // For interior DoFs, no flipping is necessary or done; we
    1646             :             // can just evaluate on any triangle ... but *not* the
    1647             :             // obvious 9,10,11 triangle, because that might not exist
    1648             :             // if we have L2_HIERARCHIC on Prism6.
    1649    89161188 :             tri.set_node(0, e.node_ptr(0));
    1650    44580594 :             tri.set_node(1, e.node_ptr(1));
    1651    44580594 :             tri.set_node(2, e.node_ptr(2));
    1652             : 
    1653             :             // For square face DoFs, prism_indices handles flipping,
    1654             :             // and we *can't* override that in the tri shape call.
    1655   499314756 :             if (i01 > 2 && i01 < 3u*totalorder)
    1656             :               {
    1657             :                 // %(p-1) to find the edge number, %2 for even vs odd
    1658   295542216 :                 const bool odd_basis = ((i01-3)%(totalorder-1))%2;
    1659   295542216 :                 if (odd_basis)
    1660             :                   {
    1661   103152204 :                     const int tri_edge = (i01-3)/(totalorder-1);
    1662             :                     // Flip nodes now to avoid triggering a shape
    1663             :                     // function flip later
    1664   121571448 :                     if (tri.point(tri_edge) > tri.point((tri_edge+1)%3))
    1665             :                       {
    1666     9745492 :                         Node * n = tri.node_ptr(tri_edge);
    1667     4872746 :                         tri.set_node(tri_edge, tri.node_ptr((tri_edge+1)%3));
    1668     4872746 :                         tri.set_node((tri_edge+1)%3, n);
    1669             :                       }
    1670             :                   }
    1671             :               }
    1672             :           }
    1673             : 
    1674   955370748 :         return (FE<2,L2_HIERARCHIC>::shape(&tri, totalorder, i01, xi_eta)*
    1675  1040666202 :                 FE<1,L2_HIERARCHIC>::shape(EDGE2, totalorder, i2, zeta));
    1676             :       }
    1677             : 
    1678   676997932 :     case TET4:
    1679     1143848 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 2);
    1680             :       libmesh_fallthrough();
    1681             :     case TET10:
    1682     3275051 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 3);
    1683             :       libmesh_fallthrough();
    1684             :     case TET14:
    1685             :       {
    1686   730416894 :         const Real zeta[4] = { 1 - p(0) - p(1) - p(2), p(0), p(1), p(2) };
    1687             : 
    1688             :         // Nodal DoFs
    1689   730416894 :         if (i < 4)
    1690   395715748 :           return zeta[i];
    1691             : 
    1692             :         // Edge DoFs
    1693   334701146 :         else if (i < 6u*totalorder - 2u)
    1694             :           {
    1695   283191414 :             const unsigned int edge_num = (i - 4) / (totalorder - 1u);
    1696             :             // const int edge_node = edge_num + 4;
    1697   283191414 :             const unsigned int basisorder = i - 2 - ((totalorder - 1u) * edge_num);
    1698             : 
    1699   283191414 :             const unsigned int edgevertex0 = Tet4::edge_nodes_map[edge_num][0],
    1700   283191414 :                                edgevertex1 = Tet4::edge_nodes_map[edge_num][1];
    1701             : 
    1702             :             // Get factors to account for edge-flipping
    1703    20248452 :             Real flip = 1;
    1704   319450356 :             if (basisorder%2 &&
    1705    36258942 :                 elem->positive_edge_orientation(edge_num))
    1706      937446 :               flip = -1;
    1707             : 
    1708   283191414 :             const Real crossval = zeta[edgevertex0] + zeta[edgevertex1];
    1709   283191414 :             const Real edgenumerator = zeta[edgevertex1] - zeta[edgevertex0];
    1710             : 
    1711   283191414 :             if (crossval == 0.) // Yes, exact comparison; we seem numerically stable otherwise
    1712             :               {
    1713       57913 :                 unsigned int basisfactorial = 1.;
    1714     2574916 :                 for (unsigned int n=2; n <= basisorder; ++n)
    1715     1522573 :                   basisfactorial *= n;
    1716             : 
    1717     1052343 :                 return flip * std::pow(edgenumerator, basisorder) / basisfactorial;
    1718             :               }
    1719             : 
    1720   282139071 :             const Real edgeval = edgenumerator / crossval;
    1721    20190539 :             const Real crossfunc = std::pow(crossval, basisorder);
    1722             : 
    1723   282139071 :             return flip * crossfunc *
    1724   282139071 :               FE<1,HIERARCHIC>::shape(EDGE3, totalorder,
    1725   282139071 :                                       basisorder, edgeval);
    1726             :           }
    1727             : 
    1728             :         // Face DoFs
    1729    51509732 :         else if (i < 2u*totalorder*totalorder + 2u)
    1730             :           {
    1731    48515412 :             const int dofs_per_face = (totalorder - 1u) * (totalorder - 2u) / 2;
    1732    48515412 :             const int face_num = (i - (6u*totalorder - 2u)) / dofs_per_face;
    1733             : 
    1734    48515412 :             const std::vector<unsigned int> face_vertex =
    1735             :               elem->oriented_face_vertices(face_num);
    1736    48515412 :             const Real zeta0 = zeta[face_vertex[0]],
    1737    48515412 :                        zeta1 = zeta[face_vertex[1]],
    1738    48515412 :                        zeta2 = zeta[face_vertex[2]];
    1739             : 
    1740    48515412 :             const unsigned int basisnum =
    1741    51011736 :               i - 4 -
    1742    51011736 :               (totalorder - 1u) * /*n_edges*/6 -
    1743    48515412 :               (dofs_per_face * face_num);
    1744             : 
    1745    48515412 :             const unsigned int exp0 = triangular_number_column[basisnum] + 1;
    1746    48515412 :             const unsigned int exp1 = triangular_number_row[basisnum] + 1 -
    1747             :               triangular_number_column[basisnum];
    1748             : 
    1749     2496324 :             Real returnval = 1;
    1750   110172776 :             for (unsigned int n = 0; n != exp0; ++n)
    1751    61657364 :               returnval *= zeta0;
    1752   110172776 :             for (unsigned int n = 0; n != exp1; ++n)
    1753    61657364 :               returnval *= zeta1;
    1754    48515412 :             returnval *= zeta2;
    1755     2496324 :             return returnval;
    1756             :           }
    1757             : 
    1758             :         // Interior DoFs
    1759             :         else
    1760             :           {
    1761     2994320 :             const unsigned int basisnum = i - 2u*totalorder*totalorder - 2u;
    1762     2994320 :             const unsigned int exp0 = tetrahedral_number_column[basisnum] + 1;
    1763     3290116 :             const unsigned int exp1 = tetrahedral_number_row[basisnum] + 1 -
    1764     2994320 :                                       tetrahedral_number_column[basisnum] -
    1765     2698524 :                                       tetrahedral_number_page[basisnum];
    1766     2994320 :             const unsigned int exp2 = tetrahedral_number_page[basisnum] + 1;
    1767             : 
    1768      147898 :             Real returnval = 1;
    1769     5988640 :             for (unsigned int n = 0; n != exp0; ++n)
    1770     2994320 :               returnval *= zeta[0];
    1771     5988640 :             for (unsigned int n = 0; n != exp1; ++n)
    1772     2994320 :               returnval *= zeta[1];
    1773     5988640 :             for (unsigned int n = 0; n != exp2; ++n)
    1774     2994320 :               returnval *= zeta[2];
    1775     2994320 :             returnval *= zeta[3];
    1776     2994320 :             return returnval;
    1777             :           }
    1778             :       }
    1779             : 
    1780           0 :     default:
    1781           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    1782             :     }
    1783             : 
    1784             : #else // LIBMESH_DIM != 3
    1785             :   libmesh_ignore(elem, order, i, p, add_p_level);
    1786             :   libmesh_not_implemented();
    1787             : #endif
    1788             : }
    1789             : 
    1790             : 
    1791             : 
    1792             : template <FEFamily T>
    1793    91971075 : Real fe_hierarchic_3D_shape_deriv(const Elem * elem,
    1794             :                                   const Order order,
    1795             :                                   const unsigned int i,
    1796             :                                   const unsigned int j,
    1797             :                                   const Point & p,
    1798             :                                   const bool add_p_level)
    1799             : {
    1800  1116947178 :   return fe_fdm_deriv(elem, order, i, j, p, add_p_level, FE<3,T>::shape);
    1801             : }
    1802             : 
    1803             : 
    1804             : 
    1805             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1806             : 
    1807             : template <FEFamily T>
    1808    33592866 : Real fe_hierarchic_3D_shape_second_deriv(const Elem * elem,
    1809             :                                          const Order order,
    1810             :                                          const unsigned int i,
    1811             :                                          const unsigned int j,
    1812             :                                          const Point & p,
    1813             :                                          const bool add_p_level)
    1814             : {
    1815   408150528 :   return fe_fdm_second_deriv(elem, order, i, j, p, add_p_level,
    1816    33592866 :                              FE<3,T>::shape_deriv);
    1817             : }
    1818             : 
    1819             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
    1820             : 
    1821             : 
    1822             : } // anonymous namespace

Generated by: LCOV version 1.14