LCOV - code coverage report
Current view: top level - src/fe - inf_fe_static.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4475 (55045b) with base a68cc6 Lines: 203 624 32.5 %
Date: 2026-06-03 14:29:06 Functions: 10 285 3.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14