LCOV - code coverage report
Current view: top level - include/fe - fe_lagrange_gll_shape.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4583 (689827) with base 9e5b0b Lines: 29 31 93.5 %
Date: 2026-10-16 15:05:09 Functions: 7 7 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             : 
      19             : #ifndef LIBMESH_FE_LAGRANGE_GLL_SHAPE_H
      20             : #define LIBMESH_FE_LAGRANGE_GLL_SHAPE_H
      21             : 
      22             : // Local includes
      23             : #include "libmesh/enum_fe_family.h"
      24             : #include "libmesh/enum_order.h"
      25             : #include "libmesh/fe_lagrange_gll_shape_1D.h"
      26             : #include "libmesh/int_range.h"
      27             : 
      28             : // Tensor product evaluation shared by the Gauss-Lobatto nodal families. The families differ
      29             : // only in how a shape function index maps to a tensor index, so each family specializes
      30             : // fe_lagrange_gll_tensor_index and shares the rest.
      31             : 
      32             : namespace libMesh
      33             : {
      34             : 
      35             : /**
      36             :  * The pair of coordinates differentiated by each second derivative index \p j of
      37             :  * FE::shape_second_deriv().
      38             :  *
      39             :  * In dimension d only the first \f$d(d+1)/2\f$ entries are used: one on an edge, three on
      40             :  * a face, and all six on a cell.
      41             :  */
      42             : constexpr unsigned int fe_lagrange_gll_second_deriv_pairs[6][2] =
      43             :   {{0, 0},   // d^2 phi / dxi^2
      44             :    {0, 1},   // d^2 phi / dxi deta
      45             :    {1, 1},   // d^2 phi / deta^2
      46             :    {0, 2},   // d^2 phi / dxi dzeta
      47             :    {1, 2},   // d^2 phi / deta dzeta
      48             :    {2, 2}};  // d^2 phi / dzeta^2
      49             : 
      50             : 
      51             : /**
      52             :  * \returns The number of distinct second derivatives in dimension \p Dim.
      53             :  */
      54             : template <unsigned int Dim>
      55    16100376 : constexpr unsigned int fe_lagrange_gll_n_second_derivs()
      56             : {
      57    16100376 :   return Dim * (Dim + 1) / 2;
      58             : }
      59             : 
      60             : /**
      61             :  * Writes the tensor index of shape function \p i of order \p order into the first \p dim
      62             :  * entries of \p indices. Entry d is the index of the one-dimensional shape function in
      63             :  * coordinate d.
      64             :  *
      65             :  * Each Gauss-Lobatto nodal family specializes this function. Using a family without a
      66             :  * specialization is a link error.
      67             :  */
      68             : template <FEFamily T>
      69             : void fe_lagrange_gll_tensor_index(const Elem * elem,
      70             :                                   const Order order,
      71             :                                   const unsigned int dim,
      72             :                                   const unsigned int i,
      73             :                                   unsigned int * indices);
      74             : 
      75             : 
      76             : /**
      77             :  * All L2_LAGRANGE_GLL degrees of freedom belong to the element. They are numbered
      78             :  * lexicographically over the tensor grid, with the first coordinate varying fastest. QBase
      79             :  * orders the points of a tensor product rule the same way, so shape function i is the one
      80             :  * that is one at quadrature point i. The numbering doesn't depend on the element, so the
      81             :  * element argument is unused.
      82             :  */
      83             : template <>
      84    28167913 : inline void fe_lagrange_gll_tensor_index<L2_LAGRANGE_GLL>(const Elem *,
      85             :                                                           const Order order,
      86             :                                                           const unsigned int dim,
      87             :                                                           const unsigned int i,
      88             :                                                           unsigned int * indices)
      89             : {
      90   309847043 :   const unsigned int n = static_cast<unsigned int>(order) + 1;
      91             : 
      92    28167913 :   unsigned int stride = 1;
      93             : 
      94  1344336084 :   for (const auto d : make_range(dim))
      95             :     {
      96  1006321128 :       indices[d] = (i / stride) % n;
      97  1006321128 :       stride *= n;
      98             :     }
      99             : 
     100    28167913 :   libmesh_assert_less (i, stride);
     101    28167913 : }
     102             : 
     103             : /**
     104             :  * \returns Shape function \p i of family \p T in dimension \p Dim, differentiated once
     105             :  * with respect to each coordinate listed in the first \p n_deriv_coords entries of
     106             :  * \p deriv_coords.
     107             :  *
     108             :  * Each factor of the tensor product is a one-dimensional shape function, differentiated as
     109             :  * many times as its coordinate is listed. FE::shape() passes zero coordinates,
     110             :  * FE::shape_deriv() passes one, and FE::shape_second_deriv() passes two.
     111             :  */
     112             : template <FEFamily T, unsigned int Dim>
     113   338014956 : inline Real fe_lagrange_gll_tensor_product(const Elem * elem,
     114             :                                            const Order order,
     115             :                                            const unsigned int i,
     116             :                                            const Point & p,
     117             :                                            const unsigned int * const deriv_coords,
     118             :                                            const unsigned int n_deriv_coords)
     119             : {
     120             :   unsigned int indices[3];
     121             : 
     122    28167913 :   fe_lagrange_gll_tensor_index<T>(elem, order, Dim, i, indices);
     123             : 
     124    28167913 :   Real value = 1.;
     125             : 
     126  1344336084 :   for (const auto d : make_range(Dim))
     127             :     {
     128    83860094 :       unsigned int deriv_order = 0;
     129  2448521160 :       for (const auto k : make_range(n_deriv_coords))
     130  1442200032 :         if (deriv_coords[k] == d)
     131   483542352 :           ++deriv_order;
     132             : 
     133  1006321128 :       switch (deriv_order)
     134             :         {
     135   619912104 :         case 0:
     136   619912104 :           value *= fe_lagrange_gll_1D_shape(order, indices[d], p(d));
     137   619912104 :           break;
     138             : 
     139   289275696 :         case 1:
     140   289275696 :           value *= fe_lagrange_gll_1D_shape_deriv(order, indices[d], 0, p(d));
     141   289275696 :           break;
     142             : 
     143             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     144    97133328 :         case 2:
     145    97133328 :           value *= fe_lagrange_gll_1D_shape_second_deriv(order, indices[d], 0, p(d));
     146    97133328 :           break;
     147             : #endif
     148             : 
     149           0 :         default:
     150           0 :           libmesh_error_msg("Invalid derivative order " << deriv_order << ".");
     151             :         }
     152             :     }
     153             : 
     154   338014956 :   return value;
     155             : }
     156             : 
     157             : } // namespace libMesh
     158             : 
     159             : #endif // LIBMESH_FE_LAGRANGE_GLL_SHAPE_H

Generated by: LCOV version 1.14