LCOV - code coverage report
Current view: top level - src/fe - inf_fe_static.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 203 630 32.2 %
Date: 2025-08-19 19:27:09 Functions: 10 300 3.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 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             : #include "libmesh/libmesh_config.h"
      20             : 
      21             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
      22             : 
      23             : // libmesh includes
      24             : #include "libmesh/inf_fe.h"
      25             : #include "libmesh/inf_fe_macro.h"
      26             : #include "libmesh/fe.h"
      27             : #include "libmesh/fe_interface.h"
      28             : #include "libmesh/fe_compute_data.h"
      29             : #include "libmesh/elem.h"
      30             : #include "libmesh/enum_to_string.h"
      31             : 
      32             : #include "libmesh/remote_elem.h"
      33             : 
      34             : // to fetch NodeConstraintRow:
      35             : #include "libmesh/dof_map.h"
      36             : 
      37             : namespace libMesh
      38             : {
      39             : 
      40             : 
      41             : // ------------------------------------------------------------
      42             : // InfFE class static member initialization
      43             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      44             : ElemType InfFE<Dim,T_radial,T_map>::_compute_node_indices_fast_current_elem_type = INVALID_ELEM;
      45             : 
      46             : #ifdef DEBUG
      47             : 
      48             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      49             : bool InfFE<Dim,T_radial,T_map>::_warned_for_nodal_soln = false;
      50             : 
      51             : 
      52             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      53             : bool InfFE<Dim,T_radial,T_map>::_warned_for_shape      = false;
      54             : 
      55             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      56             : bool InfFE<Dim,T_radial,T_map>::_warned_for_dshape     = false;
      57             : 
      58             : #endif
      59             : 
      60             : 
      61             : 
      62             : 
      63             : // ------------------------------------------------------------
      64             : // InfFE static class members
      65             : #ifdef LIBMESH_ENABLE_DEPRECATED
      66             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      67           0 : unsigned int InfFE<Dim,T_radial,T_map>::n_dofs (const FEType & fet,
      68             :                                                 const ElemType inf_elem_type)
      69             : {
      70             :   libmesh_deprecated();
      71             : 
      72           0 :   const ElemType base_et (InfFEBase::get_elem_type(inf_elem_type));
      73             : 
      74             :   if (Dim > 1)
      75           0 :     return FEInterface::n_dofs(Dim-1, fet, base_et) *
      76           0 :       InfFERadial::n_dofs(fet.radial_order);
      77             :   else
      78           0 :     return InfFERadial::n_dofs(fet.radial_order);
      79             : }
      80             : #endif // LIBMESH_ENABLE_DEPRECATED
      81             : 
      82             : 
      83             : 
      84             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      85      227358 : unsigned int InfFE<Dim,T_radial,T_map>::n_dofs(const FEType & fet,
      86             :                                                const Elem * inf_elem)
      87             : {
      88             :   // The "base" Elem is a non-infinite Elem corresponding to side 0 of
      89             :   // the InfElem.
      90      153042 :   auto base_elem = inf_elem->build_side_ptr(0);
      91             : 
      92             :   if (Dim > 1)
      93      227358 :     return FEInterface::n_dofs(fet, base_elem.get()) *
      94      301674 :       InfFERadial::n_dofs(fet.radial_order);
      95             :   else
      96           0 :     return InfFERadial::n_dofs(fet.radial_order);
      97       74460 : }
      98             : 
      99             : 
     100             : 
     101             : #ifdef LIBMESH_ENABLE_DEPRECATED
     102             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     103           0 : unsigned int InfFE<Dim,T_radial,T_map>::n_dofs_at_node (const FEType & fet,
     104             :                                                         const ElemType inf_elem_type,
     105             :                                                         const unsigned int n)
     106             : {
     107             :   libmesh_deprecated();
     108             : 
     109           0 :   const ElemType base_et (InfFEBase::get_elem_type(inf_elem_type));
     110             : 
     111             :   unsigned int n_base, n_radial;
     112           0 :   compute_node_indices(inf_elem_type, n, n_base, n_radial);
     113             : 
     114             :   //   libMesh::out << "elem_type=" << inf_elem_type
     115             :   //     << ",  fet.radial_order=" << fet.radial_order
     116             :   //     << ",  n=" << n
     117             :   //     << ",  n_radial=" << n_radial
     118             :   //     << ",  n_base=" << n_base
     119             :   //     << std::endl;
     120             : 
     121             :   if (Dim > 1)
     122           0 :     return FEInterface::n_dofs_at_node(Dim-1, fet, base_et, n_base)
     123           0 :       * InfFERadial::n_dofs_at_node(fet.radial_order, n_radial);
     124             :   else
     125           0 :     return InfFERadial::n_dofs_at_node(fet.radial_order, n_radial);
     126             : }
     127             : #endif // LIBMESH_ENABLE_DEPRECATED
     128             : 
     129             : 
     130             : 
     131             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     132      259000 : unsigned int InfFE<Dim,T_radial,T_map>::n_dofs_at_node (const FEType & fet,
     133             :                                                         const Elem * inf_elem,
     134             :                                                         const unsigned int n)
     135             : {
     136             :   // The "base" Elem is a non-infinite Elem corresponding to side 0 of
     137             :   // the InfElem.
     138      160672 :   auto base_elem = inf_elem->build_side_ptr(0);
     139             : 
     140             :   unsigned int n_base, n_radial;
     141      259000 :   compute_node_indices(inf_elem->type(), n, n_base, n_radial);
     142             : 
     143             :   if (Dim > 1)
     144      259000 :     return FEInterface::n_dofs_at_node(fet, base_elem.get(), n_base)
     145      259000 :       * InfFERadial::n_dofs_at_node(fet.radial_order, n_radial);
     146             :   else
     147           0 :     return InfFERadial::n_dofs_at_node(fet.radial_order, n_radial);
     148       62392 : }
     149             : 
     150             : 
     151             : 
     152             : #ifdef LIBMESH_ENABLE_DEPRECATED
     153             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     154           0 : unsigned int InfFE<Dim,T_radial,T_map>::n_dofs_per_elem (const FEType & fet,
     155             :                                                          const ElemType inf_elem_type)
     156             : {
     157             :   libmesh_deprecated();
     158             : 
     159           0 :   const ElemType base_et (InfFEBase::get_elem_type(inf_elem_type));
     160             : 
     161             :   if (Dim > 1)
     162           0 :     return FEInterface::n_dofs_per_elem(Dim-1, fet, base_et)
     163           0 :       * InfFERadial::n_dofs_per_elem(fet.radial_order);
     164             :   else
     165           0 :     return InfFERadial::n_dofs_per_elem(fet.radial_order);
     166             : }
     167             : #endif // LIBMESH_ENABLE_DEPRECATED
     168             : 
     169             : 
     170             : 
     171             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     172       22806 : unsigned int InfFE<Dim,T_radial,T_map>::n_dofs_per_elem (const FEType & fet,
     173             :                                                          const Elem * inf_elem)
     174             : {
     175             :   // The "base" Elem is a non-infinite Elem corresponding to side 0 of
     176             :   // the InfElem.
     177       14260 :   auto base_elem = inf_elem->build_side_ptr(0);
     178             : 
     179             :   if (Dim > 1)
     180       22806 :     return FEInterface::n_dofs_per_elem(fet, base_elem.get())
     181       31352 :       * InfFERadial::n_dofs_per_elem(fet.radial_order);
     182             :   else
     183           0 :     return InfFERadial::n_dofs_per_elem(fet.radial_order);
     184        5720 : }
     185             : 
     186             : 
     187             : 
     188             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     189           0 : void InfFE<Dim,T_radial,T_map>::nodal_soln(const FEType & /* fet */,
     190             :                                            const Elem * /* elem */,
     191             :                                            const std::vector<Number> & /* elem_soln */,
     192             :                                            std::vector<Number> &       nodal_soln)
     193             : {
     194             : #ifdef DEBUG
     195           0 :   if (!_warned_for_nodal_soln)
     196             :     {
     197           0 :       libMesh::err << "WARNING: nodal_soln(...) does _not_ work for infinite elements." << std::endl
     198           0 :                    << " Will return an empty nodal solution.  Use " << std::endl
     199           0 :                    << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!" << std::endl;
     200           0 :       _warned_for_nodal_soln = true;
     201             :     }
     202             : #endif
     203             : 
     204             :   /*
     205             :    * In the base the infinite element couples to
     206             :    * conventional finite elements.  To not destroy
     207             :    * the values there, clear \p nodal_soln.  This
     208             :    * indicates to the user of \p nodal_soln to
     209             :    * not use this result.
     210             :    */
     211           0 :   nodal_soln.clear();
     212           0 :   libmesh_assert (nodal_soln.empty());
     213           0 :   return;
     214             : }
     215             : 
     216             : 
     217             : 
     218             : 
     219             : 
     220             : 
     221             : 
     222             : 
     223             : #ifdef LIBMESH_ENABLE_DEPRECATED
     224             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     225           0 : Real InfFE<Dim,T_radial,T_map>::shape(const FEType & fet,
     226             :                                       const ElemType inf_elem_type,
     227             :                                       const unsigned int i,
     228             :                                       const Point & p)
     229             : {
     230             :   libmesh_deprecated();
     231             : 
     232             :   libmesh_assert_not_equal_to (Dim, 0);
     233             : 
     234             : #ifdef DEBUG
     235             :   // this makes only sense when used for mapping
     236           0 :   if ((T_radial != INFINITE_MAP) && !_warned_for_shape)
     237             :     {
     238           0 :       libMesh::err << "WARNING: InfFE<Dim,T_radial,T_map>::shape(...) does _not_" << std::endl
     239           0 :                    << " return the correct trial function!  Use " << std::endl
     240           0 :                    << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!"
     241           0 :                    << std::endl;
     242           0 :       _warned_for_shape = true;
     243             :     }
     244             : #endif
     245             : 
     246           0 :   const ElemType     base_et  (InfFEBase::get_elem_type(inf_elem_type));
     247           0 :   const Order        o_radial (fet.radial_order);
     248           0 :   const Real         v        (p(Dim-1));
     249             : 
     250             :   unsigned int i_base, i_radial;
     251           0 :   compute_shape_indices(fet, inf_elem_type, i, i_base, i_radial);
     252             : 
     253             :   //TODO:[SP/DD]  exp(ikr) is still missing here!
     254             :   // but is it intended?  It would be probably somehow nice, but than it would be Number, not Real !
     255             :   // --> thus it would destroy the interface...
     256             :   if (Dim > 1)
     257           0 :     return FEInterface::shape(Dim-1, fet, base_et, i_base, p)
     258           0 :       * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     259           0 :       * InfFERadial::decay(Dim,v);
     260             :   else
     261           0 :     return InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     262           0 :       * InfFERadial::decay(Dim,v);
     263             : }
     264             : #endif // LIBMESH_ENABLE_DEPRECATED
     265             : 
     266             : 
     267             : 
     268             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     269           0 : Real InfFE<Dim,T_radial,T_map>::shape(const FEType & fet,
     270             :                                       const Elem * inf_elem,
     271             :                                       const unsigned int i,
     272             :                                       const Point & p)
     273             : {
     274           0 :   libmesh_assert(inf_elem);
     275             :   libmesh_assert_not_equal_to (Dim, 0);
     276             : 
     277             : #ifdef DEBUG
     278             :   // this makes only sense when used for mapping
     279           0 :   if ((T_radial != INFINITE_MAP) && !_warned_for_shape)
     280             :     {
     281           0 :       libMesh::err << "WARNING: InfFE<Dim,T_radial,T_map>::shape(...) does _not_" << std::endl
     282           0 :                    << " return the correct trial function!  Use " << std::endl
     283           0 :                    << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!"
     284           0 :                    << std::endl;
     285           0 :       _warned_for_shape = true;
     286             :     }
     287             : #endif
     288             : 
     289           0 :   const Order o_radial (fet.radial_order);
     290           0 :   const Real v (p(Dim-1));
     291           0 :   std::unique_ptr<const Elem> base_el (inf_elem->build_side_ptr(0));
     292             : 
     293             :   unsigned int i_base, i_radial;
     294           0 :   compute_shape_indices(fet, inf_elem, i, i_base, i_radial);
     295             : 
     296             :   if (Dim > 1)
     297           0 :     return FEInterface::shape(fet, base_el.get(), i_base, p)
     298           0 :       * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     299           0 :       * InfFERadial::decay(Dim,v);
     300             :   else
     301           0 :     return InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     302           0 :       * InfFERadial::decay(Dim,v);
     303           0 : }
     304             : 
     305             : 
     306             : 
     307             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     308           0 : Real InfFE<Dim,T_radial,T_map>::shape(const FEType fet,
     309             :                                       const Elem * inf_elem,
     310             :                                       const unsigned int i,
     311             :                                       const Point & p,
     312             :                                       const bool add_p_level)
     313             : {
     314           0 :   if (add_p_level)
     315             :     {
     316           0 :       FEType tmp_fet=fet;
     317           0 :       tmp_fet = fet.order + add_p_level * inf_elem->p_level();
     318           0 :       return InfFE<Dim,T_radial,T_map>::shape(tmp_fet, inf_elem, i, p);
     319             :     }
     320           0 :   return InfFE<Dim,T_radial,T_map>::shape(fet, inf_elem, i, p);
     321             : }
     322             : 
     323             : 
     324             : #ifdef LIBMESH_ENABLE_DEPRECATED
     325             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     326           0 : Real InfFE<Dim,T_radial,T_map>::shape_deriv (const FEType & fe_t,
     327             :                                              const ElemType inf_elem_type,
     328             :                                              const unsigned int i,
     329             :                                              const unsigned int j,
     330             :                                              const Point & p)
     331             : {
     332             :   libmesh_deprecated();
     333             : 
     334             :   libmesh_assert_not_equal_to (Dim, 0);
     335           0 :   libmesh_assert_greater (Dim,j);
     336             : #ifdef DEBUG
     337             :   // this makes only sense when used for mapping
     338           0 :   if ((T_radial != INFINITE_MAP) && !_warned_for_dshape)
     339             :     {
     340           0 :       libMesh::err << "WARNING: InfFE<Dim,T_radial,T_map>::shape_deriv(...) does _not_" << std::endl
     341           0 :                    << " return the correct trial function gradients!  Use " << std::endl
     342           0 :                    << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!"
     343           0 :                    << std::endl;
     344           0 :       _warned_for_dshape = true;
     345             :     }
     346             : #endif
     347             : 
     348           0 :   const ElemType     base_et  (InfFEBase::get_elem_type(inf_elem_type));
     349           0 :   const Order o_radial (fe_t.radial_order);
     350           0 :   const Real v (p(Dim-1));
     351             : 
     352             :   unsigned int i_base, i_radial;
     353           0 :   compute_shape_indices(fe_t, inf_elem_type, i, i_base, i_radial);
     354             : 
     355           0 :   if (j== Dim -1)
     356             :     {
     357           0 :       Real RadialDeriv = InfFE<Dim,T_radial,T_map>::eval_deriv(v, o_radial, i_radial)
     358           0 :         * InfFERadial::decay(Dim,v)
     359           0 :         + InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     360           0 :         * InfFERadial::decay_deriv(Dim, v);
     361             : 
     362           0 :       return FEInterface::shape(Dim-1, fe_t, base_et, i_base, p)*RadialDeriv;
     363             :     }
     364             : 
     365           0 :   return FEInterface::shape_deriv(Dim-1, fe_t, base_et, i_base, j, p)
     366           0 :     * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     367           0 :     * InfFERadial::decay(Dim,v);
     368             : }
     369             : #endif // LIBMESH_ENABLE_DEPRECATED
     370             : 
     371             : 
     372             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     373           0 : Real InfFE<Dim,T_radial,T_map>::shape_deriv (const FEType & fe_t,
     374             :                                              const Elem * inf_elem,
     375             :                                              const unsigned int i,
     376             :                                              const unsigned int j,
     377             :                                              const Point & p)
     378             : {
     379             :   libmesh_assert_not_equal_to (Dim, 0);
     380           0 :   libmesh_assert_greater (Dim,j);
     381             : #ifdef DEBUG
     382             :   // this makes only sense when used for mapping
     383           0 :   if ((T_radial != INFINITE_MAP) && !_warned_for_dshape)
     384             :     {
     385           0 :       libMesh::err << "WARNING: InfFE<Dim,T_radial,T_map>::shape_deriv(...) does _not_" << std::endl
     386           0 :                    << " return the correct trial function gradients!  Use " << std::endl
     387           0 :                    << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!"
     388           0 :                    << std::endl;
     389           0 :       _warned_for_dshape = true;
     390             :     }
     391             : #endif
     392           0 :   const Order o_radial (fe_t.radial_order);
     393           0 :   const Real v (p(Dim-1));
     394             : 
     395           0 :   std::unique_ptr<const Elem> base_el (inf_elem->build_side_ptr(0));
     396             : 
     397             :   unsigned int i_base, i_radial;
     398             : 
     399           0 :   if ((-1. > v ) || (v  > 1.))
     400             :     {
     401             :       //TODO: This is for debugging. We should never come here.
     402             :       //   Therefore we can do very useless things then:
     403           0 :       i_base=0;
     404             :     }
     405           0 :   compute_shape_indices(fe_t, inf_elem, i, i_base, i_radial);
     406             : 
     407           0 :   if (j== Dim -1)
     408             :     {
     409           0 :       Real RadialDeriv = InfFE<Dim,T_radial,T_map>::eval_deriv(v, o_radial, i_radial)
     410           0 :         * InfFERadial::decay(Dim,v)
     411           0 :         + InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     412           0 :         * InfFERadial::decay_deriv(Dim,v);
     413             : 
     414           0 :       return FEInterface::shape(fe_t, base_el.get(), i_base, p)*RadialDeriv;
     415             :     }
     416           0 :   return FEInterface::shape_deriv(fe_t, base_el.get(), i_base, j, p)
     417           0 :     * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     418           0 :     * InfFERadial::decay(Dim,v);
     419           0 : }
     420             : 
     421             : 
     422             : 
     423             : 
     424             : 
     425             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     426           0 : void InfFE<Dim,T_radial,T_map>::compute_data(const FEType & fet,
     427             :                                              const Elem * inf_elem,
     428             :                                              FEComputeData & data)
     429             : {
     430           0 :   libmesh_assert(inf_elem);
     431             :   libmesh_assert_not_equal_to (Dim, 0);
     432             : 
     433           0 :   const Order        o_radial             (fet.radial_order);
     434           0 :   const Order        radial_mapping_order (InfFERadial::mapping_order());
     435           0 :   const Point &      p                    (data.p);
     436           0 :   const Real         v                    (p(Dim-1));
     437           0 :   std::unique_ptr<const Elem> base_el (inf_elem->build_side_ptr(0));
     438             : 
     439             :   /*
     440             :    * compute \p interpolated_dist containing the mapping-interpolated
     441             :    * distance of the base point to the origin.  This is the same
     442             :    * for all shape functions.  Set \p interpolated_dist to 0, it
     443             :    * is added to.
     444             :    */
     445           0 :   Real interpolated_dist = 0.;
     446             :   switch (Dim)
     447             :     {
     448             :     case 1:
     449             :       {
     450           0 :         libmesh_assert_equal_to (inf_elem->type(), INFEDGE2);
     451           0 :         interpolated_dist =  Point(inf_elem->point(0) - inf_elem->point(1)).norm();
     452           0 :         break;
     453             :       }
     454             : 
     455             :     case 2:
     456             :       {
     457           0 :         const unsigned int n_base_nodes = base_el->n_nodes();
     458             : 
     459           0 :         const Point    origin                 = inf_elem->origin();
     460           0 :         const Order    base_mapping_order     (base_el->default_order());
     461           0 :         const ElemType base_mapping_elem_type (base_el->type());
     462             : 
     463             :         // interpolate the base nodes' distances
     464           0 :         for (unsigned int n=0; n<n_base_nodes; n++)
     465           0 :           interpolated_dist += Point(base_el->point(n) - origin).norm()
     466           0 :             * FE<1,LAGRANGE>::shape (base_mapping_elem_type, base_mapping_order, n, p);
     467           0 :         break;
     468             :       }
     469             : 
     470             :     case 3:
     471             :       {
     472           0 :         const unsigned int n_base_nodes = base_el->n_nodes();
     473             : 
     474           0 :         const Point    origin                 = inf_elem->origin();
     475           0 :         const Order    base_mapping_order     (base_el->default_order());
     476           0 :         const ElemType base_mapping_elem_type (base_el->type());
     477             : 
     478             :         // interpolate the base nodes' distances
     479           0 :         for (unsigned int n=0; n<n_base_nodes; n++)
     480           0 :           interpolated_dist += Point(base_el->point(n) - origin).norm()
     481           0 :             * FE<2,LAGRANGE>::shape (base_mapping_elem_type, base_mapping_order, n, p);
     482           0 :         break;
     483             :       }
     484             : 
     485             :     default:
     486             :       libmesh_error_msg("Unknown Dim = " << Dim);
     487             :     }
     488             : 
     489             : 
     490           0 :   const Real speed = data.speed;
     491             : 
     492             :   //TODO: I find it inconvenient to have a quantity phase which is phase/speed.
     493             :   //    But it might be better than redefining a quantities meaning.
     494           0 :   data.phase = interpolated_dist                                                      /* together with next line:  */
     495           0 :     * InfFE<Dim,INFINITE_MAP,T_map>::eval(v, radial_mapping_order, 1)/speed;          /* phase(s,t,v)/c            */
     496             : 
     497             :   // We assume time-harmonic behavior in this function!
     498             : 
     499             : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
     500             :   // the wave number
     501             :   const Number wavenumber = 2. * libMesh::pi * data.frequency / speed;
     502             : 
     503             :   // the exponent for time-harmonic behavior
     504             :   // \note: this form is much less general than the implementation of dphase, which can be easily extended to
     505             :   //     other forms than e^{i kr}.
     506             :   const Number exponent = imaginary                                                   /* imaginary unit            */
     507             :     * wavenumber                                                                      /* k  (can be complex)       */
     508             :     * data.phase*speed;
     509             : 
     510             :   const Number time_harmonic = exp(exponent);                                         /* e^(i*k*phase(s,t,v))      */
     511             : #else
     512           0 :   const Number time_harmonic = 1;
     513             : #endif //LIBMESH_USE_COMPLEX_NUMBERS
     514             : 
     515             :   /*
     516             :    * compute \p shape for all dof in the element
     517             :    */
     518             :   if (Dim > 1)
     519             :     {
     520           0 :       const unsigned int n_dof = n_dofs (fet, inf_elem);
     521           0 :       data.shape.resize(n_dof);
     522           0 :       if (data.need_derivative())
     523             :         {
     524           0 :           data.dshape.resize(n_dof);
     525           0 :           data.local_transform.resize(Dim);
     526             : 
     527           0 :           for (unsigned int d=0; d<Dim; d++)
     528           0 :             data.local_transform[d].resize(Dim);
     529             : 
     530             :           // compute the reference->physical map at the point \p p.
     531             :           // Use another fe_map to avoid interference with \p this->_fe_map
     532             :           // which is initialized at the quadrature points...
     533           0 :           auto fe = FEBase::build_InfFE(Dim, fet);
     534           0 :           std::vector<Point> pt = {p};
     535           0 :           fe->get_dxidx(); // to compute the map
     536           0 :           fe->reinit(inf_elem, &pt);
     537             : 
     538             :           // compute the reference->physical map.
     539           0 :           data.local_transform[0][0] = fe->get_dxidx()[0];
     540           0 :           data.local_transform[1][0] = fe->get_detadx()[0];
     541           0 :           data.local_transform[1][1] = fe->get_detady()[0];
     542           0 :           data.local_transform[0][1] = fe->get_dxidy()[0];
     543             :           if (Dim > 2)
     544             :             {
     545           0 :               data.local_transform[2][0] = fe->get_dzetadx()[0];
     546           0 :               data.local_transform[2][1] = fe->get_dzetady()[0];
     547           0 :               data.local_transform[2][2] = fe->get_dzetadz()[0];
     548           0 :               data.local_transform[1][2] = fe->get_detadz()[0];
     549           0 :               data.local_transform[0][2] = fe->get_dxidz()[0];
     550             :             }
     551           0 :         } // endif data.need_derivative()
     552             : 
     553           0 :       for (unsigned int i=0; i<n_dof; i++)
     554             :         {
     555             :           // compute base and radial shape indices
     556             :           unsigned int i_base, i_radial;
     557           0 :           compute_shape_indices(fet, inf_elem, i, i_base, i_radial);
     558             : 
     559           0 :           data.shape[i] = (InfFERadial::decay(Dim,v)                                    /* (1.-v)/2. in 3D          */
     560           0 :                            * FEInterface::shape(fet, base_el.get(), i_base, p)          /* S_n(s,t)                 */
     561           0 :                            * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial))    /* L_n(v)                   */
     562             :                            * time_harmonic;                                             /* e^(i*k*phase(s,t,v)      */
     563             : 
     564             :           // use differentiation of the above equation
     565           0 :           if (data.need_derivative())
     566             :             {
     567           0 :               data.dshape[i](0)     = (InfFERadial::decay(Dim,v)
     568           0 :                                        * FEInterface::shape_deriv(fet, base_el.get(), i_base, 0, p)
     569           0 :                                        * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial))
     570             :                                        * time_harmonic;
     571             : 
     572             :               if (Dim > 2)
     573             :                 {
     574           0 :                   data.dshape[i](1)   = (InfFERadial::decay(Dim,v)
     575           0 :                                          * FEInterface::shape_deriv(fet, base_el.get(), i_base, 1, p)
     576           0 :                                          * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial))
     577             :                                          * time_harmonic;
     578             : 
     579             :                 }
     580           0 :               data.dshape[i](Dim-1)  = (InfFERadial::decay_deriv(Dim, v) * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)
     581           0 :                                         +InfFERadial::decay(Dim,v) * InfFE<Dim,T_radial,T_map>::eval_deriv(v, o_radial, i_radial))
     582           0 :                                         * FEInterface::shape(fet, base_el.get(), i_base, p) * time_harmonic;
     583             : 
     584             : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
     585             :               // derivative of time_harmonic (works for harmonic behavior only):
     586             :               data.dshape[i](Dim-1)+= data.shape[i]*imaginary*wavenumber
     587           0 :                                       *interpolated_dist*InfFE<Dim,INFINITE_MAP,T_map>::eval_deriv(v, radial_mapping_order, 1);
     588             : 
     589             : #else
     590             :             /*
     591             :              * The gradient in infinite elements is dominated by the contribution due to the oscillating phase.
     592             :              * Since this term is imaginary, I think there is no means to look at it without having complex numbers.
     593             :              */
     594           0 :             libmesh_not_implemented();
     595             :             // Maybe we can solve it with a warning as well, but I think one really should not do this...
     596             : #endif
     597             :             }
     598             :         }
     599             :     }
     600             : 
     601             :   else
     602           0 :     libmesh_error_msg("compute_data() for 1-dimensional InfFE not implemented.");
     603           0 : }
     604             : 
     605             : 
     606             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     607           0 : Real InfFE<Dim,T_radial,T_map>::shape_deriv(const FEType fet,
     608             :                                             const Elem * inf_elem,
     609             :                                             const unsigned int i,
     610             :                                             const unsigned int j,
     611             :                                             const Point & p,
     612             :                                             const bool add_p_level)
     613             : {
     614           0 :   if (add_p_level)
     615             :     {
     616           0 :       FEType tmp_fet=fet;
     617           0 :       tmp_fet = fet.order + add_p_level * inf_elem->p_level();
     618           0 :       return InfFE<Dim,T_radial,T_map>::shape_deriv(tmp_fet, inf_elem, i, j, p);
     619             :     }
     620           0 :   return InfFE<Dim,T_radial,T_map>::shape_deriv(fet, inf_elem, i, j, p);
     621             : }
     622             : 
     623             : 
     624             : 
     625             : 
     626             : 
     627             : 
     628             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     629      259000 : void InfFE<Dim,T_radial,T_map>::compute_node_indices (const ElemType inf_elem_type,
     630             :                                                       const unsigned int outer_node_index,
     631             :                                                       unsigned int & base_node,
     632             :                                                       unsigned int & radial_node)
     633             : {
     634      259000 :   switch (inf_elem_type)
     635             :     {
     636           0 :     case INFEDGE2:
     637             :       {
     638           0 :         libmesh_assert_less (outer_node_index, 2);
     639           0 :         base_node   = 0;
     640           0 :         radial_node = outer_node_index;
     641           0 :         return;
     642             :       }
     643             : 
     644             : 
     645             :       // linear base approximation, easy to determine
     646           0 :     case INFQUAD4:
     647             :       {
     648           0 :         libmesh_assert_less (outer_node_index, 4);
     649           0 :         base_node   = outer_node_index % 2;
     650           0 :         radial_node = outer_node_index / 2;
     651           0 :         return;
     652             :       }
     653             : 
     654           0 :     case INFPRISM6:
     655             :       {
     656           0 :         libmesh_assert_less (outer_node_index, 6);
     657           0 :         base_node   = outer_node_index % 3;
     658           0 :         radial_node = outer_node_index / 3;
     659           0 :         return;
     660             :       }
     661             : 
     662      110520 :     case INFHEX8:
     663             :       {
     664       42436 :         libmesh_assert_less (outer_node_index, 8);
     665      110520 :         base_node   = outer_node_index % 4;
     666      110520 :         radial_node = outer_node_index / 4;
     667      110520 :         return;
     668             :       }
     669             : 
     670             : 
     671             :       // higher order base approximation, more work necessary
     672           0 :     case INFQUAD6:
     673             :       {
     674           0 :         switch (outer_node_index)
     675             :           {
     676           0 :           case 0:
     677             :           case 1:
     678             :             {
     679           0 :               radial_node = 0;
     680           0 :               base_node   = outer_node_index;
     681           0 :               return;
     682             :             }
     683             : 
     684           0 :           case 2:
     685             :           case 3:
     686             :             {
     687           0 :               radial_node = 1;
     688           0 :               base_node   = outer_node_index-2;
     689           0 :               return;
     690             :             }
     691             : 
     692           0 :           case 4:
     693             :             {
     694           0 :               radial_node = 0;
     695           0 :               base_node   = 2;
     696           0 :               return;
     697             :             }
     698             : 
     699           0 :           case 5:
     700             :             {
     701           0 :               radial_node = 1;
     702           0 :               base_node   = 2;
     703           0 :               return;
     704             :             }
     705             : 
     706           0 :           default:
     707           0 :             libmesh_error_msg("Unrecognized outer_node_index = " << outer_node_index);
     708             :           }
     709             :       }
     710             : 
     711             : 
     712       75260 :     case INFHEX16:
     713             :     case INFHEX18:
     714             :       {
     715       75260 :         switch (outer_node_index)
     716             :           {
     717       18416 :           case 0:
     718             :           case 1:
     719             :           case 2:
     720             :           case 3:
     721             :             {
     722       18416 :               radial_node = 0;
     723       18416 :               base_node   = outer_node_index;
     724       18416 :               return;
     725             :             }
     726             : 
     727       18704 :           case 4:
     728             :           case 5:
     729             :           case 6:
     730             :           case 7:
     731             :             {
     732       18704 :               radial_node = 1;
     733       18704 :               base_node   = outer_node_index-4;
     734       18704 :               return;
     735             :             }
     736             : 
     737       14826 :           case 8:
     738             :           case 9:
     739             :           case 10:
     740             :           case 11:
     741             :             {
     742       14826 :               radial_node = 0;
     743       14826 :               base_node   = outer_node_index-4;
     744       14826 :               return;
     745             :             }
     746             : 
     747       16092 :           case 12:
     748             :           case 13:
     749             :           case 14:
     750             :           case 15:
     751             :             {
     752       16092 :               radial_node = 1;
     753       16092 :               base_node   = outer_node_index-8;
     754       16092 :               return;
     755             :             }
     756             : 
     757        3716 :           case 16:
     758             :             {
     759        1283 :               libmesh_assert_equal_to (inf_elem_type, INFHEX18);
     760        3716 :               radial_node = 0;
     761        3716 :               base_node   = 8;
     762        3716 :               return;
     763             :             }
     764             : 
     765        3506 :           case 17:
     766             :             {
     767        1203 :               libmesh_assert_equal_to (inf_elem_type, INFHEX18);
     768        3506 :               radial_node = 1;
     769        3506 :               base_node   = 8;
     770        3506 :               return;
     771             :             }
     772             : 
     773           0 :           default:
     774           0 :             libmesh_error_msg("Unrecognized outer_node_index = " << outer_node_index);
     775             :           }
     776             :       }
     777             : 
     778             : 
     779       73220 :     case INFPRISM12:
     780             :       {
     781       73220 :         switch (outer_node_index)
     782             :           {
     783       20148 :           case 0:
     784             :           case 1:
     785             :           case 2:
     786             :             {
     787       20148 :               radial_node = 0;
     788       20148 :               base_node   = outer_node_index;
     789       20148 :               return;
     790             :             }
     791             : 
     792       20120 :           case 3:
     793             :           case 4:
     794             :           case 5:
     795             :             {
     796       20120 :               radial_node = 1;
     797       20120 :               base_node   = outer_node_index-3;
     798       20120 :               return;
     799             :             }
     800             : 
     801       16172 :           case 6:
     802             :           case 7:
     803             :           case 8:
     804             :             {
     805       16172 :               radial_node = 0;
     806       16172 :               base_node   = outer_node_index-3;
     807       16172 :               return;
     808             :             }
     809             : 
     810       16780 :           case 9:
     811             :           case 10:
     812             :           case 11:
     813             :             {
     814       16780 :               radial_node = 1;
     815       16780 :               base_node   = outer_node_index-6;
     816       16780 :               return;
     817             :             }
     818             : 
     819           0 :           default:
     820           0 :             libmesh_error_msg("Unrecognized outer_node_index = " << outer_node_index);
     821             :           }
     822             :       }
     823             : 
     824             : 
     825           0 :     default:
     826           0 :       libmesh_error_msg("ERROR: Bad infinite element type=" << Utility::enum_to_string(inf_elem_type) << ", node=" << outer_node_index);
     827             :     }
     828             : }
     829             : 
     830             : 
     831             : 
     832             : 
     833             : 
     834             : 
     835             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     836             : void InfFE<Dim,T_radial,T_map>::compute_node_indices_fast (const ElemType inf_elem_type,
     837             :                                                            const unsigned int outer_node_index,
     838             :                                                            unsigned int & base_node,
     839             :                                                            unsigned int & radial_node)
     840             : {
     841             :   libmesh_assert_not_equal_to (inf_elem_type, INVALID_ELEM);
     842             : 
     843             :   static std::vector<unsigned int> _static_base_node_index;
     844             :   static std::vector<unsigned int> _static_radial_node_index;
     845             : 
     846             :   /*
     847             :    * fast counterpart to compute_node_indices(), uses local static buffers
     848             :    * to store the index maps.  The class member
     849             :    * \p _compute_node_indices_fast_current_elem_type remembers
     850             :    * the current element type.
     851             :    *
     852             :    * Note that there exist non-static members storing the
     853             :    * same data.  However, you never know what element type
     854             :    * is currently used by the \p InfFE object, and what
     855             :    * request is currently directed to the static \p InfFE
     856             :    * members (which use \p compute_node_indices_fast()).
     857             :    * So separate these.
     858             :    *
     859             :    * check whether the work for this elemtype has already
     860             :    * been done.  If so, use this index.  Otherwise, refresh
     861             :    * the buffer to this element type.
     862             :    */
     863             :   if (inf_elem_type==_compute_node_indices_fast_current_elem_type)
     864             :     {
     865             :       base_node   = _static_base_node_index  [outer_node_index];
     866             :       radial_node = _static_radial_node_index[outer_node_index];
     867             :       return;
     868             :     }
     869             :   else
     870             :     {
     871             :       // store the map for _all_ nodes for this element type
     872             :       _compute_node_indices_fast_current_elem_type = inf_elem_type;
     873             : 
     874             :       unsigned int n_nodes = libMesh::invalid_uint;
     875             : 
     876             :       switch (inf_elem_type)
     877             :         {
     878             :         case INFEDGE2:
     879             :           {
     880             :             n_nodes = 2;
     881             :             break;
     882             :           }
     883             :         case INFQUAD4:
     884             :           {
     885             :             n_nodes = 4;
     886             :             break;
     887             :           }
     888             :         case INFQUAD6:
     889             :           {
     890             :             n_nodes = 6;
     891             :             break;
     892             :           }
     893             :         case INFHEX8:
     894             :           {
     895             :             n_nodes = 8;
     896             :             break;
     897             :           }
     898             :         case INFHEX16:
     899             :           {
     900             :             n_nodes = 16;
     901             :             break;
     902             :           }
     903             :         case INFHEX18:
     904             :           {
     905             :             n_nodes = 18;
     906             :             break;
     907             :           }
     908             :         case INFPRISM6:
     909             :           {
     910             :             n_nodes = 6;
     911             :             break;
     912             :           }
     913             :         case INFPRISM12:
     914             :           {
     915             :             n_nodes = 12;
     916             :             break;
     917             :           }
     918             :         default:
     919             :           libmesh_error_msg("ERROR: Bad infinite element type=" << Utility::enum_to_string(inf_elem_type) << ", node=" << outer_node_index);
     920             :         }
     921             : 
     922             : 
     923             :       _static_base_node_index.resize  (n_nodes);
     924             :       _static_radial_node_index.resize(n_nodes);
     925             : 
     926             :       for (unsigned int n=0; n<n_nodes; n++)
     927             :         compute_node_indices (inf_elem_type,
     928             :                               n,
     929             :                               _static_base_node_index  [outer_node_index],
     930             :                               _static_radial_node_index[outer_node_index]);
     931             : 
     932             :       // and return for the specified node
     933             :       base_node   = _static_base_node_index  [outer_node_index];
     934             :       radial_node = _static_radial_node_index[outer_node_index];
     935             :       return;
     936             :     }
     937             : }
     938             : 
     939             : 
     940             : 
     941             : 
     942             : 
     943             : 
     944             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     945       56871 : void InfFE<Dim,T_radial,T_map>::compute_shape_indices (const FEType & fet,
     946             :                                                        const Elem * inf_elem,
     947             :                                                        const unsigned int i,
     948             :                                                        unsigned int & base_shape,
     949             :                                                        unsigned int & radial_shape)
     950             : {
     951             :   // An example is provided:  the numbers in comments refer to
     952             :   // a fictitious InfHex18.  The numbers are chosen as exemplary
     953             :   // values.  There is currently no base approximation that
     954             :   // requires this many dof's at nodes, sides, faces and in the element.
     955             :   //
     956             :   // the order of the shape functions is heavily related with the
     957             :   // order the dofs are assigned in \p DofMap::distributed_dofs().
     958             :   // Due to the infinite elements with higher-order base approximation,
     959             :   // some more effort is necessary.
     960             :   //
     961             :   // numbering scheme:
     962             :   // 1. all vertices in the base, assign node->n_comp() dofs to each vertex
     963             :   // 2. all vertices further out: innermost loop: radial shapes,
     964             :   //    then the base approximation shapes
     965             :   // 3. all side nodes in the base, assign node->n_comp() dofs to each side node
     966             :   // 4. all side nodes further out: innermost loop: radial shapes,
     967             :   //    then the base approximation shapes
     968             :   // 5. (all) face nodes in the base, assign node->n_comp() dofs to each face node
     969             :   // 6. (all) face nodes further out: innermost loop: radial shapes,
     970             :   //    then the base approximation shapes
     971             :   // 7. element-associated dof in the base
     972             :   // 8. element-associated dof further out
     973             : 
     974       56871 :   const unsigned int radial_order       = static_cast<unsigned int>(fet.radial_order.get_order()); // 4
     975       56871 :   const unsigned int radial_order_p_one = radial_order+1;                                          // 5
     976             : 
     977       70391 :   std::unique_ptr<const Elem> base_elem = InfFEBase::build_elem(inf_elem);                         // QUAD9
     978             : 
     979             :   // assume that the number of dof is the same for all vertices
     980       13520 :   unsigned int n_base_vertices         = libMesh::invalid_uint;                                    // 4
     981       56871 :   const unsigned int n_base_vertex_dof = FEInterface::n_dofs_at_node  (fet, base_elem.get(), 0);   // 2
     982             : 
     983       13520 :   unsigned int n_base_side_nodes       = libMesh::invalid_uint;                                    // 4
     984       13520 :   unsigned int n_base_side_dof         = libMesh::invalid_uint;                                    // 3
     985             : 
     986       13520 :   unsigned int n_base_face_nodes       = libMesh::invalid_uint;                                    // 1
     987       13520 :   unsigned int n_base_face_dof         = libMesh::invalid_uint;                                    // 5
     988             : 
     989       56871 :   const unsigned int n_base_elem_dof   = FEInterface::n_dofs_per_elem (fet, base_elem.get());      // 9
     990             : 
     991       56871 :   const ElemType inf_elem_type = inf_elem->type();
     992             : 
     993       56871 :   switch (inf_elem_type)
     994             :     {
     995           0 :     case INFEDGE2:
     996             :       {
     997           0 :         n_base_vertices   = 1;
     998           0 :         n_base_side_nodes = 0;
     999           0 :         n_base_face_nodes = 0;
    1000           0 :         n_base_side_dof   = 0;
    1001           0 :         n_base_face_dof   = 0;
    1002           0 :         break;
    1003             :       }
    1004             : 
    1005           0 :     case INFQUAD4:
    1006             :       {
    1007           0 :         n_base_vertices   = 2;
    1008           0 :         n_base_side_nodes = 0;
    1009           0 :         n_base_face_nodes = 0;
    1010           0 :         n_base_side_dof   = 0;
    1011           0 :         n_base_face_dof   = 0;
    1012           0 :         break;
    1013             :       }
    1014             : 
    1015           0 :     case INFQUAD6:
    1016             :       {
    1017           0 :         n_base_vertices   = 2;
    1018           0 :         n_base_side_nodes = 1;
    1019           0 :         n_base_face_nodes = 0;
    1020           0 :         n_base_side_dof   = FEInterface::n_dofs_at_node (fet, base_elem.get(), n_base_vertices);
    1021           0 :         n_base_face_dof   = 0;
    1022           0 :         break;
    1023             :       }
    1024             : 
    1025       15736 :     case INFHEX8:
    1026             :       {
    1027        5472 :         n_base_vertices   = 4;
    1028        5472 :         n_base_side_nodes = 0;
    1029        5472 :         n_base_face_nodes = 0;
    1030        5472 :         n_base_side_dof   = 0;
    1031        5472 :         n_base_face_dof   = 0;
    1032       15736 :         break;
    1033             :       }
    1034             : 
    1035           0 :     case INFHEX16:
    1036             :       {
    1037           0 :         n_base_vertices   = 4;
    1038           0 :         n_base_side_nodes = 4;
    1039           0 :         n_base_face_nodes = 0;
    1040           0 :         n_base_side_dof   = FEInterface::n_dofs_at_node (fet, base_elem.get(), n_base_vertices);
    1041           0 :         n_base_face_dof   = 0;
    1042           0 :         break;
    1043             :       }
    1044             : 
    1045       31205 :     case INFHEX18:
    1046             :       {
    1047        4712 :         n_base_vertices   = 4;
    1048        4712 :         n_base_side_nodes = 4;
    1049        4712 :         n_base_face_nodes = 1;
    1050       31205 :         n_base_side_dof   = FEInterface::n_dofs_at_node (fet, base_elem.get(), n_base_vertices);
    1051       31205 :         n_base_face_dof   = FEInterface::n_dofs_at_node (fet, base_elem.get(), 8);
    1052        4712 :         break;
    1053             :       }
    1054             : 
    1055             : 
    1056           0 :     case INFPRISM6:
    1057             :       {
    1058           0 :         n_base_vertices   = 3;
    1059           0 :         n_base_side_nodes = 0;
    1060           0 :         n_base_face_nodes = 0;
    1061           0 :         n_base_side_dof   = 0;
    1062           0 :         n_base_face_dof   = 0;
    1063           0 :         break;
    1064             :       }
    1065             : 
    1066        9930 :     case INFPRISM12:
    1067             :       {
    1068        3336 :         n_base_vertices   = 3;
    1069        3336 :         n_base_side_nodes = 3;
    1070        3336 :         n_base_face_nodes = 0;
    1071        9930 :         n_base_side_dof   = FEInterface::n_dofs_at_node (fet, base_elem.get(), n_base_vertices);
    1072        3336 :         n_base_face_dof   = 0;
    1073        3336 :         break;
    1074             :       }
    1075             : 
    1076           0 :     default:
    1077           0 :       libmesh_error_msg("Unrecognized inf_elem type = " << Utility::enum_to_string(inf_elem_type));
    1078             :     }
    1079             : 
    1080             : 
    1081             :   {
    1082             :     // these are the limits describing the intervals where the shape function lies
    1083       56871 :     const unsigned int n_dof_at_base_vertices = n_base_vertices*n_base_vertex_dof;                 // 8
    1084       56871 :     const unsigned int n_dof_at_all_vertices  = n_dof_at_base_vertices*radial_order_p_one;         // 40
    1085             : 
    1086       56871 :     const unsigned int n_dof_at_base_sides    = n_base_side_nodes*n_base_side_dof;                 // 12
    1087       56871 :     const unsigned int n_dof_at_all_sides     = n_dof_at_base_sides*radial_order_p_one;            // 60
    1088             : 
    1089       56871 :     const unsigned int n_dof_at_base_face     = n_base_face_nodes*n_base_face_dof;                 // 5
    1090       56871 :     const unsigned int n_dof_at_all_faces     = n_dof_at_base_face*radial_order_p_one;             // 25
    1091             : 
    1092             : 
    1093             :     // start locating the shape function
    1094       56871 :     if (i < n_dof_at_base_vertices)                                              // range of i: 0..7
    1095             :       {
    1096             :         // belongs to vertex in the base
    1097        7974 :         radial_shape = 0;
    1098        7974 :         base_shape   = i;
    1099             :       }
    1100             : 
    1101       48897 :     else if (i < n_dof_at_all_vertices)                                          // range of i: 8..39
    1102             :       {
    1103             :         /* belongs to vertex in the outer shell
    1104             :          *
    1105             :          * subtract the number of dof already counted,
    1106             :          * so that i_offset contains only the offset for the base
    1107             :          */
    1108       36122 :         const unsigned int i_offset = i - n_dof_at_base_vertices;                // 0..31
    1109             : 
    1110             :         // first the radial dof are counted, then the base dof
    1111       36122 :         radial_shape = (i_offset % radial_order) + 1;
    1112       36122 :         base_shape   = i_offset / radial_order;
    1113             :       }
    1114             : 
    1115       12775 :     else if (i < n_dof_at_all_vertices+n_dof_at_base_sides)                      // range of i: 40..51
    1116             :       {
    1117             :         // belongs to base, is a side node
    1118        2251 :         radial_shape = 0;
    1119        2251 :         base_shape = i - radial_order * n_dof_at_base_vertices;                  //  8..19
    1120             :       }
    1121             : 
    1122       10524 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides)                       // range of i: 52..99
    1123             :       {
    1124             :         // belongs to side node in the outer shell
    1125       11949 :         const unsigned int i_offset = i - (n_dof_at_all_vertices
    1126        2990 :                                            + n_dof_at_base_sides);               // 0..47
    1127        8959 :         radial_shape = (i_offset % radial_order) + 1;
    1128        8959 :         base_shape   = (i_offset / radial_order) + n_dof_at_base_vertices;
    1129             :       }
    1130             : 
    1131        1565 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_base_face)    // range of i: 100..104
    1132             :       {
    1133             :         // belongs to the node in the base face
    1134         313 :         radial_shape = 0;
    1135         417 :         base_shape = i - radial_order*(n_dof_at_base_vertices
    1136         313 :                                        + n_dof_at_base_sides);                   //  20..24
    1137             :       }
    1138             : 
    1139        1252 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_all_faces)    // range of i: 105..124
    1140             :       {
    1141             :         // belongs to the node in the outer face
    1142        1668 :         const unsigned int i_offset = i - (n_dof_at_all_vertices
    1143         416 :                                            + n_dof_at_all_sides
    1144         416 :                                            + n_dof_at_base_face);                // 0..19
    1145        1252 :         radial_shape = (i_offset % radial_order) + 1;
    1146        1252 :         base_shape   = (i_offset / radial_order) + n_dof_at_base_vertices + n_dof_at_base_sides;
    1147             :       }
    1148             : 
    1149           0 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_all_faces+n_base_elem_dof)      // range of i: 125..133
    1150             :       {
    1151             :         // belongs to the base and is an element associated shape
    1152           0 :         radial_shape = 0;
    1153           0 :         base_shape = i - (n_dof_at_all_vertices
    1154           0 :                           + n_dof_at_all_sides
    1155           0 :                           + n_dof_at_all_faces);                                 // 0..8
    1156             :       }
    1157             : 
    1158             :     else                                                                         // range of i: 134..169
    1159             :       {
    1160           0 :         libmesh_assert_less (i, n_dofs(fet, inf_elem));
    1161             :         // belongs to the outer shell and is an element associated shape
    1162           0 :         const unsigned int i_offset = i - (n_dof_at_all_vertices
    1163           0 :                                            + n_dof_at_all_sides
    1164           0 :                                            + n_dof_at_all_faces
    1165           0 :                                            + n_base_elem_dof);                   // 0..19
    1166           0 :         radial_shape = (i_offset % radial_order) + 1;
    1167           0 :         base_shape   = (i_offset / radial_order) + n_dof_at_base_vertices + n_dof_at_base_sides + n_dof_at_base_face;
    1168             :       }
    1169             :   }
    1170             : 
    1171       70391 :   return;
    1172       29831 : }
    1173             : 
    1174             : 
    1175             : 
    1176             : #ifdef LIBMESH_ENABLE_DEPRECATED
    1177             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
    1178           0 : void InfFE<Dim,T_radial,T_map>::compute_shape_indices (const FEType & fet,
    1179             :                                                        const ElemType inf_elem_type,
    1180             :                                                        const unsigned int i,
    1181             :                                                        unsigned int & base_shape,
    1182             :                                                        unsigned int & radial_shape)
    1183             : {
    1184             :   // This is basically cut-and-paste copy of the non-deprecated code
    1185             :   // above, and should be removed eventually.
    1186             :   libmesh_deprecated();
    1187             : 
    1188           0 :   const unsigned int radial_order       = static_cast<unsigned int>(fet.radial_order.get_order()); // 4
    1189           0 :   const unsigned int radial_order_p_one = radial_order+1;                                          // 5
    1190             : 
    1191           0 :   const ElemType base_elem_type           (InfFEBase::get_elem_type(inf_elem_type));               // QUAD9
    1192             : 
    1193             :   // assume that the number of dof is the same for all vertices
    1194           0 :   unsigned int n_base_vertices         = libMesh::invalid_uint;                                    // 4
    1195           0 :   const unsigned int n_base_vertex_dof = FEInterface::n_dofs_at_node  (Dim-1, fet, base_elem_type, 0);// 2
    1196             : 
    1197           0 :   unsigned int n_base_side_nodes       = libMesh::invalid_uint;                                    // 4
    1198           0 :   unsigned int n_base_side_dof         = libMesh::invalid_uint;                                    // 3
    1199             : 
    1200           0 :   unsigned int n_base_face_nodes       = libMesh::invalid_uint;                                    // 1
    1201           0 :   unsigned int n_base_face_dof         = libMesh::invalid_uint;                                    // 5
    1202             : 
    1203           0 :   const unsigned int n_base_elem_dof   = FEInterface::n_dofs_per_elem (Dim-1, fet, base_elem_type);// 9
    1204             : 
    1205             : 
    1206           0 :   switch (inf_elem_type)
    1207             :     {
    1208           0 :     case INFEDGE2:
    1209             :       {
    1210           0 :         n_base_vertices   = 1;
    1211           0 :         n_base_side_nodes = 0;
    1212           0 :         n_base_face_nodes = 0;
    1213           0 :         n_base_side_dof   = 0;
    1214           0 :         n_base_face_dof   = 0;
    1215           0 :         break;
    1216             :       }
    1217             : 
    1218           0 :     case INFQUAD4:
    1219             :       {
    1220           0 :         n_base_vertices   = 2;
    1221           0 :         n_base_side_nodes = 0;
    1222           0 :         n_base_face_nodes = 0;
    1223           0 :         n_base_side_dof   = 0;
    1224           0 :         n_base_face_dof   = 0;
    1225           0 :         break;
    1226             :       }
    1227             : 
    1228           0 :     case INFQUAD6:
    1229             :       {
    1230           0 :         n_base_vertices   = 2;
    1231           0 :         n_base_side_nodes = 1;
    1232           0 :         n_base_face_nodes = 0;
    1233           0 :         n_base_side_dof   = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices);
    1234           0 :         n_base_face_dof   = 0;
    1235           0 :         break;
    1236             :       }
    1237             : 
    1238           0 :     case INFHEX8:
    1239             :       {
    1240           0 :         n_base_vertices   = 4;
    1241           0 :         n_base_side_nodes = 0;
    1242           0 :         n_base_face_nodes = 0;
    1243           0 :         n_base_side_dof   = 0;
    1244           0 :         n_base_face_dof   = 0;
    1245           0 :         break;
    1246             :       }
    1247             : 
    1248           0 :     case INFHEX16:
    1249             :       {
    1250           0 :         n_base_vertices   = 4;
    1251           0 :         n_base_side_nodes = 4;
    1252           0 :         n_base_face_nodes = 0;
    1253           0 :         n_base_side_dof   = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices);
    1254           0 :         n_base_face_dof   = 0;
    1255           0 :         break;
    1256             :       }
    1257             : 
    1258           0 :     case INFHEX18:
    1259             :       {
    1260           0 :         n_base_vertices   = 4;
    1261           0 :         n_base_side_nodes = 4;
    1262           0 :         n_base_face_nodes = 1;
    1263           0 :         n_base_side_dof   = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices);
    1264           0 :         n_base_face_dof   = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, 8);
    1265           0 :         break;
    1266             :       }
    1267             : 
    1268             : 
    1269           0 :     case INFPRISM6:
    1270             :       {
    1271           0 :         n_base_vertices   = 3;
    1272           0 :         n_base_side_nodes = 0;
    1273           0 :         n_base_face_nodes = 0;
    1274           0 :         n_base_side_dof   = 0;
    1275           0 :         n_base_face_dof   = 0;
    1276           0 :         break;
    1277             :       }
    1278             : 
    1279           0 :     case INFPRISM12:
    1280             :       {
    1281           0 :         n_base_vertices   = 3;
    1282           0 :         n_base_side_nodes = 3;
    1283           0 :         n_base_face_nodes = 0;
    1284           0 :         n_base_side_dof   = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices);
    1285           0 :         n_base_face_dof   = 0;
    1286           0 :         break;
    1287             :       }
    1288             : 
    1289           0 :     default:
    1290           0 :       libmesh_error_msg("Unrecognized inf_elem_type = " << Utility::enum_to_string(inf_elem_type));
    1291             :     }
    1292             : 
    1293             : 
    1294             :   {
    1295             :     // these are the limits describing the intervals where the shape function lies
    1296           0 :     const unsigned int n_dof_at_base_vertices = n_base_vertices*n_base_vertex_dof;                 // 8
    1297           0 :     const unsigned int n_dof_at_all_vertices  = n_dof_at_base_vertices*radial_order_p_one;         // 40
    1298             : 
    1299           0 :     const unsigned int n_dof_at_base_sides    = n_base_side_nodes*n_base_side_dof;                 // 12
    1300           0 :     const unsigned int n_dof_at_all_sides     = n_dof_at_base_sides*radial_order_p_one;            // 60
    1301             : 
    1302           0 :     const unsigned int n_dof_at_base_face     = n_base_face_nodes*n_base_face_dof;                 // 5
    1303           0 :     const unsigned int n_dof_at_all_faces     = n_dof_at_base_face*radial_order_p_one;             // 25
    1304             : 
    1305             : 
    1306             :     // start locating the shape function
    1307           0 :     if (i < n_dof_at_base_vertices)                                              // range of i: 0..7
    1308             :       {
    1309             :         // belongs to vertex in the base
    1310           0 :         radial_shape = 0;
    1311           0 :         base_shape   = i;
    1312             :       }
    1313             : 
    1314           0 :     else if (i < n_dof_at_all_vertices)                                          // range of i: 8..39
    1315             :       {
    1316             :         /* belongs to vertex in the outer shell
    1317             :          *
    1318             :          * subtract the number of dof already counted,
    1319             :          * so that i_offset contains only the offset for the base
    1320             :          */
    1321           0 :         const unsigned int i_offset = i - n_dof_at_base_vertices;                // 0..31
    1322             : 
    1323             :         // first the radial dof are counted, then the base dof
    1324           0 :         radial_shape = (i_offset % radial_order) + 1;
    1325           0 :         base_shape   = i_offset / radial_order;
    1326             :       }
    1327             : 
    1328           0 :     else if (i < n_dof_at_all_vertices+n_dof_at_base_sides)                      // range of i: 40..51
    1329             :       {
    1330             :         // belongs to base, is a side node
    1331           0 :         radial_shape = 0;
    1332           0 :         base_shape = i - radial_order * n_dof_at_base_vertices;                  //  8..19
    1333             :       }
    1334             : 
    1335           0 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides)                       // range of i: 52..99
    1336             :       {
    1337             :         // belongs to side node in the outer shell
    1338           0 :         const unsigned int i_offset = i - (n_dof_at_all_vertices
    1339           0 :                                            + n_dof_at_base_sides);               // 0..47
    1340           0 :         radial_shape = (i_offset % radial_order) + 1;
    1341           0 :         base_shape   = (i_offset / radial_order) + n_dof_at_base_vertices;
    1342             :       }
    1343             : 
    1344           0 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_base_face)    // range of i: 100..104
    1345             :       {
    1346             :         // belongs to the node in the base face
    1347           0 :         radial_shape = 0;
    1348           0 :         base_shape = i - radial_order*(n_dof_at_base_vertices
    1349           0 :                                        + n_dof_at_base_sides);                   //  20..24
    1350             :       }
    1351             : 
    1352           0 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_all_faces)    // range of i: 105..124
    1353             :       {
    1354             :         // belongs to the node in the outer face
    1355           0 :         const unsigned int i_offset = i - (n_dof_at_all_vertices
    1356           0 :                                            + n_dof_at_all_sides
    1357           0 :                                            + n_dof_at_base_face);                // 0..19
    1358           0 :         radial_shape = (i_offset % radial_order) + 1;
    1359           0 :         base_shape   = (i_offset / radial_order) + n_dof_at_base_vertices + n_dof_at_base_sides;
    1360             :       }
    1361             : 
    1362           0 :     else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_all_faces+n_base_elem_dof)      // range of i: 125..133
    1363             :       {
    1364             :         // belongs to the base and is an element associated shape
    1365           0 :         radial_shape = 0;
    1366           0 :         base_shape = i - (n_dof_at_all_vertices
    1367           0 :                           + n_dof_at_all_sides
    1368           0 :                           + n_dof_at_all_faces);                                 // 0..8
    1369             :       }
    1370             : 
    1371             :     else                                                                         // range of i: 134..169
    1372             :       {
    1373           0 :         libmesh_assert_less (i, n_dofs(fet, inf_elem_type));
    1374             :         // belongs to the outer shell and is an element associated shape
    1375           0 :         const unsigned int i_offset = i - (n_dof_at_all_vertices
    1376           0 :                                            + n_dof_at_all_sides
    1377           0 :                                            + n_dof_at_all_faces
    1378           0 :                                            + n_base_elem_dof);                   // 0..19
    1379           0 :         radial_shape = (i_offset % radial_order) + 1;
    1380           0 :         base_shape   = (i_offset / radial_order) + n_dof_at_base_vertices + n_dof_at_base_sides + n_dof_at_base_face;
    1381             :       }
    1382             :   }
    1383             : 
    1384           0 :   return;
    1385             : }
    1386             : #endif // LIBMESH_ENABLE_DEPRECATED
    1387             : 
    1388             : 
    1389             : #ifdef LIBMESH_ENABLE_AMR
    1390             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
    1391             : 
    1392             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
    1393        2112 : void InfFE<Dim, T_radial, T_map>::inf_compute_node_constraints (NodeConstraints & /* constraints */,const Elem * elem)
    1394             : {
    1395             :   // only constrain elements in 2,3d.
    1396             :   if (Dim == 1)
    1397           0 :     return;
    1398             : 
    1399        1056 :   libmesh_assert(elem);
    1400             : 
    1401             :   // only constrain active and ancestor elements
    1402        2112 :   if (elem->subactive())
    1403           0 :     return;
    1404             : 
    1405             :   // for infinite elements, the computation of constraints is somewhat different
    1406             :   // than for Lagrange elements:
    1407             :   // 1) Only the base element (i.e. side(0) ) may be refined.
    1408             :   //    Thus, in radial direction no constraints must be considered.
    1409             :   // 2) Due to the tensorial structure of shape functions (base_shape * radial_function),
    1410             :   //    it must be ensured that all element DOFs inherit that constraint.
    1411             :   // Consequently, the constraints are computed on the base (baseh_shape) but must
    1412             :   // be applied to all DOFs with the respective base_shape index (i.e. for all radial_functions).
    1413             :   //
    1414             :   // FIXME: In the current form, this function does not work for infinite elements
    1415             :   //        because constraining the non-base points requires knowledge of the T_map and T_radial
    1416             :   //        parameters; but they are not accessible via the element and may differ between variables.
    1417             :   //
    1418             :   // For the moment being, we just check if this element can be skipped and fail otherwise.
    1419             : 
    1420             :   // if one of the sides needs a constraint, an error is thrown.
    1421             :   // In other cases, we leave the function regularly.
    1422       12072 :   for (auto s : elem->side_index_range())
    1423             :     {
    1424       19920 :       if (elem->neighbor_ptr(s) != nullptr &&
    1425        9960 :           elem->neighbor_ptr(s) != remote_elem)
    1426        9960 :         if (elem->neighbor_ptr(s)->level() < elem->level())
    1427             :           {
    1428           0 :             libmesh_not_implemented();
    1429             :           }
    1430             :     }
    1431             : }
    1432             : 
    1433             : #endif //LIBMESH_ENABLE_NODE_CONSTRAINTS
    1434             : 
    1435             : 
    1436             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
    1437        3212 : void InfFE<Dim, T_radial, T_map>::inf_compute_constraints (DofConstraints & constraints,
    1438             :                                                            DofMap & dof_map,
    1439             :                                                            const unsigned int variable_number,
    1440             :                                                            const Elem * child_elem)
    1441             : {
    1442             : 
    1443             :   // only constrain elements in 2,3d.
    1444             :   if (Dim == 1)
    1445        3186 :     return;
    1446             : 
    1447        1056 :   libmesh_assert(child_elem);
    1448             : 
    1449             :   // only constrain active and ancestor elements
    1450        3212 :   if (child_elem->subactive())
    1451           0 :     return;
    1452             : 
    1453             :   // Before we start to compute anything, lets check if any confinement is needed:
    1454        1056 :   bool need_constraints=false;
    1455       18284 :   for (auto child_neighbor : child_elem->neighbor_ptr_range())
    1456       15098 :     if (child_neighbor->level() < child_elem->level())
    1457             :       {
    1458           0 :         need_constraints = true;
    1459           0 :         break;
    1460             :       }
    1461        3212 :   if (!need_constraints)
    1462        1056 :     return;
    1463             : 
    1464             :   // For infinite elements, the computation of constraints is somewhat different
    1465             :   // than for Lagrange elements:
    1466             :   // 1) When an infinite element is refined, only the base element (i.e. side(0) ) is refined.
    1467             :   //
    1468             :   // 2) Due to the tensorial structure of shape functions (base_shape * radial_function),
    1469             :   //    it must be ensured that all element DOFs inherit that constraint.
    1470             :   //    It is important here to distinguish the (total) DOF from base DOF and radial DOF contributions.
    1471             :   //
    1472             :   // 3) Due to the generality of radial polynomial (of type fe_type.radial_family and with order fe_type.radial_order)
    1473             :   //    here basis functions cannot be mapped to nodes: Independent from the radial polynomial,
    1474             :   //    infinite elements have one set of nodes at the base (side(0)) and a second set at twice the distance to their origin.
    1475             :   //
    1476             :   //    Independent from the polynomial and degree used, the first radial DOF is 1 at the base while all others are 0 there
    1477             :   //
    1478             :   //Constraining of DOFs is only needed when a DOF is nonzero at the elements face shared with a coarser element.
    1479             :   // Thus, the following scheme is used here:
    1480             :   //
    1481             :   //  -If the coarser element is the neighbor(0) (i.e. we share only the base), we must constrain
    1482             :   //   all DOFs that correspond to the first order radial contribution.
    1483             :   //  -if an infinite neighbor is coarser (than 'child_elem'), all those DOFs must be constrained
    1484             :   //   whose contribution from the base is non-zero at the interface.
    1485             :   //   In this case, we lack a point-assignement between DOFs and nodes, but since there is no refinement in radial direction,
    1486             :   //   the radial polynomials coincide on neighboring elements.
    1487             :   //   Thus, if one constraines these DOFs at one (arbitrary) point correctly, they match for each point along the radial direction.
    1488             :   //   Hence, we constrain them with the same values as those DOFs belonging to the first order polynomial, obtaining consistent
    1489             :   //   constraints that mimic constraints that are computed at the support points for each radial polynomial contribution.
    1490             : 
    1491          26 :   FEType fe_type = dof_map.variable_type(variable_number);
    1492             : 
    1493           0 :   libmesh_assert(fe_type.family == LAGRANGE);
    1494             : 
    1495           0 :   std::vector<dof_id_type> child_base_dof_indices, parent_base_dof_indices;
    1496           0 :   std::vector<dof_id_type> child_elem_dof_indices, parent_elem_dof_indices;
    1497             : 
    1498           0 :   const Elem * parent_elem = child_elem->parent();
    1499             : 
    1500             :   // This can't happen...  Only level-0 elements have nullptr
    1501             :   // parents, and no level-0 elements can be at a higher
    1502             :   // level than their neighbors!
    1503           0 :   libmesh_assert(parent_elem);
    1504             : 
    1505          26 :   dof_map.dof_indices (child_elem, child_elem_dof_indices,
    1506             :                        variable_number);
    1507          26 :   dof_map.dof_indices (parent_elem, parent_elem_dof_indices,
    1508             :                        variable_number);
    1509             : 
    1510          26 :   const unsigned int n_total_dofs = child_elem_dof_indices.size();
    1511             :   // fill the elements shape index map: we will have to use it later
    1512             :   // to find the elements dofs that correspond to certain base_elem_dofs.
    1513          26 :   std::vector<unsigned int> radial_shape_index(n_total_dofs);
    1514          26 :   std::vector<unsigned int> base_shape_index(n_total_dofs);
    1515             :   // fill the shape index map
    1516             : #ifdef DEBUG
    1517           0 :   unsigned int max_base_id=0;
    1518           0 :   unsigned int max_radial_id=0;
    1519             : #endif
    1520        1066 :   for (unsigned int n=0; n<n_total_dofs; ++n)
    1521             :     {
    1522        1040 :       compute_shape_indices (fe_type,
    1523             :                              child_elem,
    1524             :                              n,
    1525             :                              base_shape_index[n],
    1526             :                              radial_shape_index[n]);
    1527             : 
    1528             : #ifdef DEBUG
    1529           0 :       if (base_shape_index[n] > max_base_id)
    1530           0 :         max_base_id = base_shape_index[n];
    1531           0 :       if (radial_shape_index[n] > max_radial_id)
    1532           0 :         max_radial_id = radial_shape_index[n];
    1533             : #endif
    1534             :     }
    1535             : 
    1536             : #ifdef DEBUG
    1537           0 :   libmesh_assert_equal_to( (max_base_id+1)*(max_radial_id+1), n_total_dofs );
    1538             : #endif
    1539             : 
    1540         156 :   for (auto s : child_elem->side_index_range())
    1541         130 :     if (child_elem->neighbor_ptr(s) != nullptr &&
    1542         130 :         child_elem->neighbor_ptr(s) != remote_elem)
    1543         130 :       if (child_elem->neighbor_ptr(s)->level() < child_elem->level())
    1544             :         {
    1545             :           // we ALWAYS take the base element for reference:
    1546             :           // - For s=0, we refine all dofs with `radial_shape_index == 0
    1547             :           // - for s>0, we refine all dofs whose corresponding base_shape has its support point shared with neighbor(s)
    1548          48 :           std::unique_ptr<const Elem> child_base, parent_base;
    1549          48 :           child_elem->build_side_ptr(child_base, 0);
    1550          48 :           parent_elem->build_side_ptr(parent_base, 0);
    1551             : 
    1552             :           const unsigned int n_base_dofs =
    1553          48 :             FEInterface::n_dofs(fe_type, child_base.get());
    1554             : 
    1555             :           // We need global DOF indices for both base and 'full' elements
    1556          48 :           dof_map.dof_indices (child_base.get(), child_base_dof_indices,
    1557             :                                variable_number);
    1558          48 :           dof_map.dof_indices (parent_base.get(), parent_base_dof_indices,
    1559             :                                variable_number);
    1560             : 
    1561             : 
    1562             :           // First we loop over the childs base DOFs (nodes) and check which of them needs constraint
    1563             :           // and which can be skipped.
    1564         240 :           for (unsigned int child_base_dof=0; child_base_dof != n_base_dofs; ++child_base_dof)
    1565             :             {
    1566           0 :               libmesh_assert_less (child_base_dof, child_base->n_nodes());
    1567             : 
    1568             :               // Childs global dof index.
    1569         192 :               const dof_id_type child_base_dof_g = child_base_dof_indices[child_base_dof];
    1570             : 
    1571             :               // Hunt for "constraining against myself" cases before
    1572             :               // we bother creating a constraint row
    1573           0 :               bool self_constraint = false;
    1574         844 :               for (unsigned int parent_base_dof=0;
    1575         844 :                    parent_base_dof != n_base_dofs; parent_base_dof++)
    1576             :                 {
    1577           0 :                   libmesh_assert_less (parent_base_dof, parent_base->n_nodes());
    1578             : 
    1579             :                   // Their global dof index.
    1580         700 :                   const dof_id_type parent_base_dof_g =
    1581             :                     parent_base_dof_indices[parent_base_dof];
    1582             : 
    1583         700 :                   if (parent_base_dof_g == child_base_dof_g)
    1584             :                     {
    1585           0 :                       self_constraint = true;
    1586           0 :                       break;
    1587             :                     }
    1588             :                 }
    1589             : 
    1590         192 :               if (self_constraint)
    1591          48 :                 continue;
    1592             : 
    1593             :               // now we need to constrain all __child_elem__ DOFs whose base corresponds to
    1594             :               // child_base_dof.
    1595             :               //  --> loop over all child_elem dofs whose base_shape_index == child_base_dof
    1596         144 :               unsigned int n_elem_dofs = FEInterface::n_dofs(fe_type, child_elem);
    1597           0 :               libmesh_assert_equal_to(n_elem_dofs, n_total_dofs);
    1598        5904 :               for(unsigned int child_elem_dof=0; child_elem_dof != n_elem_dofs; ++child_elem_dof)
    1599             :                 {
    1600        5760 :                   if (base_shape_index[child_elem_dof] != child_base_dof)
    1601        5566 :                     continue;
    1602             : 
    1603             :                   // independent from the radial description, the first radial DOF is 1 at the base
    1604             :                   // while all others start with 0.
    1605             :                   // Thus, to confine for the bases neighbor, we only need to refine DOFs that correspond
    1606             :                   // to the first radial DOF
    1607        1440 :                   if (s==0)
    1608             :                     {
    1609         240 :                       if (radial_shape_index[child_elem_dof] > 0)
    1610         216 :                         continue;
    1611             :                     }
    1612             :                   else
    1613             :                     {
    1614             :                       // If the neighbor is not the base, we must check now if the support point of the dof
    1615             :                       // is actually shared with that neighbor:
    1616        1200 :                       if ( !child_elem->neighbor_ptr(s)->contains_point(child_base->point(child_base_dof)) )
    1617         800 :                         continue;
    1618             :                     }
    1619             : 
    1620             : 
    1621         424 :                   const dof_id_type child_elem_dof_g = child_elem_dof_indices[child_elem_dof];
    1622             : 
    1623             :                   DofConstraintRow * constraint_row;
    1624             : 
    1625             :                   // we may be running constraint methods concurrently
    1626             :                   // on multiple threads, so we need a lock to
    1627             :                   // ensure that this constraint is "ours"
    1628             :                   {
    1629           0 :                     Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1630             : 
    1631         424 :                     if (dof_map.is_constrained_dof(child_elem_dof_g))
    1632           0 :                       continue;
    1633             : 
    1634         194 :                     constraint_row = &(constraints[child_elem_dof_g]);
    1635           0 :                     libmesh_assert(constraint_row->empty());
    1636             :                   }
    1637             : 
    1638             :                   // The support point of the DOF
    1639           0 :                   const Point & support_point = child_base->point(child_base_dof);
    1640             : 
    1641             :                   // Figure out where my (base) node lies on the parents reference element.
    1642         194 :                   const Point mapped_point = FEMap::inverse_map(Dim-1,
    1643             :                                                                 parent_base.get(),
    1644             :                                                                 support_point);
    1645             : 
    1646             :                   // now we need the parents base DOFs, evaluated at the mapped_point for refinement:
    1647         776 :                   for (unsigned int parent_base_dof=0;
    1648         970 :                        parent_base_dof != n_base_dofs; parent_base_dof++)
    1649             :                     {
    1650             : 
    1651         776 :                       const Real parent_base_dof_value = FEInterface::shape(fe_type,
    1652             :                                                                             parent_base.get(),
    1653             :                                                                             parent_base_dof,
    1654             :                                                                             mapped_point);
    1655             : 
    1656             : 
    1657             :                       // all parent elements DOFs whose base_index corresponds to parent_base_dof
    1658             :                       //  must be constrained with the parent_base_dof_value.
    1659             : 
    1660             :                       // The value of the radial function does not play a role here:
    1661             :                       // 1) only the function with radial_shape_index[] == 0 are 1 at the base,
    1662             :                       //    the others are 0.
    1663             :                       // 2) The radial basis is (usually) not a Lagrange polynomial.
    1664             :                       //    Thus, constraining according to a support point doesn't work.
    1665             :                       //    However, they reach '1' at a certain (radial) distance which is the same for parent and child.
    1666       31816 :                       for (unsigned int parent_elem_dof=0;
    1667       31816 :                            parent_elem_dof != n_elem_dofs; parent_elem_dof++)
    1668             :                         {
    1669       31040 :                           if (base_shape_index[parent_elem_dof] != parent_base_dof)
    1670       30264 :                             continue;
    1671             : 
    1672             :                           // only constrain with coinciding radial DOFs.
    1673             :                           // Otherwise, we start coupling all DOFs with each other and end up in a mess.
    1674        7760 :                           if (radial_shape_index[parent_elem_dof] != radial_shape_index[child_elem_dof])
    1675        6984 :                             continue;
    1676             : 
    1677             :                           // Their global dof index.
    1678         776 :                           const dof_id_type parent_elem_dof_g =
    1679             :                             parent_elem_dof_indices[parent_elem_dof];
    1680             : 
    1681             :                           // Only add non-zero and non-identity values
    1682             :                           // for Lagrange basis functions. (parent_base is assumed to be of Lagrange-type).
    1683         776 :                           if ((std::abs(parent_base_dof_value) > 1.e-5) &&
    1684           0 :                               (std::abs(parent_base_dof_value) < .999))
    1685             :                             {
    1686           0 :                               constraint_row->emplace(parent_elem_dof_g, parent_base_dof_value);
    1687             :                             }
    1688             : #ifdef DEBUG
    1689             :                           // Protect for the case u_i = 0.999 u_j,
    1690             :                           // in which case i better equal j.
    1691           0 :                           else if (parent_base_dof_value >= .999)
    1692             :                             {
    1693           0 :                               libmesh_assert_equal_to (child_base_dof_g, parent_base_dof_indices[parent_base_dof]);
    1694           0 :                               libmesh_assert_equal_to (child_elem_dof_g, parent_elem_dof_g);
    1695             :                             }
    1696             : #endif
    1697             :                         }
    1698             : 
    1699             :                     }
    1700             :                 }
    1701             : 
    1702             :             }
    1703          48 :         }
    1704             : }
    1705             : 
    1706             : #endif // LIBMESH_ENABLE_AMR
    1707             : 
    1708             : 
    1709             : //--------------------------------------------------------------
    1710             : // Explicit instantiations
    1711             : //#include "libmesh/inf_fe_instantiate_1D.h"
    1712             : //#include "libmesh/inf_fe_instantiate_2D.h"
    1713             : //#include "libmesh/inf_fe_instantiate_3D.h"
    1714             : 
    1715             : #ifdef LIBMESH_ENABLE_DEPRECATED
    1716             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, unsigned int, n_dofs(const FEType &, const ElemType));
    1717             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, unsigned int, n_dofs(const FEType &, const ElemType));
    1718             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, unsigned int, n_dofs(const FEType &, const ElemType));
    1719             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, unsigned int, n_dofs_per_elem(const FEType &, const ElemType));
    1720             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, unsigned int, n_dofs_per_elem(const FEType &, const ElemType));
    1721             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, unsigned int, n_dofs_per_elem(const FEType &, const ElemType));
    1722             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, unsigned int, n_dofs_at_node(const FEType &, const ElemType, const unsigned int));
    1723             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, unsigned int, n_dofs_at_node(const FEType &, const ElemType, const unsigned int));
    1724             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, unsigned int, n_dofs_at_node(const FEType &, const ElemType, const unsigned int));
    1725             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, compute_shape_indices(const FEType &, const ElemType, const unsigned int, unsigned int &, unsigned int &));
    1726             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, compute_shape_indices(const FEType &, const ElemType, const unsigned int, unsigned int &, unsigned int &));
    1727             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, compute_shape_indices(const FEType &, const ElemType, const unsigned int, unsigned int &, unsigned int &));
    1728             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, compute_node_indices(const ElemType, const unsigned int, unsigned int &, unsigned int &));
    1729             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, compute_node_indices(const ElemType, const unsigned int, unsigned int &, unsigned int &));
    1730             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, compute_node_indices(const ElemType, const unsigned int, unsigned int &, unsigned int &));
    1731             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Real, shape(const FEType &, const ElemType, const unsigned int, const Point &));
    1732             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Real, shape(const FEType &, const ElemType, const unsigned int, const Point &));
    1733             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Real, shape(const FEType &, const ElemType, const unsigned int, const Point &));
    1734             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Real, shape_deriv(const FEType &, const ElemType, const unsigned int, const unsigned int, const Point &));
    1735             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Real, shape_deriv(const FEType &, const ElemType, const unsigned int, const unsigned int, const Point &));
    1736             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Real, shape_deriv(const FEType &, const ElemType, const unsigned int, const unsigned int, const Point &));
    1737             : #endif // LIBMESH_ENABLE_DEPRECATED
    1738             : 
    1739             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, unsigned int, n_dofs(const FEType &, const Elem*));
    1740             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, unsigned int, n_dofs(const FEType &, const Elem*));
    1741             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, unsigned int, n_dofs(const FEType &, const Elem*));
    1742             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, unsigned int, n_dofs_per_elem(const FEType &, const Elem *));
    1743             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, unsigned int, n_dofs_per_elem(const FEType &, const Elem *));
    1744             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, unsigned int, n_dofs_per_elem(const FEType &, const Elem *));
    1745             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, unsigned int, n_dofs_at_node(const FEType &, const Elem *, const unsigned int));
    1746             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, unsigned int, n_dofs_at_node(const FEType &, const Elem *, const unsigned int));
    1747             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, unsigned int, n_dofs_at_node(const FEType &, const Elem *, const unsigned int));
    1748             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, compute_shape_indices(const FEType &, const Elem *, const unsigned int, unsigned int &, unsigned int &));
    1749             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, compute_shape_indices(const FEType &, const Elem *, const unsigned int, unsigned int &, unsigned int &));
    1750             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, compute_shape_indices(const FEType &, const Elem *, const unsigned int, unsigned int &, unsigned int &));
    1751             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Real, shape(const FEType &, const Elem *, const unsigned int, const Point & p));
    1752             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Real, shape(const FEType &, const Elem *, const unsigned int, const Point & p));
    1753             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Real, shape(const FEType &, const Elem *, const unsigned int, const Point & p));
    1754             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Real, shape(const FEType, const Elem *, const unsigned int, const Point &, const bool));
    1755             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Real, shape(const FEType, const Elem *, const unsigned int, const Point &, const bool));
    1756             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Real, shape(const FEType, const Elem *, const unsigned int, const Point &, const bool));
    1757             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Real, shape_deriv(const FEType &, const Elem *, const unsigned int, const unsigned int, const Point &));
    1758             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Real, shape_deriv(const FEType &, const Elem *, const unsigned int, const unsigned int, const Point &));
    1759             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Real, shape_deriv(const FEType &, const Elem *, const unsigned int, const unsigned int, const Point &));
    1760             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Real, shape_deriv(const FEType, const Elem *, const unsigned int, const unsigned int, const Point &, const bool));
    1761             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Real, shape_deriv(const FEType, const Elem *, const unsigned int, const unsigned int, const Point &, const bool));
    1762             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Real, shape_deriv(const FEType, const Elem *, const unsigned int, const unsigned int, const Point &, const bool));
    1763             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, compute_data(const FEType &, const Elem *, FEComputeData &));
    1764             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, compute_data(const FEType &, const Elem *, FEComputeData &));
    1765             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, compute_data(const FEType &, const Elem *, FEComputeData &));
    1766             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, nodal_soln(const FEType &, const Elem *, const std::vector<Number> &, std::vector<Number> &));
    1767             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, nodal_soln(const FEType &, const Elem *, const std::vector<Number> &, std::vector<Number> &));
    1768             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, nodal_soln(const FEType &, const Elem *, const std::vector<Number> &, std::vector<Number> &));
    1769             : #ifdef LIBMESH_ENABLE_AMR
    1770             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, inf_compute_constraints(DofConstraints &, DofMap &, const unsigned int, const Elem *));
    1771             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, inf_compute_constraints(DofConstraints &, DofMap &, const unsigned int, const Elem *));
    1772             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, inf_compute_constraints(DofConstraints &, DofMap &, const unsigned int, const Elem *));
    1773             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
    1774             : INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, inf_compute_node_constraints(NodeConstraints & constraints,const Elem * elem));
    1775             : INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, inf_compute_node_constraints(NodeConstraints & constraints,const Elem * elem));
    1776             : INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, inf_compute_node_constraints(NodeConstraints & constraints,const Elem * elem));
    1777             : #endif
    1778             : #endif
    1779             : 
    1780             : } // namespace libMesh
    1781             : 
    1782             : #endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS

Generated by: LCOV version 1.14