LCOV - code coverage report
Current view: top level - src/fe - fe_hierarchic_shape_3D.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4546 (ebe2b5) with base a20bc7 Lines: 1022 1140 89.6 %
Date: 2026-09-11 19:50:22 Functions: 42 60 70.0 %
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 + side_nodes_map
      25             : #include "libmesh/cell_prism6.h"
      26             : #include "libmesh/face_tri3.h" // Faster to construct these on the stack
      27             : #include "libmesh/face_quad4.h"
      28             : 
      29             : // Anonymous namespace for functions shared by HIERARCHIC and
      30             : // L2_HIERARCHIC implementations. Implementations appear at the bottom
      31             : // of this file.
      32             : namespace
      33             : {
      34             : using namespace libMesh;
      35             : 
      36             : unsigned int cube_side(const Point & p);
      37             : 
      38             : Point cube_side_point(unsigned int sidenum, const Point & interior_point);
      39             : 
      40             : std::array<unsigned int, 4> oriented_prism_nodes(const Elem & elem,
      41             :                                                  unsigned int face_num);
      42             : 
      43             : std::array<unsigned int, 3> oriented_tet_nodes(const Elem & elem,
      44             :                                                unsigned int face_num);
      45             : 
      46             : void orient_triangle(const Elem & elem,
      47             :                      unsigned int * face_vertex);
      48             : 
      49             : template <FEFamily T>
      50             : Real fe_hierarchic_3D_shape(const Elem * elem,
      51             :                             const Order order,
      52             :                             const unsigned int i,
      53             :                             const Point & p,
      54             :                             const bool add_p_level);
      55             : 
      56             : template <FEFamily T>
      57             : Real fe_hierarchic_3D_shape_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             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
      65             : 
      66             : template <FEFamily T>
      67             : Real fe_hierarchic_3D_shape_second_deriv(const Elem * elem,
      68             :                                          const Order order,
      69             :                                          const unsigned int i,
      70             :                                          const unsigned int j,
      71             :                                          const Point & p,
      72             :                                          const bool add_p_level);
      73             : 
      74             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
      75             : 
      76             : #if LIBMESH_DIM > 2
      77   593899536 : Point get_min_point(const Elem * elem,
      78             :                     unsigned int a,
      79             :                     unsigned int b,
      80             :                     unsigned int c,
      81             :                     unsigned int d)
      82             : {
      83             :   return std::min(std::min(elem->point(a),elem->point(b)),
      84   644116908 :                   std::min(elem->point(c),elem->point(d)));
      85             : }
      86             : 
      87             : // Remap non-face-nodes based on point ordering
      88             : template <unsigned int N_nodes>
      89    88992834 : unsigned int remap_node(unsigned int n,
      90             :                         const Elem & elem,
      91             :                         unsigned int nodebegin)
      92             : {
      93             :   std::array<const Point *, N_nodes> points;
      94             : 
      95   444964170 :   for (auto i : IntRange<unsigned int>(0, N_nodes))
      96   385561672 :     points[i] = &elem.point(nodebegin+i);
      97             : 
      98     7397584 :   std::sort(points.begin(), points.end(),
      99    41487311 :             [](const Point * a, const Point * b)
     100   457578133 :             { return *a < *b; });
     101             : 
     102    88992834 :   const Point * pn = points[n-nodebegin];
     103             : 
     104   233527284 :   for (auto i : IntRange<unsigned int>(nodebegin, nodebegin+N_nodes))
     105   252937514 :     if (pn == &elem.point(i))
     106     7397584 :       return i;
     107             : 
     108           0 :   libmesh_assert(false);
     109           0 :   return libMesh::invalid_uint;
     110             : }
     111             : 
     112             : 
     113    88992834 : void cube_remap(unsigned int & side_i,
     114             :                 const Elem & side,
     115             :                 unsigned int totalorder,
     116             :                 Point & sidep)
     117             : {
     118             :   // "vertex" nodes are now decoupled from vertices, so we have
     119             :   // to order them consistently otherwise
     120    88992834 :   if (side_i < 4)
     121    17967096 :     side_i = remap_node<4>(side_i, side, 0);
     122             : 
     123             :   // And "edge" nodes are decoupled from edges, so we have to
     124             :   // reorder them too!
     125    71025738 :   else if (side_i < 4u*totalorder)
     126             :     {
     127    42757920 :       unsigned int side_node = (side_i - 4)/(totalorder-1)+4;
     128    42757920 :       side_node = remap_node<4>(side_node, side, 4);
     129    49867040 :       side_i = ((side_i - 4) % (totalorder - 1)) // old local edge_i
     130    42757920 :         + 4 + (side_node-4)*(totalorder-1);
     131             :     }
     132             : 
     133             :   // Interior dofs in 2D don't care about where xi/eta point in
     134             :   // physical space, but here we need them to match from both
     135             :   // sides of a face!
     136             :   else
     137             :     {
     138    28267818 :       unsigned int min_side_node = remap_node<4>(0, side, 0);
     139             : 
     140             :       // Rotating the least node of the side to the origin leaves the
     141             :       // reflection about the diagonal through it, which is settled by
     142             :       // which of that node's two neighbors is the lesser.
     143    30618362 :       const bool flip = (side.point((min_side_node+3)%4) <
     144    28267818 :                          side.point((min_side_node+1)%4));
     145             : 
     146    28267818 :       switch (min_side_node) {
     147     3752036 :       case 0:
     148     3752036 :         if (flip)
     149      157319 :           std::swap(sidep(0), sidep(1));
     150      312044 :         break;
     151     6531006 :       case 1:
     152     6531006 :         sidep(0) = -sidep(0);
     153     6531006 :         if (!flip)
     154      250609 :           std::swap(sidep(0), sidep(1));
     155      543947 :         break;
     156     7038408 :       case 2:
     157     7038408 :         sidep(0) = -sidep(0);
     158     7038408 :         sidep(1) = -sidep(1);
     159     7038408 :         if (flip)
     160      197284 :           std::swap(sidep(0), sidep(1));
     161      585520 :         break;
     162    10946368 :       case 3:
     163    10946368 :         sidep(1) = -sidep(1);
     164    10946368 :         if (!flip)
     165      387266 :           std::swap(sidep(0), sidep(1));
     166      909033 :         break;
     167           0 :       default:
     168           0 :         libmesh_error();
     169             :       }
     170             :     }
     171    88992834 : }
     172             : 
     173             : 
     174   903497138 : void cube_indices(const Elem * elem,
     175             :                   const unsigned int totalorder,
     176             :                   const unsigned int i,
     177             :                   Real & xi, Real & eta, Real & zeta,
     178             :                   unsigned int & i0,
     179             :                   unsigned int & i1,
     180             :                   unsigned int & i2)
     181             : {
     182             :   // The only way to make any sense of this
     183             :   // is to look at the mgflo/mg2/mgf documentation
     184             :   // and make the cut-out cube!
     185             :   // Example i0 and i1 values for totalorder = 3:
     186             :   // FIXME - these examples are incorrect now that we've got truly
     187             :   // hierarchic basis functions
     188             :   //     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
     189             :   //     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
     190             :   // 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};
     191             :   // 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};
     192             :   // 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};
     193             : 
     194             :   // the number of DoFs per edge appears everywhere:
     195   903497138 :   const unsigned int e = totalorder - 1u;
     196             : 
     197    72937466 :   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
     198             : 
     199   903497138 :   Real xi_saved = xi, eta_saved = eta, zeta_saved = zeta;
     200             : 
     201             :   // Vertices:
     202   903497138 :   if (i == 0)
     203             :     {
     204    17037508 :       i0 = 0;
     205    17037508 :       i1 = 0;
     206    17037508 :       i2 = 0;
     207             :     }
     208   143134066 :   else if (i == 1)
     209             :     {
     210    17035924 :       i0 = 1;
     211    17035924 :       i1 = 0;
     212    17035924 :       i2 = 0;
     213             :     }
     214   140392672 :   else if (i == 2)
     215             :     {
     216    17035924 :       i0 = 1;
     217    17035924 :       i1 = 1;
     218    17035924 :       i2 = 0;
     219             :     }
     220   137651102 :   else if (i == 3)
     221             :     {
     222    17037508 :       i0 = 0;
     223    17037508 :       i1 = 1;
     224    17037508 :       i2 = 0;
     225             :     }
     226   134910060 :   else if (i == 4)
     227             :     {
     228    17039268 :       i0 = 0;
     229    17039268 :       i1 = 0;
     230    17039268 :       i2 = 1;
     231             :     }
     232   132168138 :   else if (i == 5)
     233             :     {
     234    17037684 :       i0 = 1;
     235    17037684 :       i1 = 0;
     236    17037684 :       i2 = 1;
     237             :     }
     238   129425688 :   else if (i == 6)
     239             :     {
     240    17037684 :       i0 = 1;
     241    17037684 :       i1 = 1;
     242    17037684 :       i2 = 1;
     243             :     }
     244   126683062 :   else if (i == 7)
     245             :     {
     246    17039268 :       i0 = 0;
     247    17039268 :       i1 = 1;
     248    17039268 :       i2 = 1;
     249             :     }
     250             :   // Edge 0
     251   767196370 :   else if (i < 8 + e)
     252             :     {
     253    25610792 :       i0 = i - 6;
     254    25610792 :       i1 = 0;
     255    25610792 :       i2 = 0;
     256    25610792 :       if (elem->positive_edge_orientation(0))
     257      384750 :         xi = -xi_saved;
     258             :     }
     259             :   // Edge 1
     260   741585578 :   else if (i < 8 + 2*e)
     261             :     {
     262    25608236 :       i0 = 1;
     263    25608236 :       i1 = i - e - 6;
     264    25608236 :       i2 = 0;
     265    25608236 :       if (elem->positive_edge_orientation(1))
     266    17612648 :         eta = -eta_saved;
     267             :     }
     268             :   // Edge 2
     269   715977342 :   else if (i < 8 + 3*e)
     270             :     {
     271    25610792 :       i0 = i - 2*e - 6;
     272    25610792 :       i1 = 1;
     273    25610792 :       i2 = 0;
     274    25610792 :       if (!elem->positive_edge_orientation(2))
     275      386170 :         xi = -xi_saved;
     276             :     }
     277             :   // Edge 3
     278   690366550 :   else if (i < 8 + 4*e)
     279             :     {
     280    25613348 :       i0 = 0;
     281    25613348 :       i1 = i - 3*e - 6;
     282    25613348 :       i2 = 0;
     283    25613348 :       if (elem->positive_edge_orientation(3))
     284    17607820 :         eta = -eta_saved;
     285             :     }
     286             :   // Edge 4
     287   664753202 :   else if (i < 8 + 5*e)
     288             :     {
     289    25616188 :       i0 = 0;
     290    25616188 :       i1 = 0;
     291    25616188 :       i2 = i - 4*e - 6;
     292    25616188 :       if (elem->positive_edge_orientation(4))
     293    17639996 :         zeta = -zeta_saved;
     294             :     }
     295             :   // Edge 5
     296   639137014 :   else if (i < 8 + 6*e)
     297             :     {
     298    25611076 :       i0 = 1;
     299    25611076 :       i1 = 0;
     300    25611076 :       i2 = i - 5*e - 6;
     301    25611076 :       if (elem->positive_edge_orientation(5))
     302    17649936 :         zeta = -zeta_saved;
     303             :     }
     304             :   // Edge 6
     305   613525938 :   else if (i < 8 + 7*e)
     306             :     {
     307    25611076 :       i0 = 1;
     308    25611076 :       i1 = 1;
     309    25611076 :       i2 = i - 6*e - 6;
     310    25611076 :       if (elem->positive_edge_orientation(6))
     311    17659876 :         zeta = -zeta_saved;
     312             :     }
     313             :   // Edge 7
     314   587914862 :   else if (i < 8 + 8*e)
     315             :     {
     316    25616188 :       i0 = 0;
     317    25616188 :       i1 = 1;
     318    25616188 :       i2 = i - 7*e - 6;
     319    25616188 :       if (elem->positive_edge_orientation(7))
     320    17649936 :         zeta = -zeta_saved;
     321             :     }
     322             :   // Edge 8
     323   562298674 :   else if (i < 8 + 9*e)
     324             :     {
     325    25616472 :       i0 = i - 8*e - 6;
     326    25616472 :       i1 = 0;
     327    25616472 :       i2 = 1;
     328    25616472 :       if (elem->positive_edge_orientation(8))
     329      394406 :         xi = -xi_saved;
     330             :     }
     331             :   // Edge 9
     332   536682202 :   else if (i < 8 + 10*e)
     333             :     {
     334    25613916 :       i0 = 1;
     335    25613916 :       i1 = i - 9*e - 6;
     336    25613916 :       i2 = 1;
     337    25613916 :       if (elem->positive_edge_orientation(9))
     338    17618612 :         eta = -eta_saved;
     339             :     }
     340             :   // Edge 10
     341   511068286 :   else if (i < 8 + 11*e)
     342             :     {
     343    25616472 :       i0 = i - 10*e - 6;
     344    25616472 :       i1 = 1;
     345    25616472 :       i2 = 1;
     346    25616472 :       if (!elem->positive_edge_orientation(10))
     347      395826 :         xi = -xi_saved;
     348             :     }
     349             :   // Edge 11
     350   485451814 :   else if (i < 8 + 12*e)
     351             :     {
     352    25619028 :       i0 = 0;
     353    25619028 :       i1 = i - 11*e - 6;
     354    25619028 :       i2 = 1;
     355    25619028 :       if (elem->positive_edge_orientation(11))
     356    17613784 :         eta = -eta_saved;
     357             :     }
     358             :   // Face 0
     359   459832786 :   else if (i < 8 + 12*e + e*e)
     360             :     {
     361    54833114 :       unsigned int basisnum = i - 8 - 12*e;
     362    54833114 :       i0 = square_number_row[basisnum] + 2;
     363    54833114 :       i1 = square_number_column[basisnum] + 2;
     364    54833114 :       i2 = 0;
     365    54833114 :       const Point min_point = get_min_point(elem, 1, 2, 0, 3);
     366             : 
     367     8864396 :       if (elem->point(0) == min_point)
     368    14146722 :         if (elem->positive_face_orientation(0))
     369             :           {
     370             :             // Case 1
     371      205634 :             xi  = xi_saved;
     372      205634 :             eta = eta_saved;
     373             :           }
     374             :         else
     375             :           {
     376             :             // Case 2
     377    13941088 :             xi  = eta_saved;
     378    13941088 :             eta = xi_saved;
     379             :           }
     380             : 
     381     3387480 :       else if (elem->point(3) == min_point)
     382    39661204 :         if (elem->positive_face_orientation(0))
     383             :           {
     384             :             // Case 3
     385      191174 :             xi  = -eta_saved;
     386      191174 :             eta = xi_saved;
     387             :           }
     388             :         else
     389             :           {
     390             :             // Case 4
     391    39470030 :             xi  = xi_saved;
     392    39470030 :             eta = -eta_saved;
     393             :           }
     394             : 
     395       83424 :       else if (elem->point(2) == min_point)
     396      316886 :         if (elem->positive_face_orientation(0))
     397             :           {
     398             :             // Case 5
     399      189246 :             xi  = -xi_saved;
     400      189246 :             eta = -eta_saved;
     401             :           }
     402             :         else
     403             :           {
     404             :             // Case 6
     405      127640 :             xi  = -eta_saved;
     406      127640 :             eta = -xi_saved;
     407             :           }
     408             : 
     409       57780 :       else if (elem->point(1) == min_point)
     410             :         {
     411      708302 :           if (elem->positive_face_orientation(0))
     412             :             {
     413             :               // Case 7
     414      277844 :               xi  = eta_saved;
     415      277844 :               eta = -xi_saved;
     416             :             }
     417             :           else
     418             :             {
     419             :               // Case 8
     420      430458 :               xi  = -xi_saved;
     421      430458 :               eta = eta_saved;
     422             :             }
     423             :         }
     424             :     }
     425             :   // Face 1
     426   404999672 :   else if (i < 8 + 12*e + 2*e*e)
     427             :     {
     428    54842754 :       unsigned int basisnum = i - 8 - 12*e - e*e;
     429    54842754 :       i0 = square_number_row[basisnum] + 2;
     430    54842754 :       i1 = 0;
     431    54842754 :       i2 = square_number_column[basisnum] + 2;
     432    54842754 :       const Point min_point = get_min_point(elem, 0, 1, 5, 4);
     433             : 
     434     8869216 :       if (elem->point(0) == min_point)
     435    14290660 :         if (!elem->positive_face_orientation(1))
     436             :           {
     437             :             // Case 1
     438      352464 :             xi   = xi_saved;
     439      352464 :             zeta = zeta_saved;
     440             :           }
     441             :         else
     442             :           {
     443             :             // Case 2
     444    13938196 :             xi   = zeta_saved;
     445    13938196 :             zeta = xi_saved;
     446             :           }
     447             : 
     448     3378096 :       else if (elem->point(1) == min_point)
     449      483960 :         if (!elem->positive_face_orientation(1))
     450             :           {
     451             :             // Case 3
     452      212864 :             xi   = zeta_saved;
     453      212864 :             zeta = -xi_saved;
     454             :           }
     455             :         else
     456             :           {
     457             :             // Case 4
     458      271096 :             xi   = -xi_saved;
     459      271096 :             zeta = zeta_saved;
     460             :           }
     461             : 
     462     3337766 :       else if (elem->point(5) == min_point)
     463      555206 :         if (!elem->positive_face_orientation(1))
     464             :           {
     465             :             // Case 5
     466      420818 :             xi   = -xi_saved;
     467      420818 :             zeta = -zeta_saved;
     468             :           }
     469             :         else
     470             :           {
     471             :             // Case 6
     472      134388 :             xi   = -zeta_saved;
     473      134388 :             zeta = -xi_saved;
     474             :           }
     475             : 
     476     3293226 :       else if (elem->point(4) == min_point)
     477             :         {
     478    39512928 :           if (!elem->positive_face_orientation(1))
     479             :             {
     480             :               // Case 7
     481    39322718 :               xi   = -zeta_saved;
     482    39322718 :               zeta = xi_saved;
     483             :             }
     484             :           else
     485             :             {
     486             :               // Case 8
     487      190210 :               xi   = xi_saved;
     488      190210 :               zeta = -zeta_saved;
     489             :             }
     490             :         }
     491             :     }
     492             :   // Face 2
     493   350156918 :   else if (i < 8 + 12*e + 3*e*e)
     494             :     {
     495    54834078 :       unsigned int basisnum = i - 8 - 12*e - 2*e*e;
     496    54834078 :       i0 = 1;
     497    54834078 :       i1 = square_number_row[basisnum] + 2;
     498    54834078 :       i2 = square_number_column[basisnum] + 2;
     499    54834078 :       const Point min_point = get_min_point(elem, 1, 2, 6, 5);
     500             : 
     501     8873072 :       if (elem->point(1) == min_point)
     502    14352748 :         if (!elem->positive_face_orientation(2))
     503             :           {
     504             :             // Case 1
     505      487244 :             eta  = eta_saved;
     506      487244 :             zeta = zeta_saved;
     507             :           }
     508             :         else
     509             :           {
     510             :             // Case 2
     511    13865504 :             eta  = zeta_saved;
     512    13865504 :             zeta = eta_saved;
     513             :           }
     514             : 
     515     3377260 :       else if (elem->point(2) == min_point)
     516      379456 :         if (!elem->positive_face_orientation(2))
     517             :           {
     518             :             // Case 3
     519      110288 :             eta  = zeta_saved;
     520      110288 :             zeta = -eta_saved;
     521             :           }
     522             :         else
     523             :           {
     524             :             // Case 4
     525      269168 :             eta  = -eta_saved;
     526      269168 :             zeta = zeta_saved;
     527             :           }
     528             : 
     529     3344514 :       else if (elem->point(6) == min_point)
     530    39616950 :         if (!elem->positive_face_orientation(2))
     531             :           {
     532             :             // Case 5
     533      280254 :             eta  = -eta_saved;
     534      280254 :             zeta = -zeta_saved;
     535             :           }
     536             :         else
     537             :           {
     538             :             // Case 6
     539    39336696 :             eta  = -zeta_saved;
     540    39336696 :             zeta = -eta_saved;
     541             :           }
     542             : 
     543       41294 :       else if (elem->point(5) == min_point)
     544             :         {
     545      484924 :           if (!elem->positive_face_orientation(2))
     546             :             {
     547             :               // Case 7
     548      207562 :               eta  = -zeta_saved;
     549      207562 :               zeta = eta_saved;
     550             :             }
     551             :           else
     552             :             {
     553             :               // Case 8
     554      277362 :               eta   = eta_saved;
     555      277362 :               zeta = -zeta_saved;
     556             :             }
     557             :         }
     558             :     }
     559             :   // Face 3
     560   295322840 :   else if (i < 8 + 12*e + 4*e*e)
     561             :     {
     562    54842754 :       unsigned int basisnum = i - 8 - 12*e - 3*e*e;
     563    54842754 :       i0 = square_number_row[basisnum] + 2;
     564    54842754 :       i1 = 1;
     565    54842754 :       i2 = square_number_column[basisnum] + 2;
     566    54842754 :       const Point min_point = get_min_point(elem, 2, 3, 7, 6);
     567             : 
     568     8871144 :       if (elem->point(3) == min_point)
     569    14280056 :         if (elem->positive_face_orientation(3))
     570             :           {
     571             :             // Case 1
     572      352464 :             xi   = xi_saved;
     573      352464 :             zeta = zeta_saved;
     574             :           }
     575             :         else
     576             :           {
     577             :             // Case 2
     578    13927592 :             xi   = zeta_saved;
     579    13927592 :             zeta = xi_saved;
     580             :           }
     581             : 
     582     3381470 :       else if (elem->point(7) == min_point)
     583    39518712 :         if (elem->positive_face_orientation(3))
     584             :           {
     585             :             // Case 3
     586    39315970 :             xi   = -zeta_saved;
     587    39315970 :             zeta = xi_saved;
     588             :           }
     589             :         else
     590             :           {
     591             :             // Case 4
     592      202742 :             xi   = xi_saved;
     593      202742 :             zeta = -zeta_saved;
     594             :           }
     595             : 
     596       88726 :       else if (elem->point(6) == min_point)
     597      583162 :         if (elem->positive_face_orientation(3))
     598             :           {
     599             :             // Case 5
     600      448774 :             xi   = -xi_saved;
     601      448774 :             zeta = -zeta_saved;
     602             :           }
     603             :         else
     604             :           {
     605             :             // Case 6
     606      134388 :             xi   = -zeta_saved;
     607      134388 :             zeta = -xi_saved;
     608             :           }
     609             : 
     610       38402 :       else if (elem->point(2) == min_point)
     611             :         {
     612      460824 :           if (elem->positive_face_orientation(3))
     613             :             {
     614             :               // Case 7
     615      197440 :               xi   = zeta_saved;
     616      197440 :               zeta = -xi_saved;
     617             :             }
     618             :           else
     619             :             {
     620             :               // Case 8
     621      263384 :               xi   = -xi_saved;
     622      263384 :               zeta = zeta_saved;
     623             :             }
     624             :         }
     625             :     }
     626             :   // Face 4
     627   240480086 :   else if (i < 8 + 12*e + 5*e*e)
     628             :     {
     629    54851430 :       unsigned int basisnum = i - 8 - 12*e - 4*e*e;
     630    54851430 :       i0 = 0;
     631    54851430 :       i1 = square_number_row[basisnum] + 2;
     632    54851430 :       i2 = square_number_column[basisnum] + 2;
     633    54851430 :       const Point min_point = get_min_point(elem, 3, 0, 4, 7);
     634             : 
     635     8867288 :       if (elem->point(0) == min_point)
     636    14394200 :         if (elem->positive_face_orientation(4))
     637             :           {
     638             :             // Case 1
     639      518092 :             eta  = eta_saved;
     640      518092 :             zeta = zeta_saved;
     641             :           }
     642             :         else
     643             :           {
     644             :             // Case 2
     645    13876108 :             eta  = zeta_saved;
     646    13876108 :             zeta = eta_saved;
     647             :           }
     648             : 
     649     3367620 :       else if (elem->point(4) == min_point)
     650      477212 :         if (elem->positive_face_orientation(4))
     651             :           {
     652             :             // Case 3
     653      202742 :             eta  = -zeta_saved;
     654      202742 :             zeta = eta_saved;
     655             :           }
     656             :         else
     657             :           {
     658             :             // Case 4
     659      274470 :             eta  = eta_saved;
     660      274470 :             zeta = -zeta_saved;
     661             :           }
     662             : 
     663     3328736 :       else if (elem->point(7) == min_point)
     664    39590922 :         if (elem->positive_face_orientation(4))
     665             :           {
     666             :             // Case 5
     667      283146 :             eta  = -eta_saved;
     668      283146 :             zeta = -zeta_saved;
     669             :           }
     670             :         else
     671             :           {
     672             :             // Case 6
     673    39307776 :             eta  = -zeta_saved;
     674    39307776 :             zeta = -eta_saved;
     675             :           }
     676             : 
     677       31300 :       else if (elem->point(3) == min_point)
     678             :         {
     679      389096 :           if (elem->positive_face_orientation(4))
     680             :             {
     681             :               // Case 7
     682      118000 :               eta   = zeta_saved;
     683      118000 :               zeta = -eta_saved;
     684             :             }
     685             :           else
     686             :             {
     687             :               // Case 8
     688      271096 :               eta  = -eta_saved;
     689      271096 :               zeta = zeta_saved;
     690             :             }
     691             :         }
     692             :     }
     693             :   // Face 5
     694   185628656 :   else if (i < 8 + 12*e + 6*e*e)
     695             :     {
     696    54852394 :       unsigned int basisnum = i - 8 - 12*e - 5*e*e;
     697    54852394 :       i0 = square_number_row[basisnum] + 2;
     698    54852394 :       i1 = square_number_column[basisnum] + 2;
     699    54852394 :       i2 = 1;
     700    54852394 :       const Point min_point = get_min_point(elem, 4, 5, 6, 7);
     701             : 
     702     8875964 :       if (elem->point(4) == min_point)
     703    14135154 :         if (!elem->positive_face_orientation(5))
     704             :           {
     705             :             // Case 1
     706      198886 :             xi  = xi_saved;
     707      198886 :             eta = eta_saved;
     708             :           }
     709             :         else
     710             :           {
     711             :             // Case 2
     712    13936268 :             xi  = eta_saved;
     713    13936268 :             eta = xi_saved;
     714             :           }
     715             : 
     716     3396156 :       else if (elem->point(5) == min_point)
     717      718906 :         if (!elem->positive_face_orientation(5))
     718             :           {
     719             :             // Case 3
     720      297124 :             xi  = eta_saved;
     721      297124 :             eta = -xi_saved;
     722             :           }
     723             :         else
     724             :           {
     725             :             // Case 4
     726      421782 :             xi  = -xi_saved;
     727      421782 :             eta = eta_saved;
     728             :           }
     729             : 
     730     3335002 :       else if (elem->point(6) == min_point)
     731      339058 :         if (!elem->positive_face_orientation(5))
     732             :           {
     733             :             // Case 5
     734      209490 :             xi  = -xi_saved;
     735      209490 :             eta = -eta_saved;
     736             :           }
     737             :         else
     738             :           {
     739             :             // Case 6
     740      129568 :             xi  = -eta_saved;
     741      129568 :             eta = -xi_saved;
     742             :           }
     743             : 
     744     3305984 :       else if (elem->point(7) == min_point)
     745             :         {
     746    39659276 :           if (!elem->positive_face_orientation(5))
     747             :             {
     748             :               // Case 7
     749      201778 :               xi  = -eta_saved;
     750      201778 :               eta = xi_saved;
     751             :             }
     752             :           else
     753             :             {
     754             :               // Case 8
     755    39457498 :               xi  = xi_saved;
     756    39457498 :               eta = -eta_saved;
     757             :             }
     758             :         }
     759             :     }
     760             : 
     761             :   // Internal DoFs
     762             :   else
     763             :     {
     764   130776262 :       unsigned int basisnum = i - 8 - 12*e - 6*e*e;
     765   130776262 :       i0 = cube_number_column[basisnum] + 2;
     766   130776262 :       i1 = cube_number_row[basisnum] + 2;
     767   130776262 :       i2 = cube_number_page[basisnum] + 2;
     768             :     }
     769   903497138 : }
     770             : 
     771             : 
     772             : // Reorder the barycentric coordinates of a triangular face of a prism, whose vertices begin at
     773             : // \p first_vertex, so that they follow the order of the face's vertices. The interior basis of a
     774             : // triangle is not symmetric in its barycentric coordinates, so a face shared between two elements
     775             : // needs them ordered the same way from both sides.
     776    51459128 : void orient_triangle_coords(const Elem & elem,
     777             :                             const unsigned int first_vertex,
     778             :                             const Point & xi_eta_saved,
     779             :                             Point & xi_eta)
     780             : {
     781    51459128 :   unsigned int face_vertex[3] = {first_vertex, first_vertex+1, first_vertex+2};
     782    51459128 :   orient_triangle(elem, face_vertex);
     783             : 
     784    51459128 :   const Real barycentric[3] = {1 - xi_eta_saved(0) - xi_eta_saved(1),
     785     9174840 :                                xi_eta_saved(0),
     786    51459128 :                                xi_eta_saved(1)};
     787             : 
     788    51459128 :   xi_eta(0) = barycentric[face_vertex[1] - first_vertex];
     789    51459128 :   xi_eta(1) = barycentric[face_vertex[2] - first_vertex];
     790    51459128 : }
     791             : 
     792             : 
     793   855156268 : void prism_indices(const Elem * elem,
     794             :                    const unsigned int totalorder,
     795             :                    const unsigned int i,
     796             :                    Point & xi_eta, Real & zeta,
     797             :                    unsigned int & i01,
     798             :                    unsigned int & i2)
     799             : {
     800             :   // the number of DoFs per edge appears everywhere:
     801   855156268 :   const unsigned int e = totalorder - 1u;
     802             : 
     803    76216482 :   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+2u)/2u);
     804             : 
     805   855156268 :   Point xi_eta_saved = xi_eta;
     806   855156268 :   Real zeta_saved = zeta;
     807             : 
     808             :   // Vertices:
     809   855156268 :   if (i == 0)
     810             :     {
     811    22576908 :       i01 = 0;
     812    22576908 :       i2 = 0;
     813             :     }
     814   148409684 :   else if (i == 1)
     815             :     {
     816    22577454 :       i01 = 1;
     817    22577454 :       i2 = 0;
     818             :     }
     819   144386508 :   else if (i == 2)
     820             :     {
     821    22575738 :       i01 = 2;
     822    22575738 :       i2 = 0;
     823             :     }
     824   140363748 :   else if (i == 3)
     825             :     {
     826    22577068 :       i01 = 0;
     827    22577068 :       i2 = 1;
     828             :     }
     829   136340468 :   else if (i == 4)
     830             :     {
     831    22577614 :       i01 = 1;
     832    22577614 :       i2 = 1;
     833             :     }
     834   132317292 :   else if (i == 5)
     835             :     {
     836    22575898 :       i01 = 2;
     837    22575898 :       i2 = 1;
     838             :     }
     839             :   // Edges 0,1,2 (vertices 6,7,8)
     840   719695588 :   else if (i < 6 + 3*e)
     841             :     {
     842             :       // The TRI code will handle any flips here
     843   110421228 :       i01 = i - 3;
     844   110421228 :       i2 = 0;
     845             :     }
     846             :   // Edge 3,4,5 (vertices 9,10,11)
     847   609274360 :   else if (i < 6 + 6*e)
     848             :     {
     849   110493276 :       i01 = (i - 6 - 3*e)/e; // which tri DoF are we?
     850   110493276 :       i2 = (i - 6 - 3*e)%e+2; // edge DoF? +2 to skip endpoints
     851             :       // EDGE evaluations don't flip, so handle that here
     852   110493276 :       if (elem->positive_edge_orientation(i01+3))
     853   110238196 :         zeta = -zeta;
     854             :     }
     855             :   // Edge 6,7,8 (vertices 12,13,14)
     856   498781084 :   else if (i < 6 + 9*e)
     857             :     {
     858             :       // The TRI code will handle any flips here
     859   110422476 :       i01 = i - 3 - 6*e;
     860   110422476 :       i2 = 1;
     861             :     }
     862             :   // Face 1, node 15 (*before* 0, via node 18 on prism20)
     863   388358608 :   else if (i < 6 + 9*e + e*e)
     864             :     {
     865    88288182 :       unsigned int basisnum = i - 6 - 9*e;
     866             : 
     867             :       // How wide is the stretch from one side to the other of the
     868             :       // line in the xi-eta plane parallel to this face?
     869    88288182 :       const Real xe_scale = 1 - xi_eta_saved(1);
     870             : 
     871             :       // What percentage of the way along that stretch are we?
     872    88288182 :       const Real xe_fraction = (xe_scale==0) ?
     873    88220092 :         0 : xi_eta_saved(0)/xe_scale;
     874             : 
     875             :       // indexes in edge numbering
     876    88288182 :       unsigned int s0 = square_number_row[basisnum] + 2;
     877    88288182 :       unsigned int s1 = square_number_column[basisnum] + 2;
     878    88288182 :       const Point min_point = get_min_point(elem, 0, 1, 3, 4);
     879             : 
     880    15740216 :       if (elem->point(0) == min_point)
     881             :         {
     882      101656 :           if (!elem->positive_face_orientation(1))
     883             :             {
     884             :               // Case 1: no flips needed
     885           0 :               i01 = s0+1; // edge to triangle side 0 numbering
     886           0 :               i2 = s1;
     887             :             }
     888             :           else
     889             :             {
     890             :               // Case 2: flip about 0-4 diagonal
     891      101656 :               i01 = s1+1;
     892      101656 :               i2 = s0;
     893             :             }
     894             :         }
     895     7861766 :       else if (elem->point(3) == min_point)
     896             :         {
     897    42489708 :           if (!elem->positive_face_orientation(1))
     898             :             {
     899             :               // Case 3: 0->3->4->1->0 rotation
     900    42489708 :               i01 = s1+1;
     901    42489708 :               i2 = s0;
     902    42489708 :               zeta = -zeta_saved;
     903             :             }
     904             :           else
     905             :             {
     906             :               // Case 4: flip about 9-10 midline
     907           0 :               i01 = s0+1;
     908           0 :               i2 = s1;
     909           0 :               zeta = -zeta_saved;
     910             :             }
     911             :         }
     912     4704244 :       else if (elem->point(1) == min_point)
     913             :         {
     914       72362 :           if (!elem->positive_face_orientation(1))
     915             :             {
     916             :               // Case 5: 0->1->4->3->0 rotation
     917       72362 :               i01 = s1+1;
     918       72362 :               i2 = s0;
     919       72362 :               xi_eta(0) = (1-xe_fraction)*xe_scale;
     920             :             }
     921             :           else
     922             :             {
     923             :               // Case 6: flip about 6-12 midline
     924           0 :               i01 = s0+1;
     925           0 :               i2 = s1;
     926           0 :               xi_eta(0) = (1-xe_fraction)*xe_scale;
     927             :             }
     928             :         }
     929     4697842 :       else if (elem->point(4) == min_point)
     930             :         {
     931    45624456 :           if (!elem->positive_face_orientation(1))
     932             :             {
     933             :               // Case 7: 180 degree rotation
     934           0 :               i01 = s0+1;
     935           0 :               i2 = s1;
     936           0 :               xi_eta(0) = (1-xe_fraction)*xe_scale;
     937           0 :               zeta = -zeta_saved;
     938             :             }
     939             :           else
     940             :             {
     941             :               // Case 8: flip about 1-3 diagonal
     942    45624456 :               i01 = s1+1;
     943    45624456 :               i2 = s0;
     944    45624456 :               xi_eta(0) = (1-xe_fraction)*xe_scale;
     945    45624456 :               zeta = -zeta_saved;
     946             :             }
     947             :         }
     948             :     }
     949             :   // Face 2, node 16
     950   300070426 :   else if (i < 6 + 9*e + 2*e*e)
     951             :     {
     952    88279452 :       unsigned int basisnum = i - 6 - 9*e - e*e;
     953             : 
     954             :       // How wide is the stretch from one side to the other of the
     955             :       // line in the xi-eta plane parallel to this face?
     956    88279452 :       const Real xe_scale = xi_eta_saved(0) + xi_eta_saved(1);
     957             : 
     958             :       // What percentage of the way along that stretch are we?
     959    88279452 :       const Real xe_fraction = (xe_scale==0) ?
     960     7865548 :         0 : xi_eta_saved(0)/xe_scale;
     961             : 
     962             :       // indexes in edge numbering
     963    88279452 :       unsigned int s0 = square_number_row[basisnum] + 2;
     964    88279452 :       unsigned int s1 = square_number_column[basisnum] + 2;
     965    88279452 :       const Point min_point = get_min_point(elem, 1, 2, 4, 5);
     966             : 
     967    15736336 :       if (elem->point(1) == min_point)
     968             :         {
     969       39382 :           if (!elem->positive_face_orientation(2))
     970             :             {
     971             :               // Case 1: no flips needed
     972           0 :               i01 = s0+1+e; // edge to triangle side 1 numbering
     973           0 :               i2 = s1;
     974             :             }
     975             :           else
     976             :             {
     977             :               // Case 2: flip about 1-5 diagonal
     978       39382 :               i01 = s1+1+e;
     979       39382 :               i2 = s0;
     980             :             }
     981             :         }
     982     7865452 :       else if (elem->point(4) == min_point)
     983             :         {
     984    55255072 :           if (!elem->positive_face_orientation(2))
     985             :             {
     986             :               // Case 3: 1->4->5->2->1 rotation
     987    55255072 :               i01 = s1+1+e;
     988    55255072 :               i2 = s0;
     989    55255072 :               zeta = -zeta_saved;
     990             :             }
     991             :           else
     992             :             {
     993             :               // Case 4: flip about 10-11 midline
     994           0 :               i01 = s0+1+e;
     995           0 :               i2 = s1;
     996           0 :               zeta = -zeta_saved;
     997             :             }
     998             :         }
     999       15326 :       else if (elem->point(2) == min_point)
    1000             :         {
    1001      135606 :           if (!elem->positive_face_orientation(2))
    1002             :             {
    1003             :               // Case 5: 1->2->5->4->1 rotation
    1004      135606 :               i01 = s1+1+e;
    1005      135606 :               i2 = s0;
    1006       11640 :               const Real xe = xe_fraction;
    1007      135606 :               xi_eta(1) = xe*xe_scale;
    1008      135606 :               xi_eta(0) = xe_scale - xi_eta(1);
    1009             :             }
    1010             :           else
    1011             :             {
    1012             :               // Case 6: flip about 7-13 midline
    1013           0 :               i01 = s0+1+e;
    1014           0 :               i2 = s1;
    1015           0 :               const Real xe = xe_fraction;
    1016           0 :               xi_eta(1) = xe*xe_scale;
    1017           0 :               xi_eta(0) = xe_scale - xi_eta(1);
    1018             :             }
    1019             :         }
    1020        3686 :       else if (elem->point(5) == min_point)
    1021             :         {
    1022    32849392 :           if (!elem->positive_face_orientation(2))
    1023             :             {
    1024             :               // Case 7: 180 degree rotation
    1025           0 :               i01 = s0+1+e;
    1026           0 :               i2 = s1;
    1027           0 :               zeta = -zeta_saved;
    1028           0 :               const Real xe = xe_fraction;
    1029           0 :               xi_eta(1) = xe*xe_scale;
    1030           0 :               xi_eta(0) = xe_scale - xi_eta(1);
    1031             :             }
    1032             :           else
    1033             :             {
    1034             :               // Case 8: flip about 2-4 diagonal
    1035    32849392 :               i01 = s1+1+e;
    1036    32849392 :               i2 = s0;
    1037    32849392 :               zeta = -zeta_saved;
    1038        3686 :               const Real xe = xe_fraction;
    1039    32849392 :               xi_eta(1) = xe*xe_scale;
    1040    32849392 :               xi_eta(0) = xe_scale - xi_eta(1);
    1041             :             }
    1042             :         }
    1043             :     }
    1044             :   // Face 3, node 17
    1045   211790974 :   else if (i < 6 + 9*e + 3*e*e)
    1046             :     {
    1047    88275378 :       unsigned int basisnum = i - 6 - 9*e - 2*e*e;
    1048             : 
    1049             :       // How wide is the stretch from one side to the other of the
    1050             :       // line in the xi-eta plane parallel to this face?
    1051    88275378 :       const Real xe_scale = 1 - xi_eta_saved(0);
    1052             : 
    1053             :       // What percentage of the way along that stretch are we?
    1054    88275378 :       const Real xe_fraction = (xe_scale==0) ?
    1055    88243938 :         0 : (xe_scale - xi_eta_saved(1))/xe_scale;
    1056             : 
    1057             :       // indexes in edge numbering
    1058    88275378 :       unsigned int s0 = square_number_row[basisnum] + 2;
    1059    88275378 :       unsigned int s1 = square_number_column[basisnum] + 2;
    1060    88275378 :       const Point min_point = get_min_point(elem, 0, 2, 3, 5);
    1061             : 
    1062    15737112 :       if (elem->point(2) == min_point)
    1063             :         {
    1064      114848 :           if (!elem->positive_face_orientation(3))
    1065             :             {
    1066             :               // Case 1: no flips needed
    1067           0 :               i01 = s0+1+2*e; // edge to triangle side 2 numbering
    1068           0 :               i2 = s1;
    1069             :             }
    1070             :           else
    1071             :             {
    1072             :               // Case 2: flip about 2-3 diagonal
    1073      114848 :               i01 = s1+1+2*e;
    1074      114848 :               i2 = s0;
    1075             :             }
    1076             :         }
    1077     7858662 :       else if (elem->point(5) == min_point)
    1078             :         {
    1079    22131366 :           if (!elem->positive_face_orientation(3))
    1080             :             {
    1081             :               // Case 3: 2->5->3->0->2 rotation
    1082    22131366 :               i01 = s1+1+2*e;
    1083    22131366 :               i2 = s0;
    1084    22131366 :               zeta = -zeta_saved;
    1085             :             }
    1086             :           else
    1087             :             {
    1088             :               // Case 4: flip about 11-9 midline
    1089           0 :               i01 = s0+1+2*e;
    1090           0 :               i2 = s1;
    1091           0 :               zeta = -zeta_saved;
    1092             :             }
    1093             :         }
    1094     7852648 :       else if (elem->point(0) == min_point)
    1095             :         {
    1096       57230 :           if (!elem->positive_face_orientation(3))
    1097             :             {
    1098             :               // Case 5: 2->0->3->5->2 rotation
    1099       57230 :               i01 = s1+1+2*e;
    1100       57230 :               i2 = s0;
    1101       57230 :               const Real xe = (1-xe_fraction);
    1102       57230 :               xi_eta(1) = xe_scale - xe*xe_scale;
    1103             :             }
    1104             :           else
    1105             :             {
    1106             :               // Case 6: flip about 8-14 midline
    1107           0 :               i01 = s0+1+2*e;
    1108           0 :               i2 = s1;
    1109           0 :               const Real xe = (1-xe_fraction);
    1110           0 :               xi_eta(1) = xe_scale - xe*xe_scale;
    1111             :             }
    1112             :         }
    1113     7848186 :       else if (elem->point(3) == min_point)
    1114             :         {
    1115    65971934 :           if (!elem->positive_face_orientation(3))
    1116             :             {
    1117             :               // Case 7: 180 degree rotation
    1118           0 :               i01 = s0+1+2*e;
    1119           0 :               i2 = s1;
    1120           0 :               zeta = -zeta_saved;
    1121           0 :               const Real xe = (1-xe_fraction);
    1122           0 :               xi_eta(1) = xe_scale - xe*xe_scale;
    1123             :             }
    1124             :           else
    1125             :             {
    1126             :               // Case 8: flip about 0-5 diagonal
    1127    65971934 :               i01 = s1+1+2*e;
    1128    65971934 :               i2 = s0;
    1129    65971934 :               zeta = -zeta_saved;
    1130    65971934 :               const Real xe = (1-xe_fraction);
    1131    65971934 :               xi_eta(1) = xe_scale - xe*xe_scale;
    1132             :             }
    1133             :         }
    1134             :     }
    1135             :   // Face 0, node 18 - node order due to hierarchic numbering
    1136   123515596 :   else if (i < 6 + 9*e + 3*e*e + e*(e-1)/2)
    1137             :     {
    1138    25729388 :       i01 = i - 3 - 6*e - 3*e*e;
    1139    25729388 :       i2 = 0;
    1140    25729388 :       orient_triangle_coords(*elem, 0, xi_eta_saved, xi_eta);
    1141             :     }
    1142             :   // Face 4
    1143    97786208 :   else if (i < 6 + 9*e + 3*e*e + e*(e-1))
    1144             :     {
    1145    25729740 :       i01 = i - 3 - 6*e - 3*e*e - e*(e-1)/2;
    1146    25729740 :       i2 = 1;
    1147    25729740 :       orient_triangle_coords(*elem, 3, xi_eta_saved, xi_eta);
    1148             :     }
    1149             :   // Internal DoFs
    1150             :   else
    1151             :     {
    1152             :       // We won't bother with any internal DoF reordering / flipping;
    1153             :       // that's fine unless we ever get to 4D.
    1154    72056468 :       unsigned int basisnum = i - 6 - 9*e - 3*e*e - e*(e-1);
    1155    72056468 :       i01 = prism_number_triangle[basisnum] + 3 + 3*e;
    1156    72056468 :       i2 = prism_number_page[basisnum] + 2;
    1157             :     }
    1158   855156268 : }
    1159             : 
    1160             : #endif // LIBMESH_DIM > 2
    1161             : 
    1162             : } // end anonymous namespace
    1163             : 
    1164             : 
    1165             : 
    1166             : namespace libMesh
    1167             : {
    1168             : 
    1169             : 
    1170   112483229 : LIBMESH_DEFAULT_VECTORIZED_FE(3,HIERARCHIC)
    1171   120723998 : LIBMESH_DEFAULT_VECTORIZED_FE(3,L2_HIERARCHIC)
    1172    97033343 : LIBMESH_DEFAULT_VECTORIZED_FE(3,SIDE_HIERARCHIC)
    1173             : 
    1174             : 
    1175             : template <>
    1176           0 : Real FE<3,HIERARCHIC>::shape(const ElemType,
    1177             :                              const Order,
    1178             :                              const unsigned int,
    1179             :                              const Point &)
    1180             : {
    1181           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1182             :   return 0.;
    1183             : }
    1184             : 
    1185             : 
    1186             : 
    1187             : template <>
    1188           0 : Real FE<3,L2_HIERARCHIC>::shape(const ElemType,
    1189             :                                 const Order,
    1190             :                                 const unsigned int,
    1191             :                                 const Point &)
    1192             : {
    1193           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1194             :   return 0.;
    1195             : }
    1196             : 
    1197             : 
    1198             : 
    1199             : template <>
    1200           0 : Real FE<3,SIDE_HIERARCHIC>::shape(const ElemType,
    1201             :                                   const Order,
    1202             :                                   const unsigned int,
    1203             :                                   const Point &)
    1204             : {
    1205           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1206             :   return 0.;
    1207             : }
    1208             : 
    1209             : 
    1210             : 
    1211             : template <>
    1212  1040935570 : Real FE<3,HIERARCHIC>::shape(const Elem * elem,
    1213             :                              const Order order,
    1214             :                              const unsigned int i,
    1215             :                              const Point & p,
    1216             :                              const bool add_p_level)
    1217             : {
    1218  1040935570 :   return fe_hierarchic_3D_shape<HIERARCHIC>(elem, order, i, p, add_p_level);
    1219             : }
    1220             : 
    1221             : 
    1222             : template <>
    1223           0 : Real FE<3,HIERARCHIC>::shape(const FEType fet,
    1224             :                              const Elem * elem,
    1225             :                              const unsigned int i,
    1226             :                              const Point & p,
    1227             :                              const bool add_p_level)
    1228             : {
    1229           0 :   return fe_hierarchic_3D_shape<HIERARCHIC>(elem, fet.order, i, p, add_p_level);
    1230             : }
    1231             : 
    1232             : 
    1233             : 
    1234             : 
    1235             : template <>
    1236  1412617344 : Real FE<3,L2_HIERARCHIC>::shape(const Elem * elem,
    1237             :                                 const Order order,
    1238             :                                 const unsigned int i,
    1239             :                                 const Point & p,
    1240             :                                 const bool add_p_level)
    1241             : {
    1242  1412617344 :   return fe_hierarchic_3D_shape<L2_HIERARCHIC>(elem, order, i, p, add_p_level);
    1243             : }
    1244             : 
    1245             : 
    1246             : template <>
    1247           0 : Real FE<3,L2_HIERARCHIC>::shape(const FEType fet,
    1248             :                                 const Elem * elem,
    1249             :                                 const unsigned int i,
    1250             :                                 const Point & p,
    1251             :                                 const bool add_p_level)
    1252             : {
    1253           0 :   return fe_hierarchic_3D_shape<L2_HIERARCHIC>(elem, fet.order, i, p, add_p_level);
    1254             : }
    1255             : 
    1256             : 
    1257             : 
    1258             : template <>
    1259  4529357029 : Real FE<3,SIDE_HIERARCHIC>::shape(const Elem * elem,
    1260             :                                   const Order order,
    1261             :                                   const unsigned int i,
    1262             :                                   const Point & p,
    1263             :                                   const bool add_p_level)
    1264             : {
    1265             : #if LIBMESH_DIM == 3
    1266   376761768 :   libmesh_assert(elem);
    1267  4529357029 :   const ElemType type = elem->type();
    1268             : 
    1269  4906118797 :   const Order totalorder = order + add_p_level*elem->p_level();
    1270             : 
    1271  4529357029 :   switch (type)
    1272             :     {
    1273    41575248 :     case HEX27:
    1274             :       {
    1275   500333274 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
    1276    41575248 :         libmesh_assert_less(i, 6*dofs_per_side);
    1277             : 
    1278   500333274 :         const unsigned int sidenum = cube_side(p);
    1279   500333274 :         if (sidenum > 5)
    1280       25920 :           return std::numeric_limits<Real>::quiet_NaN();
    1281             : 
    1282   499903326 :         const unsigned int dof_offset = sidenum * dofs_per_side;
    1283             : 
    1284   499903326 :         if (i < dof_offset) // i is on a previous side
    1285    17119013 :           return 0;
    1286             : 
    1287   293517049 :         if (i >= dof_offset + dofs_per_side) // i is on a later side
    1288    17227987 :           return 0;
    1289             : 
    1290    86646501 :         if (totalorder == 0) // special case since raw HIERARCHIC lacks CONSTANTs
    1291       14264 :           return 1;
    1292             : 
    1293    86478594 :         unsigned int side_i = i - dof_offset;
    1294             : 
    1295    86478594 :         std::unique_ptr<const Elem> side = elem->build_side_ptr(sidenum);
    1296             : 
    1297    86478594 :         Point sidep = cube_side_point(sidenum, p);
    1298             : 
    1299    86478594 :         cube_remap(side_i, *side, totalorder, sidep);
    1300             : 
    1301    86478594 :         return FE<2,HIERARCHIC>::shape(side.get(), order, side_i, sidep, add_p_level);
    1302    72102466 :       }
    1303             : 
    1304   240081920 :     case TET14:
    1305             :       {
    1306  2884736640 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+2u)/2u;
    1307   240081920 :         libmesh_assert_less(i, 4*dofs_per_side);
    1308             : 
    1309  2884736640 :         const Real zeta[4] = { Real(1.) - p(0) - p(1) - p(2), p(0), p(1), p(2) };
    1310             : 
    1311   240081920 :         unsigned int face_num = 0;
    1312  2884736640 :         if (zeta[0] > zeta[3] &&
    1313   992688136 :             zeta[1] > zeta[3] &&
    1314    79217916 :             zeta[2] > zeta[3])
    1315             :           {
    1316    60007536 :             face_num = 0;
    1317             :           }
    1318  2163466560 :         else if (zeta[0] > zeta[2] &&
    1319   750599560 :                  zeta[1] > zeta[2] &&
    1320    60010416 :                  zeta[3] > zeta[2])
    1321             :           {
    1322    60010416 :             face_num = 1;
    1323             :           }
    1324  1442858576 :         else if (zeta[1] > zeta[0] &&
    1325   721207504 :                  zeta[2] > zeta[0] &&
    1326    59987424 :                  zeta[3] > zeta[0])
    1327             :           {
    1328    59987424 :             face_num = 2;
    1329             :           }
    1330             :         else
    1331             :           {
    1332             :             // We'd better not be right between two faces
    1333    60076544 :             libmesh_assert (zeta[0] > zeta[1] &&
    1334             :                             zeta[2] > zeta[1] &&
    1335             :                             zeta[3] > zeta[1]);
    1336    60076544 :             face_num = 3;
    1337             :           }
    1338             : 
    1339  2884736640 :         if (i < face_num * dofs_per_side ||
    1340  1802742588 :             i >= (face_num+1) * dofs_per_side)
    1341   180061440 :           return 0;
    1342             : 
    1343   721184160 :         if (totalorder == 0)
    1344      178112 :           return 1;
    1345             : 
    1346             :         const std::array<unsigned int, 3> face_vertex =
    1347   659202408 :           oriented_tet_nodes(*elem, face_num);
    1348             : 
    1349             :         // We only need a Tri3 to evaluate L2_HIERARCHIC on the affine
    1350             :         // master element
    1351   119684736 :         Tri3 side;
    1352             : 
    1353             :         // We pinky swear not to modify these nodes
    1354    59842368 :         Elem & e = const_cast<Elem &>(*elem);
    1355   719044776 :         side.set_node(0, e.node_ptr(face_vertex[0]));
    1356   659202408 :         side.set_node(1, e.node_ptr(face_vertex[1]));
    1357   659202408 :         side.set_node(2, e.node_ptr(face_vertex[2]));
    1358             : 
    1359   719044776 :         const unsigned int basisnum = i - face_num*dofs_per_side;
    1360             : 
    1361   719044776 :         Point sidep {zeta[face_vertex[1]], zeta[face_vertex[2]]};
    1362             : 
    1363   719044776 :         return FE<2,L2_HIERARCHIC>::shape(&side, totalorder,
    1364    59842368 :                                           basisnum, sidep, false);
    1365             :       }
    1366             : 
    1367    95104600 :     case PRISM20:
    1368             :     case PRISM21:
    1369             :       {
    1370  1144287115 :         const unsigned int dofs_per_quad = (totalorder+1u)*(totalorder+1u);
    1371  1144287115 :         const unsigned int dofs_per_tri = (totalorder+1u)*(totalorder+2u)/2u;
    1372    95104600 :         libmesh_assert_less(i, 3*dofs_per_quad + 2*dofs_per_tri);
    1373             : 
    1374             :         // We only need a Tri3 or Quad4 to evaluate L2_HIERARCHIC on
    1375             :         // the affine master element
    1376   190209200 :         Tri3 tri;
    1377   190209200 :         Quad4 quad;
    1378    95104600 :         Elem * side = &quad;
    1379    95104600 :         unsigned int dofs_on_side = dofs_per_quad;
    1380             : 
    1381             :         // We pinky swear not to modify the nodes we'll point to
    1382    95104600 :         Elem & e = const_cast<Elem &>(*elem);
    1383             : 
    1384    95104600 :         Point sidep;
    1385             : 
    1386             :         // Face number calculation is tricky - the ordering of side
    1387             :         // nodes on Prisms does *not* match the ordering of sides!
    1388             :         // (the mid-triangle side nodes were added "later")
    1389             :         // Here face_num will be the numbering that matches the side
    1390             :         // number, but i_offset will have to consider the nodal
    1391             :         // ordering.
    1392    95104600 :         unsigned int face_num = 0;
    1393    95104600 :         unsigned int i_offset = 0;
    1394             : 
    1395             :         // Triangular coordinates
    1396  1144287115 :         const Real zeta[3] = { Real(1.) - p(0) - p(1), p(0), p(1) };
    1397             : 
    1398             :         // Closeness to midplane
    1399  1144287115 :         const Real zmid = 1 - std::abs(p(2));
    1400             : 
    1401  1144287115 :         if (zeta[1] > zeta[2] && zeta[0] > zeta[2] &&
    1402   377613345 :             zmid > 3*zeta[2]) // face 1, quad
    1403             :           {
    1404    21012280 :             face_num = 1;
    1405    21012280 :             i_offset = 0;
    1406             :           }
    1407   891497900 :         else if (zeta[1] > zeta[0] && zeta[2] > zeta[0] &&
    1408   378143710 :                  zmid > 3*zeta[0]) // face 2, quad
    1409             :           {
    1410    21012280 :             face_num = 2;
    1411    21012280 :             i_offset = dofs_per_quad;
    1412             :           }
    1413   638853620 :         else if (zeta[0] > zeta[1] && zeta[2] > zeta[1] &&
    1414   376661480 :                  zmid > 3*zeta[1]) // face 3, quad
    1415             :           {
    1416    21012280 :             face_num = 3;
    1417   252934150 :             i_offset = 2*dofs_per_quad;
    1418             :           }
    1419   586705960 :         else if (p(2) + 1 < 3*zeta[0] &&
    1420   402016570 :                  p(2) + 1 < 3*zeta[1] &&
    1421   193260030 :                  p(2) + 1 < 3*zeta[2]) // face 0, tri
    1422             :           {
    1423    16097100 :             face_num = 0;
    1424   193260030 :             i_offset = 3*dofs_per_quad;
    1425    16097100 :             dofs_on_side = dofs_per_tri;
    1426    16097100 :             side = &tri;
    1427             :           }
    1428   369348220 :         else if (1 - p(2) < 3*zeta[0] &&
    1429   208630100 :                  1 - p(2) < 3*zeta[1] &&
    1430   192659440 :                  1 - p(2) < 3*zeta[2]) // face 4, tri
    1431             :           {
    1432    15970660 :             face_num = 4;
    1433   192659440 :             i_offset = dofs_per_tri + 3*dofs_per_quad;
    1434    15970660 :             dofs_on_side = dofs_per_tri;
    1435    15970660 :             side = &tri;
    1436             :           }
    1437             :         else
    1438             :           {
    1439           0 :             libmesh_error_msg("Evaluating SIDE_HIERARCHIC right between two Prism faces?");
    1440             :           }
    1441             : 
    1442  1144287115 :         if (i < i_offset ||
    1443   663248625 :             i >= i_offset + dofs_on_side)
    1444    75535040 :           return 0;
    1445             : 
    1446   235450955 :         if (totalorder == 0)
    1447        1400 :           return 1;
    1448             : 
    1449             :         const std::array<unsigned int, 4> face_vertex =
    1450   235433340 :           oriented_prism_nodes(*elem, face_num);
    1451             : 
    1452   255001500 :         side->set_node(0, e.node_ptr(face_vertex[0]));
    1453   255001500 :         side->set_node(1, e.node_ptr(face_vertex[1]));
    1454   255001500 :         side->set_node(2, e.node_ptr(face_vertex[2]));
    1455   235433340 :         if (face_vertex[3] < 21)
    1456   194216130 :           side->set_node(3, e.node_ptr(face_vertex[3]));
    1457             : 
    1458   235433340 :         if (face_num == 0 || face_num == 4)
    1459    56121930 :           sidep = {zeta[face_vertex[1]%3], zeta[face_vertex[2]%3]};
    1460             :         else
    1461             :           {
    1462             :             // Transform a coordinate from the master prism to the
    1463             :             // master quad, based on two vertex indices defining the
    1464             :             // coordinate's direction
    1465   358622820 :             auto coord_val = [p](int v1, int v2){
    1466   358622820 :               if (v2-v1 == 3)
    1467    78513840 :                 return p(2);
    1468   280108980 :               else if (v2-v1 == -3)
    1469   100797570 :                 return -p(2);
    1470   179311410 :               else if (v1%3 == 0 && v2%3 == 1)
    1471    31965930 :                 return 2*p(0)-1;
    1472   147345480 :               else if (v2%3 == 0 && v1%3 == 1)
    1473    27804540 :                 return 1-2*p(0);
    1474   119540940 :               else if (v1%3 == 1 && v2%3 == 2)
    1475    31432920 :                 return p(1)-p(0);
    1476    88108020 :               else if (v2%3 == 1 && v1%3 == 2)
    1477    28303320 :                 return p(0)-p(1);
    1478    59804700 :               else if (v1%3 == 2 && v2%3 == 0)
    1479    20748270 :                 return 1-2*p(1);
    1480    39056430 :               else if (v2%3 == 2 && v1%3 == 0)
    1481    39056430 :                 return 2*p(1)-1;
    1482             :               else
    1483           0 :                 libmesh_error();
    1484   179311410 :             };
    1485             : 
    1486   194216130 :             sidep = {coord_val(face_vertex[0], face_vertex[1]),
    1487    14904720 :                      coord_val(face_vertex[0], face_vertex[3])};
    1488             :           }
    1489             : 
    1490   235433340 :         const unsigned int basisnum = i - i_offset;
    1491             : 
    1492   235433340 :         return FE<2,L2_HIERARCHIC>::shape(side, totalorder,
    1493    19568160 :                                           basisnum, sidep, false);
    1494             :       }
    1495             : 
    1496             : 
    1497           0 :     default:
    1498           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    1499             :     }
    1500             : 
    1501             : #else // LIBMESH_DIM != 3
    1502             :   libmesh_ignore(elem, order, i, p, add_p_level);
    1503             :   libmesh_not_implemented();
    1504             : #endif
    1505             : }
    1506             : 
    1507             : 
    1508             : template <>
    1509           0 : Real FE<3,SIDE_HIERARCHIC>::shape(const FEType fet,
    1510             :                                   const Elem * elem,
    1511             :                                   const unsigned int i,
    1512             :                                   const Point & p,
    1513             :                                   const bool add_p_level)
    1514             : {
    1515           0 :   return FE<3,SIDE_HIERARCHIC>::shape(elem,fet.order, i, p, add_p_level);
    1516             : }
    1517             : 
    1518             : 
    1519             : template <>
    1520           0 : Real FE<3,HIERARCHIC>::shape_deriv(const ElemType,
    1521             :                                    const Order,
    1522             :                                    const unsigned int,
    1523             :                                    const unsigned int,
    1524             :                                    const Point & )
    1525             : {
    1526           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1527             :   return 0.;
    1528             : }
    1529             : 
    1530             : 
    1531             : 
    1532             : template <>
    1533           0 : Real FE<3,L2_HIERARCHIC>::shape_deriv(const ElemType,
    1534             :                                       const Order,
    1535             :                                       const unsigned int,
    1536             :                                       const unsigned int,
    1537             :                                       const Point & )
    1538             : {
    1539           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1540             :   return 0.;
    1541             : }
    1542             : 
    1543             : 
    1544             : 
    1545             : template <>
    1546           0 : Real FE<3,SIDE_HIERARCHIC>::shape_deriv(const ElemType,
    1547             :                                         const Order,
    1548             :                                         const unsigned int,
    1549             :                                         const unsigned int,
    1550             :                                         const Point & )
    1551             : {
    1552           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1553             :   return 0.;
    1554             : }
    1555             : 
    1556             : 
    1557             : 
    1558             : template <>
    1559   378528906 : Real FE<3,HIERARCHIC>::shape_deriv(const Elem * elem,
    1560             :                                    const Order order,
    1561             :                                    const unsigned int i,
    1562             :                                    const unsigned int j,
    1563             :                                    const Point & p,
    1564             :                                    const bool add_p_level)
    1565             : {
    1566   725499699 :   return fe_hierarchic_3D_shape_deriv<HIERARCHIC>(elem, order, i, j, p, add_p_level);
    1567             : }
    1568             : 
    1569             : 
    1570             : template <>
    1571           0 : Real FE<3,HIERARCHIC>::shape_deriv(const FEType fet,
    1572             :                                    const Elem * elem,
    1573             :                                    const unsigned int i,
    1574             :                                    const unsigned int j,
    1575             :                                    const Point & p,
    1576             :                                    const bool add_p_level)
    1577             : {
    1578           0 :   return fe_hierarchic_3D_shape_deriv<HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
    1579             : }
    1580             : 
    1581             : 
    1582             : 
    1583             : template <>
    1584   644931312 : Real FE<3,L2_HIERARCHIC>::shape_deriv(const Elem * elem,
    1585             :                                       const Order order,
    1586             :                                       const unsigned int i,
    1587             :                                       const unsigned int j,
    1588             :                                       const Point & p,
    1589             :                                       const bool add_p_level)
    1590             : {
    1591  1236817422 :   return fe_hierarchic_3D_shape_deriv<L2_HIERARCHIC>(elem, order, i, j, p, add_p_level);
    1592             : }
    1593             : 
    1594             : 
    1595             : template <>
    1596           0 : Real FE<3,L2_HIERARCHIC>::shape_deriv(const FEType fet,
    1597             :                                       const Elem * elem,
    1598             :                                       const unsigned int i,
    1599             :                                       const unsigned int j,
    1600             :                                       const Point & p,
    1601             :                                       const bool add_p_level)
    1602             : {
    1603           0 :   return fe_hierarchic_3D_shape_deriv<L2_HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
    1604             : }
    1605             : 
    1606             : 
    1607             : 
    1608             : template <>
    1609  2042311680 : Real FE<3,SIDE_HIERARCHIC>::shape_deriv(const Elem * elem,
    1610             :                                         const Order order,
    1611             :                                         const unsigned int i,
    1612             :                                         const unsigned int j,
    1613             :                                         const Point & p,
    1614             :                                         const bool add_p_level)
    1615             : {
    1616             : #if LIBMESH_DIM == 3
    1617   170192640 :   libmesh_assert(elem);
    1618  2042311680 :   const ElemType type = elem->type();
    1619             : 
    1620  2212504320 :   const Order totalorder = order + add_p_level*elem->p_level();
    1621             : 
    1622  2042311680 :   if (totalorder == 0) // special case since raw HIERARCHIC lacks CONSTANTs
    1623       62400 :     return 0; // constants have zero derivative
    1624             : 
    1625  2041562880 :   switch (type)
    1626             :     {
    1627    19448640 :     case HEX27:
    1628             :       {
    1629             :         // I need to debug the p>2 case here...
    1630   233383680 :         if (totalorder > 2)
    1631   228355200 :           return fe_fdm_deriv(elem, order, i, j, p, add_p_level, FE<3,SIDE_HIERARCHIC>::shape);
    1632             : 
    1633     5028480 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
    1634      419040 :         libmesh_assert_less(i, 6*dofs_per_side);
    1635             : 
    1636     5028480 :         const unsigned int sidenum = cube_side(p);
    1637     5028480 :         if (sidenum > 5)
    1638           0 :           return std::numeric_limits<Real>::quiet_NaN();
    1639             : 
    1640     5028480 :         const unsigned int dof_offset = sidenum * dofs_per_side;
    1641             : 
    1642     5028480 :         if (i < dof_offset) // i is on a previous side
    1643      174600 :           return 0;
    1644             : 
    1645     2933280 :         if (i >= dof_offset + dofs_per_side) // i is on a later side
    1646      174600 :           return 0;
    1647             : 
    1648      838080 :         unsigned int side_i = i - dof_offset;
    1649             : 
    1650      838080 :         std::unique_ptr<const Elem> side = elem->build_side_ptr(sidenum);
    1651             : 
    1652      838080 :         Point sidep = cube_side_point(sidenum, p);
    1653             : 
    1654      838080 :         cube_remap(side_i, *side, totalorder, sidep);
    1655             : 
    1656             :         // What direction on the side corresponds to the derivative
    1657             :         // direction we want?
    1658       69840 :         unsigned int sidej = 100;
    1659             : 
    1660             :         // Do we need a -1 here to flip that direction?
    1661       69840 :         Real f = 1.;
    1662             : 
    1663             :         switch (j)
    1664             :           {
    1665      279360 :           case 0: // d()/dxi
    1666             :             {
    1667             :               switch (sidenum)
    1668             :                 {
    1669        3880 :                 case 0:
    1670        3880 :                   sidej = 1;
    1671        3880 :                   break;
    1672        7760 :                 case 1:
    1673        3880 :                   sidej = 0;
    1674        7760 :                   break;
    1675        3880 :                 case 2:
    1676        3880 :                   return 0;
    1677       46560 :                 case 3:
    1678        3880 :                   sidej = 0;
    1679        3880 :                   f = -1;
    1680       46560 :                   break;
    1681        3880 :                 case 4:
    1682        3880 :                   return 0;
    1683        7760 :                 case 5:
    1684        3880 :                   sidej = 0;
    1685        7760 :                   break;
    1686           0 :                 default:
    1687           0 :                   libmesh_error();
    1688             :                 }
    1689       15520 :               break;
    1690             :             }
    1691      279360 :           case 1: // d()/deta
    1692             :             {
    1693             :               switch (sidenum)
    1694             :                 {
    1695        3880 :                 case 0:
    1696        3880 :                   sidej = 0;
    1697        3880 :                   break;
    1698        3880 :                 case 1:
    1699        3880 :                   return 0;
    1700        3880 :                 case 2:
    1701        3880 :                   sidej = 0;
    1702        3880 :                   break;
    1703        3880 :                 case 3:
    1704        3880 :                   return 0;
    1705       46560 :                 case 4:
    1706        3880 :                   sidej = 0;
    1707        3880 :                   f = -1;
    1708       46560 :                   break;
    1709        7760 :                 case 5:
    1710        3880 :                   sidej = 1;
    1711        7760 :                   break;
    1712           0 :                 default:
    1713           0 :                   libmesh_error();
    1714             :                 }
    1715       15520 :               break;
    1716             :             }
    1717      279360 :           case 2: // d()/dzeta
    1718             :             {
    1719             :               switch (sidenum)
    1720             :                 {
    1721        3880 :                 case 0:
    1722        3880 :                   return 0;
    1723       15520 :                 case 1:
    1724             :                 case 2:
    1725             :                 case 3:
    1726             :                 case 4:
    1727       15520 :                   sidej = 1;
    1728       15520 :                   break;
    1729        3880 :                 case 5:
    1730        3880 :                   return 0;
    1731           0 :                 default:
    1732           0 :                   libmesh_error();
    1733             :                 }
    1734       15520 :               break;
    1735             :             }
    1736             : 
    1737           0 :           default:
    1738           0 :             libmesh_error_msg("Invalid derivative index j = " << j);
    1739             :           }
    1740             : 
    1741      558720 :         return f * FE<2,HIERARCHIC>::shape_deriv(side.get(), order,
    1742             :                                                  side_i, sidej, sidep,
    1743      558720 :                                                  add_p_level);
    1744      698400 :       }
    1745             : 
    1746  1808179200 :     case TET14:
    1747             :     case PRISM20:
    1748             :     case PRISM21:
    1749             :       {
    1750  1808179200 :         return fe_fdm_deriv(elem, order, i, j, p, add_p_level, FE<3,SIDE_HIERARCHIC>::shape);
    1751             :       }
    1752             : 
    1753           0 :     default:
    1754           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    1755             :     }
    1756             : 
    1757             : #else // LIBMESH_DIM != 3
    1758             :   libmesh_ignore(elem, order, i, j, p, add_p_level);
    1759             :   libmesh_not_implemented();
    1760             : #endif
    1761             : }
    1762             : 
    1763             : 
    1764             : template <>
    1765           0 : Real FE<3,SIDE_HIERARCHIC>::shape_deriv(const FEType fet,
    1766             :                                         const Elem * elem,
    1767             :                                         const unsigned int i,
    1768             :                                         const unsigned int j,
    1769             :                                         const Point & p,
    1770             :                                         const bool add_p_level)
    1771             : {
    1772           0 :   return FE<3,SIDE_HIERARCHIC>::shape_deriv(elem, fet.order, i, j, p, add_p_level);
    1773             : }
    1774             : 
    1775             : 
    1776             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1777             : 
    1778             : template <>
    1779           0 : Real FE<3,HIERARCHIC>::shape_second_deriv(const ElemType,
    1780             :                                           const Order,
    1781             :                                           const unsigned int,
    1782             :                                           const unsigned int,
    1783             :                                           const Point & )
    1784             : {
    1785           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1786             :   return 0.;
    1787             : }
    1788             : 
    1789             : 
    1790             : 
    1791             : template <>
    1792           0 : Real FE<3,L2_HIERARCHIC>::shape_second_deriv(const ElemType,
    1793             :                                              const Order,
    1794             :                                              const unsigned int,
    1795             :                                              const unsigned int,
    1796             :                                              const Point & )
    1797             : {
    1798           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1799             :   return 0.;
    1800             : }
    1801             : 
    1802             : 
    1803             : 
    1804             : template <>
    1805           0 : Real FE<3,SIDE_HIERARCHIC>::shape_second_deriv(const ElemType,
    1806             :                                                const Order,
    1807             :                                                const unsigned int,
    1808             :                                                const unsigned int,
    1809             :                                                const Point & )
    1810             : {
    1811           0 :   libmesh_error_msg("Hierarchic shape functions require an Elem for edge/face orientation.");
    1812             :   return 0.;
    1813             : }
    1814             : 
    1815             : 
    1816             : 
    1817             : template <>
    1818   138671364 : Real FE<3,HIERARCHIC>::shape_second_deriv(const Elem * elem,
    1819             :                                           const Order order,
    1820             :                                           const unsigned int i,
    1821             :                                           const unsigned int j,
    1822             :                                           const Point & p,
    1823             :                                           const bool add_p_level)
    1824             : {
    1825   265781166 :   return fe_hierarchic_3D_shape_second_deriv<HIERARCHIC>(elem, order, i, j, p, add_p_level);
    1826             : }
    1827             : 
    1828             : 
    1829             : 
    1830             : template <>
    1831           0 : Real FE<3,HIERARCHIC>::shape_second_deriv(const FEType fet,
    1832             :                                           const Elem * elem,
    1833             :                                           const unsigned int i,
    1834             :                                           const unsigned int j,
    1835             :                                           const Point & p,
    1836             :                                           const bool add_p_level)
    1837             : {
    1838           0 :   return fe_hierarchic_3D_shape_second_deriv<HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
    1839             : }
    1840             : 
    1841             : 
    1842             : 
    1843             : template <>
    1844   232084380 : Real FE<3,L2_HIERARCHIC>::shape_second_deriv(const Elem * elem,
    1845             :                                              const Order order,
    1846             :                                              const unsigned int i,
    1847             :                                              const unsigned int j,
    1848             :                                              const Point & p,
    1849             :                                              const bool add_p_level)
    1850             : {
    1851   445084560 :   return fe_hierarchic_3D_shape_second_deriv<L2_HIERARCHIC>(elem, order, i, j, p, add_p_level);
    1852             : }
    1853             : 
    1854             : 
    1855             : template <>
    1856           0 : Real FE<3,L2_HIERARCHIC>::shape_second_deriv(const FEType fet,
    1857             :                                              const Elem * elem,
    1858             :                                              const unsigned int i,
    1859             :                                              const unsigned int j,
    1860             :                                              const Point & p,
    1861             :                                              const bool add_p_level)
    1862             : {
    1863           0 :   return fe_hierarchic_3D_shape_second_deriv<L2_HIERARCHIC>(elem, fet.order, i, j, p, add_p_level);
    1864             : }
    1865             : 
    1866             : 
    1867             : template <>
    1868   826168320 : Real FE<3,SIDE_HIERARCHIC>::shape_second_deriv(const Elem * elem,
    1869             :                                                const Order order,
    1870             :                                                const unsigned int i,
    1871             :                                                const unsigned int j,
    1872             :                                                const Point & p,
    1873             :                                                const bool add_p_level)
    1874             : {
    1875             : #if LIBMESH_DIM == 3
    1876    68847360 :   libmesh_assert(elem);
    1877   826168320 :   const ElemType type = elem->type();
    1878             : 
    1879   895015680 :   const Order totalorder = order + add_p_level*elem->p_level();
    1880             : 
    1881   826168320 :   if (totalorder == 0) // special case since raw HIERARCHIC lacks CONSTANTs
    1882      124800 :     return 0; // constants have zero derivative
    1883             : 
    1884   824670720 :   switch (type)
    1885             :     {
    1886     8449920 :     case HEX27:
    1887             :       {
    1888             :         // I need to debug the p>2 case here...
    1889   101399040 :         if (totalorder > 2)
    1890    91342080 :           return fe_fdm_second_deriv(elem, order, i, j, p, add_p_level,
    1891     7611840 :                                      FE<3,SIDE_HIERARCHIC>::shape_deriv);
    1892             : 
    1893    10056960 :         const unsigned int dofs_per_side = (totalorder+1u)*(totalorder+1u);
    1894      838080 :         libmesh_assert_less(i, 6*dofs_per_side);
    1895             : 
    1896    10056960 :         const unsigned int sidenum = cube_side(p);
    1897    10056960 :         if (sidenum > 5)
    1898           0 :           return std::numeric_limits<Real>::quiet_NaN();
    1899             : 
    1900    10056960 :         const unsigned int dof_offset = sidenum * dofs_per_side;
    1901             : 
    1902    10056960 :         if (i < dof_offset) // i is on a previous side
    1903      349200 :           return 0;
    1904             : 
    1905     5866560 :         if (i >= dof_offset + dofs_per_side) // i is on a later side
    1906      349200 :           return 0;
    1907             : 
    1908     1676160 :         unsigned int side_i = i - dof_offset;
    1909             : 
    1910     1676160 :         std::unique_ptr<const Elem> side = elem->build_side_ptr(sidenum);
    1911             : 
    1912     1676160 :         Point sidep = cube_side_point(sidenum, p);
    1913             : 
    1914     1676160 :         cube_remap(side_i, *side, totalorder, sidep);
    1915             : 
    1916             :         // What second derivative or mixed derivative on the side
    1917             :         // corresponds to the xi/eta/zeta mix we were asked for?
    1918      139680 :         unsigned int sidej = 100;
    1919             : 
    1920             :         // Do we need a -1 here to flip the final derivative value?
    1921      139680 :         Real f = 1.;
    1922             : 
    1923             :         switch (j)
    1924             :           {
    1925      279360 :           case 0: // d^2()/dxi^2
    1926             :             {
    1927             :               switch (sidenum)
    1928             :                 {
    1929        3880 :                 case 0:
    1930        3880 :                   sidej = 2;
    1931        3880 :                   break;
    1932        7760 :                 case 1:
    1933        3880 :                   sidej = 0;
    1934        7760 :                   break;
    1935        3880 :                 case 2:
    1936        3880 :                   return 0;
    1937        7760 :                 case 3:
    1938        3880 :                   sidej = 0;
    1939        7760 :                   break;
    1940        3880 :                 case 4:
    1941        3880 :                   return 0;
    1942        7760 :                 case 5:
    1943        3880 :                   sidej = 0;
    1944        7760 :                   break;
    1945           0 :                 default:
    1946           0 :                   libmesh_error();
    1947             :                 }
    1948       15520 :               break;
    1949             :             }
    1950      279360 :           case 1: // d^2()/dxideta
    1951             :             {
    1952             :               switch (sidenum)
    1953             :                 {
    1954        3880 :                 case 0:
    1955        3880 :                   sidej = 1;
    1956        3880 :                   break;
    1957       15520 :                 case 1:
    1958             :                 case 2:
    1959             :                 case 3:
    1960             :                 case 4:
    1961       15520 :                   return 0;
    1962        3880 :                 case 5:
    1963        3880 :                   sidej = 1;
    1964        3880 :                   break;
    1965           0 :                 default:
    1966           0 :                   libmesh_error();
    1967             :                 }
    1968        7760 :               break;
    1969             :             }
    1970      279360 :           case 2: // d^2()/deta^2
    1971             :             {
    1972             :               switch (sidenum)
    1973             :                 {
    1974        3880 :                 case 0:
    1975        3880 :                   sidej = 0;
    1976        3880 :                   break;
    1977        3880 :                 case 1:
    1978        3880 :                   return 0;
    1979        3880 :                 case 2:
    1980        3880 :                   sidej = 0;
    1981        3880 :                   break;
    1982        3880 :                 case 3:
    1983        3880 :                   return 0;
    1984        3880 :                 case 4:
    1985        3880 :                   sidej = 0;
    1986        3880 :                   break;
    1987        3880 :                 case 5:
    1988        3880 :                   sidej = 2;
    1989        3880 :                   break;
    1990           0 :                 default:
    1991           0 :                   libmesh_error();
    1992             :                 }
    1993       15520 :               break;
    1994             :             }
    1995      279360 :           case 3: // d^2()/dxidzeta
    1996             :             {
    1997             :               switch (sidenum)
    1998             :                 {
    1999        3880 :                 case 0:
    2000        3880 :                   return 0;
    2001        3880 :                 case 1:
    2002        3880 :                   sidej = 1;
    2003        3880 :                   break;
    2004        3880 :                 case 2:
    2005        3880 :                   return 0;
    2006        3880 :                 case 3:
    2007        3880 :                   sidej = 1;
    2008        3880 :                   f = -1;
    2009        3880 :                   break;
    2010        7760 :                 case 4:
    2011             :                 case 5:
    2012        7760 :                   return 0;
    2013           0 :                 default:
    2014           0 :                   libmesh_error();
    2015             :                 }
    2016        7760 :               break;
    2017             :             }
    2018      279360 :           case 4: // d^2()/detadzeta
    2019             :             {
    2020             :               switch (sidenum)
    2021             :                 {
    2022        7760 :                 case 0:
    2023             :                 case 1:
    2024        7760 :                   return 0;
    2025        3880 :                 case 2:
    2026        3880 :                   sidej = 1;
    2027        3880 :                   break;
    2028        3880 :                 case 3:
    2029        3880 :                   return 0;
    2030        3880 :                 case 4:
    2031        3880 :                   sidej = 1;
    2032        3880 :                   f = -1;
    2033        3880 :                   break;
    2034        3880 :                 case 5:
    2035        3880 :                   return 0;
    2036           0 :                 default:
    2037           0 :                   libmesh_error();
    2038             :                 }
    2039        7760 :               break;
    2040             :             }
    2041      279360 :           case 5: // d^2()/dzeta^2
    2042             :             {
    2043             :               switch (sidenum)
    2044             :                 {
    2045        3880 :                 case 0:
    2046        3880 :                   return 0;
    2047       15520 :                 case 1:
    2048             :                 case 2:
    2049             :                 case 3:
    2050             :                 case 4:
    2051       15520 :                   sidej = 2;
    2052       15520 :                   break;
    2053        3880 :                 case 5:
    2054        3880 :                   return 0;
    2055           0 :                 default:
    2056           0 :                   libmesh_error();
    2057             :                 }
    2058       15520 :               break;
    2059             :             }
    2060             : 
    2061           0 :           default:
    2062           0 :             libmesh_error_msg("Invalid derivative index j = " << j);
    2063             :           }
    2064             : 
    2065      838080 :         return f * FE<2,HIERARCHIC>::shape_second_deriv(side.get(),
    2066             :                                                         order, side_i,
    2067             :                                                         sidej, sidep,
    2068      838080 :                                                         add_p_level);
    2069     1396800 :       }
    2070             : 
    2071   723271680 :     case TET14:
    2072             :     case PRISM20:
    2073             :     case PRISM21:
    2074             :       {
    2075   723271680 :         return fe_fdm_second_deriv(elem, order, i, j, p, add_p_level,
    2076   723271680 :                                    FE<3,SIDE_HIERARCHIC>::shape_deriv);
    2077             :       }
    2078             : 
    2079           0 :     default:
    2080           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    2081             :     }
    2082             : 
    2083             : #else // LIBMESH_DIM != 3
    2084             :   libmesh_ignore(elem, order, i, j, p, add_p_level);
    2085             :   libmesh_not_implemented();
    2086             : #endif
    2087             : }
    2088             : 
    2089             : 
    2090             : template <>
    2091           0 : Real FE<3,SIDE_HIERARCHIC>::shape_second_deriv(const FEType fet,
    2092             :                                                const Elem * elem,
    2093             :                                                const unsigned int i,
    2094             :                                                const unsigned int j,
    2095             :                                                const Point & p,
    2096             :                                                const bool add_p_level)
    2097             : {
    2098           0 :   return FE<3,SIDE_HIERARCHIC>::shape_second_deriv(elem, fet.order, i, j, p, add_p_level);
    2099             : }
    2100             : 
    2101             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
    2102             : 
    2103             : } // namespace libMesh
    2104             : 
    2105             : 
    2106             : 
    2107             : namespace
    2108             : {
    2109             : using namespace libMesh;
    2110             : 
    2111             : 
    2112   515418714 : unsigned int cube_side (const Point & p)
    2113             : {
    2114   515418714 :   const Real xi = p(0), eta = p(1), zeta = p(2);
    2115   515418714 :   const Real absxi   = std::abs(xi),
    2116   515418714 :              abseta  = std::abs(eta),
    2117   515418714 :              abszeta = std::abs(zeta);
    2118   515418714 :   const Real maxabs_xi_eta   = std::max(absxi, abseta),
    2119   515418714 :              maxabs_xi_zeta  = std::max(absxi, abszeta),
    2120   515418714 :              maxabs_eta_zeta = std::max(abseta, abszeta);
    2121             : 
    2122   515418714 :   if (zeta < -maxabs_xi_eta)
    2123     7151148 :     return 0;
    2124   429516196 :   else if (eta < -maxabs_xi_zeta)
    2125     7171126 :     return 1;
    2126   343477936 :   else if (xi > maxabs_eta_zeta)
    2127     7188558 :     return 2;
    2128   257348620 :   else if (eta > maxabs_xi_zeta)
    2129     7158032 :     return 3;
    2130   171597400 :   else if (xi < -maxabs_eta_zeta)
    2131     7006032 :     return 4;
    2132    86307298 :   else if (zeta > maxabs_xi_eta)
    2133    85877350 :     return 5;
    2134             : 
    2135             :   // We need to be able to return invalid values for cases where
    2136             :   // mixed FE are being evaluated together on edges and vertices
    2137       25920 :   return 65535;
    2138             : }
    2139             : 
    2140             : 
    2141             : 
    2142    88992834 : Point cube_side_point(unsigned int sidenum, const Point & p)
    2143             : {
    2144     7397584 :   Point sidep;
    2145             : 
    2146    88992834 :   switch (sidenum)
    2147             :     {
    2148    14834316 :     case 0:
    2149    14834316 :       sidep(0) = p(1);
    2150    14834316 :       sidep(1) = p(0);
    2151    14834316 :       break;
    2152    14866568 :     case 1:
    2153    14866568 :       sidep(0) = p(0);
    2154    14866568 :       sidep(1) = p(2);
    2155    14866568 :       break;
    2156    14873064 :     case 2:
    2157    14873064 :       sidep(0) = p(1);
    2158    14873064 :       sidep(1) = p(2);
    2159    14873064 :       break;
    2160    14818788 :     case 3:
    2161    14818788 :       sidep(0) = -p(0);
    2162    14818788 :       sidep(1) = p(2);
    2163    14818788 :       break;
    2164    14750670 :     case 4:
    2165    14750670 :       sidep(0) = -p(1);
    2166    14750670 :       sidep(1) = p(2);
    2167    14750670 :       break;
    2168    14849428 :     case 5:
    2169    14849428 :       sidep(0) = p(0);
    2170    14849428 :       sidep(1) = p(1);
    2171    14849428 :       break;
    2172           0 :     default:
    2173           0 :       libmesh_error();
    2174             :     }
    2175             : 
    2176    88992834 :   return sidep;
    2177             : }
    2178             : 
    2179             : 
    2180   179311410 : void orient_quad(const Elem & elem,
    2181             :                  std::array<unsigned int, 4> & face_vertex)
    2182             : {
    2183             :   // Sort the minimum point into face_vertex[0], the minimum of its
    2184             :   // neighbors into face_vertex[1].  Keep the other two consistent; we
    2185             :   // want to rotate or flip the quad but not to twist it.
    2186             : 
    2187             :   const unsigned int min_pt =
    2188    14904720 :     std::min_element(face_vertex.begin(), face_vertex.end(),
    2189   537934230 :                      [&elem](auto v1, auto v2)
    2190   627362550 :                      {return elem.point(v1)<elem.point(v2);}) -
    2191   194216130 :     face_vertex.begin();
    2192             : 
    2193             :   // Do we flip the quad?
    2194   194216130 :   if (elem.point(face_vertex[(min_pt+3)%4]) <
    2195   179311410 :       elem.point(face_vertex[(min_pt+1)%4]))
    2196   103966290 :     face_vertex = { face_vertex[min_pt], face_vertex[(min_pt+3)%4],
    2197    89178930 :                     face_vertex[(min_pt+2)%4], face_vertex[(min_pt+1)%4] };
    2198             :   else
    2199   105154560 :     face_vertex = { face_vertex[min_pt], face_vertex[(min_pt+1)%4],
    2200    90132480 :                     face_vertex[(min_pt+2)%4], face_vertex[(min_pt+3)%4] };
    2201   179311410 : }
    2202             : 
    2203             : 
    2204   866960182 : void orient_triangle(const Elem & elem,
    2205             :                      unsigned int * face_vertex)
    2206             : {
    2207             :   // Reorient nodes to account for flipping and rotation.
    2208             :   // We could try to identify indices with symmetric shape
    2209             :   // functions, to skip this in those cases, if we really
    2210             :   // need to optimize later.
    2211             :   //
    2212             :   // With only 3 items, we should bubble sort!
    2213             :   // Programming-for-MechE's class pays off!
    2214    71261072 :   bool lastcheck = true;
    2215  1009482326 :   if (elem.point(face_vertex[0]) > elem.point(face_vertex[1]))
    2216             :     {
    2217    36670636 :       std::swap(face_vertex[0], face_vertex[1]);
    2218    36670636 :       lastcheck = true;
    2219             :     }
    2220  1009482326 :   if (elem.point(face_vertex[1]) > elem.point(face_vertex[2]))
    2221    45559055 :     std::swap(face_vertex[1], face_vertex[2]);
    2222  1009482326 :   if (lastcheck && elem.point(face_vertex[0]) > elem.point(face_vertex[1]))
    2223    23208357 :     std::swap(face_vertex[0], face_vertex[1]);
    2224   866960182 : }
    2225             : 
    2226             : 
    2227   235433340 : std::array<unsigned int, 4> oriented_prism_nodes(const Elem & elem,
    2228             :                                                  unsigned int face_num)
    2229             : {
    2230             :   std::array<unsigned int, 4> face_vertex
    2231   235433340 :     { Prism6::side_nodes_map[face_num][0],
    2232   235433340 :       Prism6::side_nodes_map[face_num][1],
    2233   235433340 :       Prism6::side_nodes_map[face_num][2],
    2234   313705980 :       Prism6::side_nodes_map[face_num][3] };
    2235             : 
    2236   235433340 :   if (face_num > 0 && face_num < 4)
    2237   179311410 :     orient_quad(elem, face_vertex);
    2238             :   else
    2239    56121930 :     orient_triangle(elem, face_vertex.data());
    2240             : 
    2241   235433340 :   return face_vertex;
    2242             : }
    2243             : 
    2244             : 
    2245   697368912 : std::array<unsigned int, 3> oriented_tet_nodes(const Elem & elem,
    2246             :                                                unsigned int face_num)
    2247             : {
    2248             :   std::array<unsigned int, 3> face_vertex
    2249   759379124 :     { Tet4::side_nodes_map[face_num][0],
    2250   759379124 :       Tet4::side_nodes_map[face_num][1],
    2251   883399548 :       Tet4::side_nodes_map[face_num][2] };
    2252             : 
    2253   757211280 :   orient_triangle(elem, face_vertex.data());
    2254             : 
    2255   757211280 :   return face_vertex;
    2256             : }
    2257             : 
    2258             : 
    2259             : template <FEFamily T>
    2260  2453552914 : Real fe_hierarchic_3D_shape(const Elem * elem,
    2261             :                             const Order order,
    2262             :                             const unsigned int i,
    2263             :                             const Point & p,
    2264             :                             const bool add_p_level)
    2265             : {
    2266             : #if LIBMESH_DIM == 3
    2267             : 
    2268   202376202 :   libmesh_assert(elem);
    2269  2453552914 :   const ElemType type = elem->type();
    2270             : 
    2271  2655929116 :   const Order totalorder = order + add_p_level*elem->p_level();
    2272             : 
    2273  2251176712 :   switch (type)
    2274             :     {
    2275   847174850 :     case HEX8:
    2276             :     case HEX20:
    2277    16615178 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 2);
    2278             :       libmesh_fallthrough();
    2279             :     case HEX27:
    2280             :       {
    2281    72937466 :         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
    2282             : 
    2283             :         // Compute hex shape functions as a tensor-product
    2284   903497138 :         Real xi   = p(0);
    2285   903497138 :         Real eta  = p(1);
    2286   903497138 :         Real zeta = p(2);
    2287             : 
    2288             :         unsigned int i0, i1, i2;
    2289             : 
    2290   903497138 :         cube_indices(elem, totalorder, i, xi, eta, zeta, i0, i1, i2);
    2291             : 
    2292   976434604 :         return (FE<1,T>::shape(EDGE3, totalorder, i0, xi)*
    2293   976434604 :                 FE<1,T>::shape(EDGE3, totalorder, i1, eta)*
    2294   976434604 :                 FE<1,T>::shape(EDGE3, totalorder, i2, zeta));
    2295             :       }
    2296             : 
    2297   793683796 :     case PRISM6:
    2298             :     case PRISM15:
    2299    14744010 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 2);
    2300             :       libmesh_fallthrough();
    2301             :     case PRISM18:
    2302    17277378 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 3);
    2303             :       libmesh_fallthrough();
    2304             :     case PRISM20:
    2305             :     case PRISM21:
    2306             :       {
    2307    76216482 :         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+2u)/2u);
    2308             : 
    2309             :         // Compute prism shape functions as a tensor-product.
    2310             :         // Non-const here, because prism_indices might need to do some
    2311             :         // flips before evaluating edge or face DoFs
    2312   855156268 :         Point xi_eta {p(0),p(1)};
    2313   855156268 :         Real zeta = p(2);
    2314             : 
    2315             :         unsigned int i01, i2;
    2316             : 
    2317   855156268 :         prism_indices(elem, totalorder, i, xi_eta, zeta, i01, i2);
    2318             : 
    2319             :         // We'll use the 2D Tri to handle any basis function flipping
    2320             :         // needed in xi/eta for triangle face+edge bases.
    2321    76216482 :         Tri3 tri;
    2322             : 
    2323             :         // We pinky swear not to modify these nodes
    2324    76216482 :         Elem & e = const_cast<Elem &>(*elem);
    2325   855156268 :         if (i2 == 0)
    2326             :           {
    2327    36338484 :             tri.set_node(0, e.node_ptr(0));
    2328    18169242 :             tri.set_node(1, e.node_ptr(1));
    2329    18169242 :             tri.set_node(2, e.node_ptr(2));
    2330             :           }
    2331   651275552 :         else if (i2 == 1)
    2332             :           {
    2333    36338484 :             tri.set_node(0, e.node_ptr(3));
    2334    18169242 :             tri.set_node(1, e.node_ptr(4));
    2335    18169242 :             tri.set_node(2, e.node_ptr(5));
    2336             :           }
    2337             :         else
    2338             :           {
    2339             :             // For interior DoFs, no flipping is necessary or done; we
    2340             :             // can just evaluate on any triangle ... but *not* the
    2341             :             // obvious 9,10,11 triangle, because that might not exist
    2342             :             // if we have L2_HIERARCHIC on Prism6.
    2343    79755996 :             tri.set_node(0, e.node_ptr(0));
    2344    39877998 :             tri.set_node(1, e.node_ptr(1));
    2345    39877998 :             tri.set_node(2, e.node_ptr(2));
    2346             : 
    2347             :             // For square face DoFs, prism_indices handles flipping,
    2348             :             // and we *can't* override that in the tri shape call.
    2349   447392756 :             if (i01 > 2 && i01 < 3u*totalorder)
    2350             :               {
    2351             :                 // %(p-1) to find the edge number, %2 for even vs odd
    2352   264843012 :                 const bool odd_basis = ((i01-3)%(totalorder-1))%2;
    2353   264843012 :                 if (odd_basis)
    2354             :                   {
    2355    92442516 :                     const int tri_edge = (i01-3)/(totalorder-1);
    2356             :                     // Flip nodes now to avoid triggering a shape
    2357             :                     // function flip later
    2358   108922008 :                     if (tri.point(tri_edge) > tri.point((tri_edge+1)%3))
    2359             :                       {
    2360     8775616 :                         Node * n = tri.node_ptr(tri_edge);
    2361     4387808 :                         tri.set_node(tri_edge, tri.node_ptr((tri_edge+1)%3));
    2362     4387808 :                         tri.set_node((tri_edge+1)%3, n);
    2363             :                       }
    2364             :                   }
    2365             :               }
    2366             :           }
    2367             : 
    2368   855156268 :         return (FE<2,L2_HIERARCHIC>::shape(&tri, totalorder, i01, xi_eta)*
    2369   931372750 :                 FE<1,L2_HIERARCHIC>::shape(EDGE2, totalorder, i2, zeta));
    2370             :       }
    2371             : 
    2372   642568814 :     case TET4:
    2373      891560 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 2);
    2374             :       libmesh_fallthrough();
    2375             :     case TET10:
    2376     2608835 :       libmesh_assert (T == L2_HIERARCHIC || totalorder < 3);
    2377             :       libmesh_fallthrough();
    2378             :     case TET14:
    2379             :       {
    2380   694899508 :         const Real zeta[4] = { 1 - p(0) - p(1) - p(2), p(0), p(1), p(2) };
    2381             : 
    2382             :         // Nodal DoFs
    2383   694899508 :         if (i < 4)
    2384   387667020 :           return zeta[i];
    2385             : 
    2386             :         // Edge DoFs
    2387   307232488 :         else if (i < 6u*totalorder - 2u)
    2388             :           {
    2389   264433242 :             const unsigned int edge_num = (i - 4) / (totalorder - 1u);
    2390             :             // const int edge_node = edge_num + 4;
    2391   264433242 :             const unsigned int basisorder = i - 2 - ((totalorder - 1u) * edge_num);
    2392             : 
    2393   264433242 :             const unsigned int edgevertex0 = Tet4::edge_nodes_map[edge_num][0],
    2394   264433242 :                                edgevertex1 = Tet4::edge_nodes_map[edge_num][1];
    2395             : 
    2396             :             // Get factors to account for edge-flipping
    2397    19538916 :             Real flip = 1;
    2398   294775380 :             if (basisorder%2 &&
    2399    30342138 :                 elem->positive_edge_orientation(edge_num))
    2400      825512 :               flip = -1;
    2401             : 
    2402   264433242 :             const Real crossval = zeta[edgevertex0] + zeta[edgevertex1];
    2403   264433242 :             const Real edgenumerator = zeta[edgevertex1] - zeta[edgevertex0];
    2404             : 
    2405   264433242 :             if (crossval == 0.) // Yes, exact comparison; we seem numerically stable otherwise
    2406             :               {
    2407             :                 // The limit of the general expression below, in which only the bubble's leading term
    2408             :                 // survives and so carries the same normalization the one-dimensional bubble does
    2409       41693 :                 return std::pow(edgenumerator, basisorder) *
    2410      553111 :                   fe_hierarchic_bubble_scaling(basisorder);
    2411             :               }
    2412             : 
    2413   263880131 :             const Real edgeval = edgenumerator / crossval;
    2414    19497223 :             const Real crossfunc = std::pow(crossval, basisorder);
    2415             : 
    2416   263880131 :             return flip * crossfunc *
    2417   263880131 :               FE<1,HIERARCHIC>::shape(EDGE3, totalorder,
    2418   263880131 :                                       basisorder, edgeval);
    2419             :           }
    2420             : 
    2421             :         // Face DoFs
    2422    42799246 :         else if (i < 2u*totalorder*totalorder + 2u)
    2423             :           {
    2424    40334348 :             const int dofs_per_face = (totalorder - 1u) * (totalorder - 2u) / 2;
    2425    40334348 :             const int face_num = (i - (6u*totalorder - 2u)) / dofs_per_face;
    2426             : 
    2427             :             const std::array<unsigned int, 3> face_vertex =
    2428    38166504 :               oriented_tet_nodes(*elem, face_num);
    2429    40334348 :             const Real zeta0 = zeta[face_vertex[0]],
    2430    40334348 :                        zeta1 = zeta[face_vertex[1]],
    2431    40334348 :                        zeta2 = zeta[face_vertex[2]];
    2432             : 
    2433    40334348 :             const unsigned int basisnum =
    2434    42502192 :               i - 4 -
    2435    42502192 :               (totalorder - 1u) * /*n_edges*/6 -
    2436    40334348 :               (dofs_per_face * face_num);
    2437             : 
    2438    40334348 :             const unsigned int exp0 = triangular_number_column[basisnum] + 1;
    2439    40334348 :             const unsigned int exp1 = triangular_number_row[basisnum] + 1 -
    2440             :               triangular_number_column[basisnum];
    2441             : 
    2442     2167844 :             Real returnval = 1;
    2443    91689504 :             for (unsigned int n = 0; n != exp0; ++n)
    2444    51355156 :               returnval *= zeta0;
    2445    91689504 :             for (unsigned int n = 0; n != exp1; ++n)
    2446    51355156 :               returnval *= zeta1;
    2447    40334348 :             returnval *= zeta2;
    2448     2167844 :             return returnval;
    2449             :           }
    2450             : 
    2451             :         // Interior DoFs
    2452             :         else
    2453             :           {
    2454     2464898 :             const unsigned int basisnum = i - 2u*totalorder*totalorder - 2u;
    2455     2464898 :             const unsigned int exp0 = tetrahedral_number_column[basisnum] + 1;
    2456     2716926 :             const unsigned int exp1 = tetrahedral_number_row[basisnum] + 1 -
    2457     2464898 :                                       tetrahedral_number_column[basisnum] -
    2458     2212870 :                                       tetrahedral_number_page[basisnum];
    2459     2464898 :             const unsigned int exp2 = tetrahedral_number_page[basisnum] + 1;
    2460             : 
    2461      126014 :             Real returnval = 1;
    2462     4929796 :             for (unsigned int n = 0; n != exp0; ++n)
    2463     2464898 :               returnval *= zeta[0];
    2464     4929796 :             for (unsigned int n = 0; n != exp1; ++n)
    2465     2464898 :               returnval *= zeta[1];
    2466     4929796 :             for (unsigned int n = 0; n != exp2; ++n)
    2467     2464898 :               returnval *= zeta[2];
    2468     2464898 :             returnval *= zeta[3];
    2469     2464898 :             return returnval;
    2470             :           }
    2471             :       }
    2472             : 
    2473           0 :     default:
    2474           0 :       libmesh_error_msg("Invalid element type = " << Utility::enum_to_string(type));
    2475             :     }
    2476             : 
    2477             : #else // LIBMESH_DIM != 3
    2478             :   libmesh_ignore(elem, order, i, p, add_p_level);
    2479             :   libmesh_not_implemented();
    2480             : #endif
    2481             : }
    2482             : 
    2483             : 
    2484             : 
    2485             : template <FEFamily T>
    2486    84603315 : Real fe_hierarchic_3D_shape_deriv(const Elem * elem,
    2487             :                                   const Order order,
    2488             :                                   const unsigned int i,
    2489             :                                   const unsigned int j,
    2490             :                                   const Point & p,
    2491             :                                   const bool add_p_level)
    2492             : {
    2493  1023460218 :   return fe_fdm_deriv(elem, order, i, j, p, add_p_level, FE<3,T>::shape);
    2494             : }
    2495             : 
    2496             : 
    2497             : 
    2498             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2499             : 
    2500             : template <FEFamily T>
    2501    30645762 : Real fe_hierarchic_3D_shape_second_deriv(const Elem * elem,
    2502             :                                          const Order order,
    2503             :                                          const unsigned int i,
    2504             :                                          const unsigned int j,
    2505             :                                          const Point & p,
    2506             :                                          const bool add_p_level)
    2507             : {
    2508   370755744 :   return fe_fdm_second_deriv(elem, order, i, j, p, add_p_level,
    2509    30645762 :                              FE<3,T>::shape_deriv);
    2510             : }
    2511             : 
    2512             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
    2513             : 
    2514             : 
    2515             : } // anonymous namespace

Generated by: LCOV version 1.14