LCOV - code coverage report
Current view: top level - include/fe - fe_reference_element_traits.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4554 (5a536d) with base 54e0d5 Lines: 2 2 100.0 %
Date: 2026-09-16 12:37:14 Functions: 12 12 100.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             : // Reference-element topology and node locations shared between the host
      19             : // element classes and Kokkos device code: constexpr side/edge tables and
      20             : // lookups, with second-order side rows and higher-order node coordinates
      21             : // derived from the stored linear facts.
      22             : 
      23             : #ifndef LIBMESH_FE_REFERENCE_ELEMENT_TRAITS_H
      24             : #define LIBMESH_FE_REFERENCE_ELEMENT_TRAITS_H
      25             : 
      26             : #include "libmesh/enum_elem_type.h"
      27             : #include "libmesh/libmesh.h"
      28             : #include "libmesh/libmesh_device.h"
      29             : #include "libmesh/point.h"
      30             : 
      31             : namespace libMesh
      32             : {
      33             : 
      34             : template <unsigned int N>
      35             : struct ReferenceElementVector
      36             : {
      37             :   unsigned int values[N];
      38             : 
      39             :   LIBMESH_DEVICE_INLINE constexpr unsigned int operator[](unsigned int i) const
      40             :   { return values[i]; }
      41             : };
      42             : 
      43             : template <unsigned int Rows, unsigned int Cols>
      44             : struct ReferenceElementTable
      45             : {
      46             :   using Row = unsigned int[Cols];
      47             : 
      48             :   Row values[Rows];
      49             : 
      50   359263658 :   LIBMESH_DEVICE_INLINE constexpr const Row & operator[](unsigned int i) const
      51   550847348 :   { return values[i]; }
      52             : 
      53             :   LIBMESH_DEVICE_INLINE constexpr unsigned int operator()(unsigned int i, unsigned int j) const
      54             :   { return values[i][j]; }
      55             : };
      56             : 
      57             : 
      58             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<5, 4>
      59             : prism6_side_nodes()
      60             : {
      61             :   return {{
      62             :     {0, 2, 1, 99},
      63             :     {0, 1, 4, 3},
      64             :     {1, 2, 5, 4},
      65             :     {2, 0, 3, 5},
      66             :     {3, 4, 5, 99}
      67             :   }};
      68             : }
      69             : 
      70             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<5, 4>
      71             : pyramid5_side_nodes()
      72             : {
      73             :   return {{
      74             :     {0, 1, 4, 99},
      75             :     {1, 2, 4, 99},
      76             :     {2, 3, 4, 99},
      77             :     {3, 0, 4, 99},
      78             :     {0, 3, 2, 1}
      79             :   }};
      80             : }
      81             : 
      82             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<3, 2>
      83             : tri3_side_nodes()
      84             : {
      85             :   return {{
      86             :     {0, 1},
      87             :     {1, 2},
      88             :     {2, 0}
      89             :   }};
      90             : }
      91             : 
      92             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<4, 2>
      93             : quad4_side_nodes()
      94             : {
      95             :   return {{
      96             :     {0, 1},
      97             :     {1, 2},
      98             :     {2, 3},
      99             :     {3, 0}
     100             :   }};
     101             : }
     102             : 
     103             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<4, 3>
     104             : tet4_side_nodes()
     105             : {
     106             :   return {{
     107             :     {0, 2, 1},
     108             :     {0, 1, 3},
     109             :     {1, 2, 3},
     110             :     {2, 0, 3}
     111             :   }};
     112             : }
     113             : 
     114             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<6, 4>
     115             : hex8_side_nodes()
     116             : {
     117             :   return {{
     118             :     {0, 3, 2, 1},
     119             :     {0, 1, 5, 4},
     120             :     {1, 2, 6, 5},
     121             :     {2, 3, 7, 6},
     122             :     {3, 0, 4, 7},
     123             :     {4, 5, 6, 7}
     124             :   }};
     125             : }
     126             : 
     127             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<6, 3>
     128             : tet_edge_nodes()
     129             : {
     130             :   return {{
     131             :     {0, 1, 4},
     132             :     {1, 2, 5},
     133             :     {0, 2, 6},
     134             :     {0, 3, 7},
     135             :     {1, 3, 8},
     136             :     {2, 3, 9}
     137             :   }};
     138             : }
     139             : 
     140             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<12, 3>
     141             : hex_edge_nodes()
     142             : {
     143             :   return {{
     144             :     {0, 1, 8},
     145             :     {1, 2, 9},
     146             :     {2, 3, 10},
     147             :     {0, 3, 11},
     148             :     {0, 4, 12},
     149             :     {1, 5, 13},
     150             :     {2, 6, 14},
     151             :     {3, 7, 15},
     152             :     {4, 5, 16},
     153             :     {5, 6, 17},
     154             :     {6, 7, 18},
     155             :     {4, 7, 19}
     156             :   }};
     157             : }
     158             : 
     159             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<9, 3>
     160             : prism_edge_nodes()
     161             : {
     162             :   return {{
     163             :     {0, 1, 6},
     164             :     {1, 2, 7},
     165             :     {0, 2, 8},
     166             :     {0, 3, 9},
     167             :     {1, 4, 10},
     168             :     {2, 5, 11},
     169             :     {3, 4, 12},
     170             :     {4, 5, 13},
     171             :     {3, 5, 14}
     172             :   }};
     173             : }
     174             : 
     175             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<8, 3>
     176             : pyramid_edge_nodes()
     177             : {
     178             :   return {{
     179             :     {0, 1, 5},
     180             :     {1, 2, 6},
     181             :     {2, 3, 7},
     182             :     {0, 3, 8},
     183             :     {0, 4, 9},
     184             :     {1, 4, 10},
     185             :     {2, 4, 11},
     186             :     {3, 4, 12}
     187             :   }};
     188             : }
     189             : 
     190             : LIBMESH_DEVICE_INLINE bool
     191             : requires_side_specific_topology(ElemType parent)
     192             : {
     193             :   switch (parent)
     194             :   {
     195             :     case PRISM6:
     196             :     case PRISM15:
     197             :     case PRISM18:
     198             :     case PRISM20:
     199             :     case PRISM21:
     200             :     case PYRAMID5:
     201             :     case PYRAMID13:
     202             :     case PYRAMID14:
     203             :     case PYRAMID18:
     204             :       return true;
     205             :     default:
     206             :       return false;
     207             :   }
     208             : }
     209             : 
     210             : LIBMESH_DEVICE_INLINE ElemType
     211             : side_topology_or_invalid(ElemType parent,
     212             :                          unsigned int side)
     213             : {
     214             :   if (side > 4)
     215             :     return INVALID_ELEM;
     216             : 
     217             :   // Prism sides 0 and 4 are the triangles; pyramid side 4 is the quad base.
     218             :   // Every other supported element has the same topology on all its sides.
     219             :   const bool prism_tri = (side == 0 || side == 4);
     220             :   const bool pyramid_tri = (side != 4);
     221             : 
     222             :   switch (parent)
     223             :   {
     224             :     case EDGE2:
     225             :     case EDGE3:
     226             :     case EDGE4:
     227             :       return NODEELEM;
     228             :     case TRI3:
     229             :     case QUAD4:
     230             :       return EDGE2;
     231             :     case TRI6:
     232             :     case TRI7:
     233             :     case QUAD8:
     234             :     case QUAD9:
     235             :       return EDGE3;
     236             :     case TET4:
     237             :       return TRI3;
     238             :     case HEX8:
     239             :       return QUAD4;
     240             :     case TET10:
     241             :       return TRI6;
     242             :     case TET14:
     243             :       return TRI7;
     244             :     case HEX20:
     245             :       return QUAD8;
     246             :     case HEX27:
     247             :       return QUAD9;
     248             :     case PRISM6:
     249             :       return prism_tri ? TRI3 : QUAD4;
     250             :     case PRISM15:
     251             :       return prism_tri ? TRI6 : QUAD8;
     252             :     case PRISM18:
     253             :       return prism_tri ? TRI6 : QUAD9;
     254             :     case PRISM20:
     255             :     case PRISM21:
     256             :       return prism_tri ? TRI7 : QUAD9;
     257             :     case PYRAMID5:
     258             :       return pyramid_tri ? TRI3 : QUAD4;
     259             :     case PYRAMID13:
     260             :       return pyramid_tri ? TRI6 : QUAD8;
     261             :     case PYRAMID14:
     262             :       return pyramid_tri ? TRI6 : QUAD9;
     263             :     case PYRAMID18:
     264             :       return pyramid_tri ? TRI7 : QUAD9;
     265             :     default:
     266             :       return INVALID_ELEM;
     267             :   }
     268             : }
     269             : 
     270             : // Mid-side node counts are uniform per element type except for the
     271             : // prisms and pyramids, whose triangular and quadrilateral faces differ.
     272             : LIBMESH_DEVICE_INLINE constexpr unsigned int
     273             : side_node_count_or_zero(ElemType parent,
     274             :                         unsigned int side)
     275             : {
     276             :   switch (parent)
     277             :   {
     278             :     case EDGE2:
     279             :     case EDGE3:
     280             :     case EDGE4:
     281             :       return side < 2 ? 1 : 0;
     282             :     case TRI3:
     283             :     case TRISHELL3:
     284             :       return side < 3 ? 2 : 0;
     285             :     case TRI6:
     286             :     case TRI7:
     287             :       return side < 3 ? 3 : 0;
     288             :     case QUAD4:
     289             :     case QUADSHELL4:
     290             :       return side < 4 ? 2 : 0;
     291             :     case QUAD8:
     292             :     case QUADSHELL8:
     293             :     case QUAD9:
     294             :     case QUADSHELL9:
     295             :       return side < 4 ? 3 : 0;
     296             :     case TET4:
     297             :       return side < 4 ? 3 : 0;
     298             :     case TET10:
     299             :       return side < 4 ? 6 : 0;
     300             :     case TET14:
     301             :       return side < 4 ? 7 : 0;
     302             :     case HEX8:
     303             :       return side < 6 ? 4 : 0;
     304             :     case HEX20:
     305             :       return side < 6 ? 8 : 0;
     306             :     case HEX27:
     307             :       return side < 6 ? 9 : 0;
     308             :     case PRISM6:
     309             :       return side < 5 ? ((side == 0 || side == 4) ? 3 : 4) : 0;
     310             :     case PRISM15:
     311             :       return side < 5 ? ((side == 0 || side == 4) ? 6 : 8) : 0;
     312             :     case PRISM18:
     313             :       return side < 5 ? ((side == 0 || side == 4) ? 6 : 9) : 0;
     314             :     case PRISM20:
     315             :     case PRISM21:
     316             :       return side < 5 ? ((side == 0 || side == 4) ? 7 : 9) : 0;
     317             :     case PYRAMID5:
     318             :       return side < 5 ? (side == 4 ? 4 : 3) : 0;
     319             :     case PYRAMID13:
     320             :       return side < 5 ? (side == 4 ? 8 : 6) : 0;
     321             :     case PYRAMID14:
     322             :       return side < 5 ? (side == 4 ? 9 : 6) : 0;
     323             :     case PYRAMID18:
     324             :       return side < 5 ? (side == 4 ? 9 : 7) : 0;
     325             :     default:
     326             :       return 0;
     327             :   }
     328             : }
     329             : 
     330             : // Every element type with edge nodes has 3 nodes (two vertices plus a
     331             : // midpoint) on each of its edges; only the edge count varies.  The edge
     332             : // tables cover the second-order families only: the linear elements'
     333             : // vertex-pair edges stay with their classes, which device code never
     334             : // queries.
     335             : LIBMESH_DEVICE_INLINE constexpr unsigned int
     336             : edge_node_count_or_zero(ElemType parent,
     337             :                         unsigned int edge)
     338             : {
     339             :   switch (parent)
     340             :   {
     341             :     case TET10:
     342             :     case TET14:
     343             :       return edge < 6 ? 3 : 0;
     344             :     case HEX20:
     345             :     case HEX27:
     346             :       return edge < 12 ? 3 : 0;
     347             :     case PRISM15:
     348             :     case PRISM18:
     349             :     case PRISM20:
     350             :     case PRISM21:
     351             :       return edge < 9 ? 3 : 0;
     352             :     case PYRAMID13:
     353             :     case PYRAMID14:
     354             :     case PYRAMID18:
     355             :       return edge < 8 ? 3 : 0;
     356             :     default:
     357             :       return 0;
     358             :   }
     359             : }
     360             : 
     361             : LIBMESH_DEVICE_INLINE constexpr bool
     362             : try_local_edge_node(ElemType parent,
     363             :                     unsigned int edge,
     364             :                     unsigned int edge_node,
     365             :                     unsigned int & node)
     366             : {
     367             :   const unsigned int count = edge_node_count_or_zero(parent, edge);
     368             :   if (!count || edge_node >= count)
     369             :     return false;
     370             : 
     371             :   switch (parent)
     372             :   {
     373             :     case TET10:
     374             :     case TET14:
     375             :       node = tet_edge_nodes()(edge, edge_node);
     376             :       return true;
     377             :     case HEX20:
     378             :     case HEX27:
     379             :       node = hex_edge_nodes()(edge, edge_node);
     380             :       return true;
     381             :     case PRISM15:
     382             :     case PRISM18:
     383             :     case PRISM20:
     384             :     case PRISM21:
     385             :       node = prism_edge_nodes()(edge, edge_node);
     386             :       return true;
     387             :     case PYRAMID13:
     388             :     case PYRAMID14:
     389             :     case PYRAMID18:
     390             :       node = pyramid_edge_nodes()(edge, edge_node);
     391             :       return true;
     392             :     default:
     393             :       return false;
     394             :   }
     395             : }
     396             : 
     397             : LIBMESH_DEVICE_INLINE constexpr ElemType
     398             : linear_sibling_or_invalid(ElemType type)
     399             : {
     400             :   switch (type)
     401             :   {
     402             :     case EDGE2:
     403             :     case EDGE3:
     404             :     case EDGE4:
     405             :       return EDGE2;
     406             :     case TRI3:
     407             :     case TRISHELL3:
     408             :     case TRI6:
     409             :     case TRI7:
     410             :       return TRI3;
     411             :     case QUAD4:
     412             :     case QUADSHELL4:
     413             :     case QUAD8:
     414             :     case QUADSHELL8:
     415             :     case QUAD9:
     416             :     case QUADSHELL9:
     417             :       return QUAD4;
     418             :     case TET4:
     419             :     case TET10:
     420             :     case TET14:
     421             :       return TET4;
     422             :     case HEX8:
     423             :     case HEX20:
     424             :     case HEX27:
     425             :       return HEX8;
     426             :     case PRISM6:
     427             :     case PRISM15:
     428             :     case PRISM18:
     429             :     case PRISM20:
     430             :     case PRISM21:
     431             :       return PRISM6;
     432             :     case PYRAMID5:
     433             :     case PYRAMID13:
     434             :     case PYRAMID14:
     435             :     case PYRAMID18:
     436             :       return PYRAMID5;
     437             :     default:
     438             :       return INVALID_ELEM;
     439             :   }
     440             : }
     441             : 
     442             : // The node id of a face's center node, for the element types that have them.
     443             : LIBMESH_DEVICE_INLINE constexpr unsigned int
     444             : face_center_node_or_invalid(ElemType type,
     445             :                             unsigned int side)
     446             : {
     447             :   switch (type)
     448             :   {
     449             :     case TET14:
     450             :       return side < 4 ? 10 + side : invalid_uint;
     451             :     case HEX27:
     452             :       return side < 6 ? 20 + side : invalid_uint;
     453             :     case PRISM18:
     454             :       return (side >= 1 && side <= 3) ? 14 + side : invalid_uint;
     455             :     case PRISM20:
     456             :     case PRISM21:
     457             :       return side == 0 ? 18 :
     458             :              side == 4 ? 19 :
     459             :              side <= 3 ? 14 + side : invalid_uint;
     460             :     case PYRAMID14:
     461             :       return side == 4 ? 13 : invalid_uint;
     462             :     case PYRAMID18:
     463             :       return side == 4 ? 13 :
     464             :              side < 4 ? 14 + side : invalid_uint;
     465             :     default:
     466             :       return invalid_uint;
     467             :   }
     468             : }
     469             : 
     470             : // Corner k of a linear element's side, from the stored linear tables.
     471             : LIBMESH_DEVICE_INLINE constexpr bool
     472             : try_linear_corner(ElemType linear,
     473             :                   unsigned int side,
     474             :                   unsigned int k,
     475             :                   unsigned int & node)
     476             : {
     477             :   switch (linear)
     478             :   {
     479             :     case EDGE2:
     480             :       node = side;
     481             :       return true;
     482             :     case TRI3:
     483             :       node = tri3_side_nodes()(side, k);
     484             :       return true;
     485             :     case QUAD4:
     486             :       node = quad4_side_nodes()(side, k);
     487             :       return true;
     488             :     case TET4:
     489             :       node = tet4_side_nodes()(side, k);
     490             :       return true;
     491             :     case HEX8:
     492             :       node = hex8_side_nodes()(side, k);
     493             :       return true;
     494             :     case PRISM6:
     495             :       node = prism6_side_nodes()(side, k);
     496             :       return true;
     497             :     case PYRAMID5:
     498             :       node = pyramid5_side_nodes()(side, k);
     499             :       return true;
     500             :     default:
     501             :       return false;
     502             :   }
     503             : }
     504             : 
     505             : // The mid-edge node of the edge joining vertices a and b, if any.
     506             : LIBMESH_DEVICE_INLINE constexpr bool
     507             : try_edge_mid_between(ElemType parent,
     508             :                      unsigned int a,
     509             :                      unsigned int b,
     510             :                      unsigned int & node)
     511             : {
     512             :   for (unsigned int e = 0; edge_node_count_or_zero(parent, e); ++e)
     513             :   {
     514             :     unsigned int v0 = 0, v1 = 0;
     515             :     if (try_local_edge_node(parent, e, 0, v0) &&
     516             :         try_local_edge_node(parent, e, 1, v1) &&
     517             :         ((v0 == a && v1 == b) || (v0 == b && v1 == a)))
     518             :       return try_local_edge_node(parent, e, 2, node);
     519             :   }
     520             :   return false;
     521             : }
     522             : 
     523             : // A second-order side row is fully determined by the linear sibling's
     524             : // corner row plus the element's edge table: the corners come first, then
     525             : // the midpoint of each consecutive corner pair (wrapping), then the face's
     526             : // center node where one exists.  Only the linear tables are stored; the
     527             : // second-order rows are derived, so the side and edge topologies cannot
     528             : // disagree.
     529             : LIBMESH_DEVICE_INLINE constexpr bool
     530             : derive_local_side_node(ElemType parent,
     531             :                        unsigned int side,
     532             :                        unsigned int side_node,
     533             :                        unsigned int & node)
     534             : {
     535             :   const unsigned int count = side_node_count_or_zero(parent, side);
     536             :   if (!count || side_node >= count)
     537             :     return false;
     538             : 
     539             :   const ElemType linear = linear_sibling_or_invalid(parent);
     540             :   const unsigned int corners = side_node_count_or_zero(linear, side);
     541             : 
     542             :   if (side_node < corners)
     543             :     return try_linear_corner(linear, side, side_node, node);
     544             : 
     545             :   // 2D second-order elements: the single mid-side node
     546             :   if (count == 3 && corners == 2)
     547             :   {
     548             :     node = (linear == TRI3 ? 3u : 4u) + side;
     549             :     return true;
     550             :   }
     551             : 
     552             :   // 3D mid-edge nodes
     553             :   if (side_node < 2 * corners)
     554             :   {
     555             :     unsigned int a = 0, b = 0;
     556             :     if (!try_linear_corner(linear, side, side_node - corners, a) ||
     557             :         !try_linear_corner(linear, side, (side_node - corners + 1) % corners, b))
     558             :       return false;
     559             :     return try_edge_mid_between(parent, a, b, node);
     560             :   }
     561             : 
     562             :   // face center
     563             :   node = face_center_node_or_invalid(parent, side);
     564             :   return node != invalid_uint;
     565             : }
     566             : 
     567             : // Materialize a type's full side-node table at compile time from the
     568             : // derivation above, so runtime lookups are direct indexing while the
     569             : // derivation remains the only authority (99 pads short rows, matching the
     570             : // stored linear tables).
     571             : template <unsigned int Rows, unsigned int Cols>
     572             : LIBMESH_DEVICE_INLINE constexpr ReferenceElementTable<Rows, Cols>
     573             : build_side_nodes(ElemType parent)
     574             : {
     575             :   ReferenceElementTable<Rows, Cols> t {};
     576             :   for (unsigned int r = 0; r != Rows; ++r)
     577             :     for (unsigned int c = 0; c != Cols; ++c)
     578             :       {
     579             :         unsigned int n = 99;
     580             :         derive_local_side_node(parent, r, c, n);
     581             :         t.values[r][c] = n;
     582             :       }
     583             :   return t;
     584             : }
     585             : 
     586             : LIBMESH_DEVICE_INLINE bool
     587             : try_local_side_node(ElemType parent,
     588             :                     unsigned int side,
     589             :                     unsigned int side_node,
     590             :                     unsigned int & node)
     591             : {
     592             :   const unsigned int count = side_node_count_or_zero(parent, side);
     593             :   if (!count || side_node >= count)
     594             :     return false;
     595             : 
     596             :   switch (parent)
     597             :   {
     598             :     case EDGE2:
     599             :     case EDGE3:
     600             :     case EDGE4:
     601             :       node = side;
     602             :       return true;
     603             :     case TRI3:
     604             :     case TRISHELL3:
     605             :       node = tri3_side_nodes()(side, side_node);
     606             :       return true;
     607             :     case QUAD4:
     608             :     case QUADSHELL4:
     609             :       node = quad4_side_nodes()(side, side_node);
     610             :       return true;
     611             :     case TET4:
     612             :       node = tet4_side_nodes()(side, side_node);
     613             :       return true;
     614             :     case HEX8:
     615             :       node = hex8_side_nodes()(side, side_node);
     616             :       return true;
     617             :     case PRISM6:
     618             :       node = prism6_side_nodes()(side, side_node);
     619             :       return true;
     620             :     case PYRAMID5:
     621             :       node = pyramid5_side_nodes()(side, side_node);
     622             :       return true;
     623             :     case TRI6:
     624             :     case TRI7:
     625             :     {
     626             :       constexpr auto t = build_side_nodes<3, 3>(TRI6);
     627             :       node = t(side, side_node);
     628             :       return true;
     629             :     }
     630             :     case QUAD8:
     631             :     case QUADSHELL8:
     632             :     case QUAD9:
     633             :     case QUADSHELL9:
     634             :     {
     635             :       constexpr auto t = build_side_nodes<4, 3>(QUAD8);
     636             :       node = t(side, side_node);
     637             :       return true;
     638             :     }
     639             :     case TET10:
     640             :     {
     641             :       constexpr auto t = build_side_nodes<4, 6>(TET10);
     642             :       node = t(side, side_node);
     643             :       return true;
     644             :     }
     645             :     case TET14:
     646             :     {
     647             :       constexpr auto t = build_side_nodes<4, 7>(TET14);
     648             :       node = t(side, side_node);
     649             :       return true;
     650             :     }
     651             :     case HEX20:
     652             :     {
     653             :       constexpr auto t = build_side_nodes<6, 8>(HEX20);
     654             :       node = t(side, side_node);
     655             :       return true;
     656             :     }
     657             :     case HEX27:
     658             :     {
     659             :       constexpr auto t = build_side_nodes<6, 9>(HEX27);
     660             :       node = t(side, side_node);
     661             :       return true;
     662             :     }
     663             :     case PRISM15:
     664             :     {
     665             :       constexpr auto t = build_side_nodes<5, 8>(PRISM15);
     666             :       node = t(side, side_node);
     667             :       return true;
     668             :     }
     669             :     case PRISM18:
     670             :     {
     671             :       constexpr auto t = build_side_nodes<5, 9>(PRISM18);
     672             :       node = t(side, side_node);
     673             :       return true;
     674             :     }
     675             :     case PRISM20:
     676             :     case PRISM21:
     677             :     {
     678             :       constexpr auto t = build_side_nodes<5, 9>(PRISM20);
     679             :       node = t(side, side_node);
     680             :       return true;
     681             :     }
     682             :     case PYRAMID13:
     683             :     {
     684             :       constexpr auto t = build_side_nodes<5, 8>(PYRAMID13);
     685             :       node = t(side, side_node);
     686             :       return true;
     687             :     }
     688             :     case PYRAMID14:
     689             :     {
     690             :       constexpr auto t = build_side_nodes<5, 9>(PYRAMID14);
     691             :       node = t(side, side_node);
     692             :       return true;
     693             :     }
     694             :     case PYRAMID18:
     695             :     {
     696             :       constexpr auto t = build_side_nodes<5, 9>(PYRAMID18);
     697             :       node = t(side, side_node);
     698             :       return true;
     699             :     }
     700             :     default:
     701             :       return false;
     702             :   }
     703             : }
     704             : 
     705             : // Reference-element vertex locations, per family (higher-order family
     706             : // members share their linear sibling's vertices).
     707             : LIBMESH_DEVICE_INLINE unsigned int
     708             : reference_vertex_count(ElemType type)
     709             : {
     710             :   switch (type)
     711             :   {
     712             :     case EDGE2:
     713             :     case EDGE3:
     714             :     case EDGE4:
     715             :       return 2;
     716             :     case TRI3:
     717             :     case TRISHELL3:
     718             :     case TRI6:
     719             :     case TRI7:
     720             :       return 3;
     721             :     case QUAD4:
     722             :     case QUADSHELL4:
     723             :     case QUAD8:
     724             :     case QUADSHELL8:
     725             :     case QUAD9:
     726             :     case QUADSHELL9:
     727             :     case TET4:
     728             :     case TET10:
     729             :     case TET14:
     730             :       return 4;
     731             :     case PYRAMID5:
     732             :     case PYRAMID13:
     733             :     case PYRAMID14:
     734             :     case PYRAMID18:
     735             :       return 5;
     736             :     case PRISM6:
     737             :     case PRISM15:
     738             :     case PRISM18:
     739             :     case PRISM20:
     740             :     case PRISM21:
     741             :       return 6;
     742             :     case HEX8:
     743             :     case HEX20:
     744             :     case HEX27:
     745             :       return 8;
     746             :     default:
     747             :       return 0;
     748             :   }
     749             : }
     750             : 
     751             : LIBMESH_DEVICE_INLINE bool
     752             : reference_vertex(ElemType type,
     753             :                  unsigned int v,
     754             :                  Point & pt)
     755             : {
     756             :   if (v >= reference_vertex_count(type))
     757             :     return false;
     758             : 
     759             :   switch (type)
     760             :   {
     761             :     case EDGE2:
     762             :     case EDGE3:
     763             :     case EDGE4:
     764             :       pt = Point(v == 0 ? -1.0 : 1.0);
     765             :       return true;
     766             :     case TRI3:
     767             :     case TRISHELL3:
     768             :     case TRI6:
     769             :     case TRI7:
     770             :       pt = Point(v == 1 ? 1.0 : 0.0, v == 2 ? 1.0 : 0.0);
     771             :       return true;
     772             :     case QUAD4:
     773             :     case QUADSHELL4:
     774             :     case QUAD8:
     775             :     case QUADSHELL8:
     776             :     case QUAD9:
     777             :     case QUADSHELL9:
     778             :       pt = Point((v == 1 || v == 2) ? 1.0 : -1.0,
     779             :                  (v == 2 || v == 3) ? 1.0 : -1.0);
     780             :       return true;
     781             :     case TET4:
     782             :     case TET10:
     783             :     case TET14:
     784             :       pt = Point(v == 1 ? 1.0 : 0.0, v == 2 ? 1.0 : 0.0, v == 3 ? 1.0 : 0.0);
     785             :       return true;
     786             :     case PYRAMID5:
     787             :     case PYRAMID13:
     788             :     case PYRAMID14:
     789             :     case PYRAMID18:
     790             :       pt = v == 4 ? Point(0.0, 0.0, 1.0)
     791             :                   : Point((v == 1 || v == 2) ? 1.0 : -1.0,
     792             :                           (v == 2 || v == 3) ? 1.0 : -1.0,
     793             :                           0.0);
     794             :       return true;
     795             :     case PRISM6:
     796             :     case PRISM15:
     797             :     case PRISM18:
     798             :     case PRISM20:
     799             :     case PRISM21:
     800             :       pt = Point(v % 3 == 1 ? 1.0 : 0.0,
     801             :                  v % 3 == 2 ? 1.0 : 0.0,
     802             :                  v < 3 ? -1.0 : 1.0);
     803             :       return true;
     804             :     case HEX8:
     805             :     case HEX20:
     806             :     case HEX27:
     807             :       pt = Point((v % 4 == 1 || v % 4 == 2) ? 1.0 : -1.0,
     808             :                  (v % 4 == 2 || v % 4 == 3) ? 1.0 : -1.0,
     809             :                  v < 4 ? -1.0 : 1.0);
     810             :       return true;
     811             :     default:
     812             :       return false;
     813             :   }
     814             : }
     815             : 
     816             : // The node holding an element's vertex-centroid, if it has one.
     817             : LIBMESH_DEVICE_INLINE unsigned int
     818             : centroid_node_or_invalid(ElemType type)
     819             : {
     820             :   switch (type)
     821             :   {
     822             :     case EDGE3:
     823             :       return 2;
     824             :     case TRI7:
     825             :       return 6;
     826             :     case QUAD9:
     827             :     case QUADSHELL9:
     828             :       return 8;
     829             :     case HEX27:
     830             :       return 26;
     831             :     case PRISM21:
     832             :       return 20;
     833             :     default:
     834             :       return invalid_uint;
     835             :   }
     836             : }
     837             : 
     838             : // Every higher-order reference node sits at the centroid of its
     839             : // subentity's vertices -- mid-edge nodes at edge midpoints, face nodes at
     840             : // face-corner centroids, interior nodes at the vertex centroid -- so only
     841             : // the vertices are tabulated and the rest is derived through the same
     842             : // side/edge topology tables everything else uses.  The one exception is
     843             : // the cubic EDGE4, whose two interior nodes trisect the edge.
     844             : LIBMESH_DEVICE_INLINE bool
     845             : try_reference_node(ElemType type,
     846             :                    unsigned int node,
     847             :                    Point & pt)
     848             : {
     849             :   const unsigned int nv = reference_vertex_count(type);
     850             :   if (node < nv)
     851             :     return reference_vertex(type, node, pt);
     852             : 
     853             :   if (type == EDGE4)
     854             :     {
     855             :       if (node > 3)
     856             :         return false;
     857             :       pt = Point(node == 2 ? Real(-1) / 3 : Real(1) / 3);
     858             :       return true;
     859             :     }
     860             : 
     861             :   if (node == centroid_node_or_invalid(type))
     862             :     {
     863             :       Point sum;
     864             :       for (unsigned int v = 0; v != nv; ++v)
     865             :         {
     866             :           Point pv;
     867             :           reference_vertex(type, v, pv);
     868             :           sum += pv;
     869             :         }
     870             :       pt = sum / Real(nv);
     871             :       return true;
     872             :     }
     873             : 
     874             :   // Mid-edge nodes: the third entry of an edge-table row {v0, v1, mid}.
     875             :   for (unsigned int e = 0; edge_node_count_or_zero(type, e); ++e)
     876             :     {
     877             :       unsigned int mid, v0, v1;
     878             :       if (try_local_edge_node(type, e, 2, mid) && mid == node &&
     879             :           try_local_edge_node(type, e, 0, v0) &&
     880             :           try_local_edge_node(type, e, 1, v1))
     881             :         {
     882             :           Point p0, p1;
     883             :           reference_vertex(type, v0, p0);
     884             :           reference_vertex(type, v1, p1);
     885             :           pt = (p0 + p1) / 2;
     886             :           return true;
     887             :         }
     888             :     }
     889             : 
     890             :   // 2D mid-side nodes ({v0, v1, mid} side rows) and 3D face-center nodes
     891             :   // (the last entry of a 7- or 9-node side row, behind 3 or 4 corners).
     892             :   for (unsigned int s = 0; ; ++s)
     893             :     {
     894             :       const unsigned int count = side_node_count_or_zero(type, s);
     895             :       if (!count)
     896             :         break;
     897             :       const unsigned int corners =
     898             :         count == 3 ? 2 : count == 7 ? 3 : count == 9 ? 4 : 0;
     899             :       unsigned int last;
     900             :       if (!corners ||
     901             :           !try_local_side_node(type, s, count - 1, last) || last != node)
     902             :         continue;
     903             :       Point sum;
     904             :       for (unsigned int k = 0; k != corners; ++k)
     905             :         {
     906             :           unsigned int v;
     907             :           try_local_side_node(type, s, k, v);
     908             :           Point pv;
     909             :           reference_vertex(type, v, pv);
     910             :           sum += pv;
     911             :         }
     912             :       pt = sum / Real(corners);
     913             :       return true;
     914             :     }
     915             : 
     916             :   return false;
     917             : }
     918             : LIBMESH_DEVICE_INLINE bool
     919             : try_refspace_node(ElemType type,
     920             :                   unsigned int node,
     921             :                   Point & pt)
     922             : {
     923             :   switch (type)
     924             :   {
     925             :     case NODEELEM:
     926             :       if (!node)
     927             :       {
     928             :         pt = Point(0.0, 0.0, 0.0);
     929             :         return true;
     930             :       }
     931             :       return false;
     932             : 
     933             :     case TRISHELL3:
     934             :       return try_reference_node(TRI3, node, pt);
     935             : 
     936             :     case QUADSHELL4:
     937             :       return try_reference_node(QUAD4, node, pt);
     938             : 
     939             :     case QUADSHELL8:
     940             :       return try_reference_node(QUAD8, node, pt);
     941             : 
     942             :     case QUADSHELL9:
     943             :       return try_reference_node(QUAD9, node, pt);
     944             : 
     945             :     default:
     946             :       return try_reference_node(type, node, pt);
     947             :   }
     948             : }
     949             : 
     950             : LIBMESH_DEVICE_INLINE bool
     951             : try_reference_side_node(ElemType parent,
     952             :                         unsigned int side,
     953             :                         unsigned int side_node,
     954             :                         Point & pt)
     955             : {
     956             :   unsigned int node = libMesh::invalid_uint;
     957             :   if (!try_local_side_node(parent, side, side_node, node))
     958             :     return false;
     959             : 
     960             :   return try_reference_node(parent, node, pt);
     961             : }
     962             : 
     963             : } // namespace libMesh
     964             : 
     965             : #endif // LIBMESH_FE_REFERENCE_ELEMENT_TRAITS_H

Generated by: LCOV version 1.14