LCOV - code coverage report
Current view: top level - include/fe - inf_fe.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 75 137 54.7 %
Date: 2026-06-03 20:22:46 Functions: 40 668 6.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : #ifndef LIBMESH_INF_FE_H
      21             : #define LIBMESH_INF_FE_H
      22             : 
      23             : #include "libmesh/libmesh_config.h"
      24             : 
      25             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
      26             : 
      27             : // Local includes
      28             : #include "libmesh/fe_base.h"
      29             : #include "libmesh/inf_fe_map.h"
      30             : 
      31             : // C++ includes
      32             : #include <cstddef>
      33             : 
      34             : namespace libMesh
      35             : {
      36             : 
      37             : 
      38             : // forward declarations
      39             : class Elem;
      40             : class FEComputeData;
      41             : 
      42             : 
      43             : /**
      44             :  * Infinite elements are in some sense directional, compared
      45             :  * to conventional finite elements.  All methods related
      46             :  * to the radial part, which extends perpendicular from the base,
      47             :  * are collected in this class.  This class offers static methods for
      48             :  * use in \p InfFE and \p InfFEMap
      49             :  *
      50             :  * \author Daniel Dreyer
      51             :  * \date 2003
      52             :  */
      53             : class InfFERadial
      54             : {
      55             : private:
      56             : 
      57             :   /**
      58             :    * Never use an object of this type.
      59             :    */
      60             :   InfFERadial() {}
      61             : 
      62             : public:
      63             : 
      64             :   /**
      65             :    * \returns The decay in the radial direction of
      66             :    * the \p Dim dimensional infinite element.
      67             :    */
      68             :   static Real decay (const unsigned int dim, const Real v);
      69             : 
      70             :   /**
      71             :    * \returns The first (local) derivative of the
      72             :    * decay in radial direction of the infinite element.
      73             :    */
      74             :   static Real decay_deriv (const unsigned int dim, const Real);
      75             : 
      76             :   /**
      77             :    * \returns The radial weight D, used as an additional weight
      78             :    * for the test function, evaluated at local radial coordinate \p v.
      79             :    * FIXME: This is only valid for 3D!!
      80             :    * And also makes assumptions on the mapping
      81             :    */
      82        2961 :   static Real D (const Real v) { return (1.-v)*(1.-v)/4.; }
      83             : 
      84       30648 :   static Real Dxr_sq (const Real /*v*/) { return 1.; }
      85             : 
      86             :   /**
      87             :    * \returns The first (local) radial derivative of the radial weight D.
      88             :    * FIXME: this is valid only in 3D.
      89             :    */
      90        4942 :   static Real D_deriv (const Real v) { return (v-1.)/2.; }
      91             : 
      92             : 
      93             :   /**
      94             :    * \returns The Order of the mapping functions
      95             :    * in the radial direction. Currently, this is always \p FIRST.
      96             :    */
      97           0 :   static Order mapping_order() { return FIRST; }
      98             : 
      99             :   /**
     100             :    * \returns The number of shape functions in radial direction
     101             :    * associated with this infinite element.
     102             :    * Either way, if the modes are stored as nodal dofs (\p n_dofs_at_node)
     103             :    * or as element dofs (\p n_dofs_per_elem), in each case we have the
     104             :    * same number of modes in radial direction.
     105             :    *
     106             :    * \note For the case of 1D infinite elements, in the base the
     107             :    * dof-per-node scheme is used.
     108             :    *
     109             :    * From the formulation of the infinite elements, we have
     110             :    * 1 mode, when \p o_radial=CONST.
     111             :    * Therefore, we have a total of \p o_radial+1 modes in radial direction.
     112             :    */
     113       80716 :   static unsigned int n_dofs (const Order o_radial)
     114      234830 :   { return static_cast<unsigned int>(o_radial)+1; }
     115             : 
     116             :   /**
     117             :    * \returns The number of dofs in radial direction on "onion slice"
     118             :    * \p n (either 0 or 1) for an infinite element of type \p inf_elem_type and
     119             :    * radial order \p o_radial.
     120             :    *
     121             :    * Currently, the first radial mode is associated with the nodes in
     122             :    * the base.  All higher radial modes are associated with
     123             :    * the physically existing nodes further out.
     124             :    */
     125             :   static unsigned int n_dofs_at_node (const Order o_radial,
     126             :                                       const unsigned int n_onion);
     127             : 
     128             :   /**
     129             :    * \returns The number of modes in radial direction interior to the element,
     130             :    * not associated with any interior nodes.
     131             :    *
     132             :    * \note These modes are a discontinuous approximation, therefore
     133             :    * we have no special formulation for coupling in the base, like in the
     134             :    * case of associating (possibly) multiple dofs per (outer) node.
     135             :    */
     136        8515 :   static unsigned int n_dofs_per_elem (const Order o_radial)
     137       22750 :   { return static_cast<unsigned int>(o_radial)+1; }
     138             : 
     139             : };
     140             : 
     141             : 
     142             : 
     143             : /**
     144             :  * This nested class contains most of the static methods related
     145             :  * to the base part of an infinite element.  Only static members
     146             :  * are provided, for use within \p InfFE and \p InfFEMap.
     147             :  *
     148             :  * \author Daniel Dreyer
     149             :  * \date 2003
     150             :  */
     151             : class InfFEBase
     152             : {
     153             : private:
     154             : 
     155             :   /**
     156             :    * Never use an object of this type.
     157             :    */
     158             :   InfFEBase() {}
     159             : 
     160             : public:
     161             : 
     162             :   /**
     163             :    * Build the base element of an infinite element. Here "base" refers
     164             :    * to the non-infinite/traditional geometric element face which is
     165             :    * associated with this infinite element. A const base Elem is built
     166             :    * from a const input InfElem.
     167             :    */
     168             :   static std::unique_ptr<const Elem> build_elem (const Elem * inf_elem);
     169             : 
     170             :   /**
     171             :    * \returns The base element associated to
     172             :    * \p type.  This is, for example, \p TRI3 for
     173             :    * \p INFPRISM6.
     174             :    */
     175             :   static ElemType get_elem_type (const ElemType type);
     176             : 
     177             :   /**
     178             :    * \returns The number of shape functions used in the
     179             :    * mapping in the base element of type \p base_elem_type
     180             :    * mapped with order \p base_mapping_order
     181             :    */
     182             :   static unsigned int n_base_mapping_sf (const Elem & base_elem,
     183             :                                          const Order base_mapping_order);
     184             : 
     185             : };
     186             : 
     187             : 
     188             : 
     189             : /**
     190             :  * A specific instantiation of the \p FEBase class. This
     191             :  * class is templated, and specific template instantiations
     192             :  * will result in different Infinite Element families, similar
     193             :  * to the \p FE class.  \p InfFE builds a \p FE<Dim-1,T_base>,
     194             :  * and most of the requests related to the base are handed over
     195             :  * to this object.  All methods related to the radial part
     196             :  * are collected in the class \p InfFERadial.  Similarly,
     197             :  * most of the static methods concerning base approximation
     198             :  * are contained in \p InfFEBase.
     199             :  *
     200             :  * Having different shape approximation families in radial direction
     201             :  * introduces the requirement for an additional \p Order in this
     202             :  * class. Therefore, the \p FEType internals change when infinite
     203             :  * elements are enabled.
     204             :  * When the specific infinite element type is not known at compile
     205             :  * time, use the \p FEBase::build() member to create abstract
     206             :  * (but still optimized) infinite elements at run time.
     207             :  *
     208             :  * The node numbering scheme is the one from the current
     209             :  * infinite element.  Each node in the base holds exactly
     210             :  * the same number of dofs as an adjacent conventional \p FE
     211             :  * would contain.  The nodes further out hold the additional
     212             :  * dof necessary for radial approximation.  The order of the outer nodes'
     213             :  * components is such that the radial shapes have highest
     214             :  * priority, followed by the base shapes.
     215             :  *
     216             :  * For the derivation and some background of the implemented algorithm
     217             :  * see https://arxiv.org/abs/2501.05568.
     218             :  *
     219             :  * \author Daniel Dreyer
     220             :  * \date 2003
     221             :  * \brief Base class for all the infinite geometric element types.
     222             :  */
     223             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     224             : class InfFE : public FEBase
     225             : {
     226             : 
     227             :   /*
     228             :    * Protect the nested class
     229             :    */
     230             : protected:
     231             : 
     232             : 
     233             : public:
     234             : 
     235             :   // InfFE continued
     236             : 
     237             :   /**
     238             :    * Constructor and empty destructor.
     239             :    * Initializes some data structures.  Builds a \p FE<Dim-1,T_base>
     240             :    * object to handle  approximation in the base, so that
     241             :    * there is no need to template \p InfFE<Dim,T_radial,T_map> also with
     242             :    * respect to the base approximation \p T_base.
     243             :    *
     244             :    * The same remarks concerning compile-time optimization for
     245             :    * \p FE also hold for \p InfFE.  Use the
     246             :    * \p FEBase::build_InfFE(const unsigned int, const FEType &)
     247             :    * method to build specific instantiations of \p InfFE at
     248             :    * run time.
     249             :    */
     250             :   explicit
     251             :   InfFE(const FEType & fet);
     252        2140 :   ~InfFE() = default;
     253             : 
     254             :   // The static public members for access from FEInterface etc
     255             : 
     256             :   /**
     257             :    * \returns The value of the \f$ i^{th} \f$ shape function at
     258             :    * point \p p.  This method lets you specify the relevant
     259             :    * data directly, and is therefore allowed to be static.
     260             :    *
     261             :    * \note This class member is not as efficient as its counterpart in
     262             :    * \p FE<Dim,T>, and is not employed in the \p reinit() cycle.
     263             :    *
     264             :    * \note This method does not return physically correct shapes,
     265             :    * instead use \p compute_data().  The \p shape() methods should
     266             :    * only be used for mapping.
     267             :    */
     268             :   static Real shape(const FEType & fet,
     269             :                     const ElemType t,
     270             :                     const unsigned int i,
     271             :                     const Point & p);
     272             : 
     273             :   /**
     274             :    * \returns The value of the \f$ i^{th} \f$ shape function at
     275             :    * point \p p.  This method lets you specify the relevant
     276             :    * data directly, and is therefore allowed to be static.
     277             :    *
     278             :    * \note This class member is not as efficient as its counterpart in
     279             :    * \p FE<Dim,T>, and is not employed in the \p reinit() cycle.
     280             :    *
     281             :    * \note This method does not return physically correct shapes,
     282             :    * instead use \p compute_data().  The \p shape() methods should
     283             :    * only be used for mapping.
     284             :    */
     285             :   static Real shape(const FEType & fet,
     286             :                     const Elem * elem,
     287             :                     const unsigned int i,
     288             :                     const Point & p);
     289             : 
     290             :   /**
     291             :    * \returns The value of the \f$ i^{th} \f$ shape function at
     292             :    * point \p p.  This method lets you specify the relevant
     293             :    * data directly, and is therefore allowed to be static.
     294             :    *
     295             :    * \note This class member is not as efficient as its counterpart in
     296             :    * \p FE<Dim,T>, and is not employed in the \p reinit() cycle.
     297             :    *
     298             :    * \note This method does not return physically correct shapes,
     299             :    * instead use \p compute_data().  The \p shape() methods should
     300             :    * only be used for mapping.
     301             :    */
     302             :   static Real shape(const FEType fet,
     303             :                     const Elem * elem,
     304             :                     const unsigned int i,
     305             :                     const Point & p,
     306             :                     const bool add_p_level);
     307             : 
     308             :   /**
     309             :    * \returns The \f$ j^{th} \f$ derivative of the \f$ i^{th} \f$
     310             :    * shape function at point \p p. This method lets you specify the relevant
     311             :    * data directly, and is therefore allowed to be static.
     312             :    *
     313             :    * \note This class member is not as efficient as its counterpart in
     314             :    * \p FE<Dim,T>, and is not employed in the \p reinit() cycle.
     315             :    *
     316             :    * \note This method does not return physically correct shape gradients,
     317             :    * instead use \p compute_data().  The \p shape_deriv() methods should
     318             :    * only be used for mapping.
     319             :    */
     320             :   static Real shape_deriv (const FEType & fet,
     321             :                            const Elem * inf_elem,
     322             :                            const unsigned int i,
     323             :                            const unsigned int j,
     324             :                            const Point & p);
     325             : 
     326             :   /**
     327             :    * \returns The \f$ j^{th} \f$ derivative of the \f$ i^{th} \f$
     328             :    * shape function at point \p p. This method lets you specify the relevant
     329             :    * data directly, and is therefore allowed to be static.
     330             :    *
     331             :    * \note This class member is not as efficient as its counterpart in
     332             :    * \p FE<Dim,T>, and is not employed in the \p reinit() cycle.
     333             :    *
     334             :    * \note This method does not return physically correct shape gradients,
     335             :    * instead use \p compute_data().  The \p shape_deriv() methods should
     336             :    * only be used for mapping.
     337             :    */
     338             :   static Real shape_deriv (const FEType fet,
     339             :                            const Elem * inf_elem,
     340             :                            const unsigned int i,
     341             :                            const unsigned int j,
     342             :                            const Point & p,
     343             :                            const bool add_p_level);
     344             : 
     345             :   /**
     346             :    * \returns The \f$ j^{th} \f$ derivative of the \f$ i^{th} \f$
     347             :    * shape function at point \p p. This method lets you specify the relevant
     348             :    * data directly, and is therefore allowed to be static.
     349             :    *
     350             :    * \note This class member is not as efficient as its counterpart in
     351             :    * \p FE<Dim,T>, and is not employed in the \p reinit() cycle.
     352             :    *
     353             :    * \note This method does not return physically correct shape gradients,
     354             :    * instead use \p compute_data().  The \p shape_deriv() methods should
     355             :    * only be used for mapping.
     356             :    */
     357             :   static Real shape_deriv (const FEType & fet,
     358             :                            const ElemType inf_elem_type,
     359             :                            const unsigned int i,
     360             :                            const unsigned int j,
     361             :                            const Point & p);
     362             : 
     363             :   /**
     364             :    * Generalized version of \p shape(), takes an \p Elem *.  The \p data
     365             :    * contains both input and output parameters.  For frequency domain
     366             :    * simulations, the complex-valued shape is returned.  In time domain
     367             :    * both the computed shape, and the phase is returned.
     368             :    *
     369             :    * \note The phase (proportional to the distance of the \p Point \p
     370             :    * data.p from the envelope) is actually a measure how far into the
     371             :    * future the results are.
     372             :    */
     373             :   static void compute_data(const FEType & fe_t,
     374             :                            const Elem * inf_elem,
     375             :                            FEComputeData & data);
     376             : 
     377             :   /**
     378             :    * \returns The number of shape functions associated with
     379             :    * a finite element of type \p t and approximation order \p o.
     380             :    */
     381           0 :   static unsigned int n_shape_functions (const FEType & fet,
     382             :                                          const Elem * inf_elem)
     383           0 :   { return n_dofs(fet, inf_elem); }
     384             : 
     385             :   /**
     386             :    * \returns The number of shape functions associated with this
     387             :    * infinite element.  Currently, we have \p o_radial+1 modes in
     388             :    * radial direction, and \code FE<Dim-1,T>::n_dofs(...) \endcode
     389             :    * in the base.
     390             :    */
     391             :   static unsigned int n_dofs(const FEType & fet,
     392             :                              const Elem * inf_elem);
     393             : 
     394             : #ifdef LIBMESH_ENABLE_DEPRECATED
     395             :   /**
     396             :    * \returns The number of dofs at infinite element node \p n
     397             :    * (not dof!) for an element of type \p t and order \p o.
     398             :    */
     399             :   static unsigned int n_dofs_at_node(const FEType & fet,
     400             :                                      const ElemType inf_elem_type,
     401             :                                      const unsigned int n);
     402             : #endif // LIBMESH_ENABLE_DEPRECATED
     403             : 
     404             :   /**
     405             :    * \returns The number of dofs at infinite element node \p n
     406             :    * (not dof!) for an element of type \p t and order \p o.
     407             :    */
     408             :   static unsigned int n_dofs_at_node(const FEType & fet,
     409             :                                      const Elem * inf_elem,
     410             :                                      const unsigned int n);
     411             : 
     412             : #ifdef LIBMESH_ENABLE_DEPRECATED
     413             :   /**
     414             :    * \returns The number of dofs interior to the element,
     415             :    * not associated with any interior nodes.
     416             :    *
     417             :    * \deprecated Call the version of this function that takes an Elem*
     418             :    * instead for consistency with other FEInterface::n_dofs() methods.
     419             :    */
     420             :   static unsigned int n_dofs_per_elem(const FEType & fet,
     421             :                                       const ElemType inf_elem_type);
     422             : #endif // LIBMESH_ENABLE_DEPRECATED
     423             : 
     424             :   /**
     425             :    * \returns The number of dofs interior to the element,
     426             :    * not associated with any interior nodes.
     427             :    */
     428             :   static unsigned int n_dofs_per_elem(const FEType & fet,
     429             :                                       const Elem * inf_elem);
     430             : 
     431             :   /**
     432             :    * \returns The continuity of the element.
     433             :    */
     434           0 :   virtual FEContinuity get_continuity() const override
     435           0 :   { return C_ZERO; }  // FIXME - is this true??
     436             : 
     437             :   /**
     438             :    * \returns \p true if the element's higher order shape functions are
     439             :    * hierarchic
     440             :    */
     441           0 :   virtual bool is_hierarchic() const override
     442           0 :   { return false; }  // FIXME - Inf FEs don't handle p elevation yet
     443             : 
     444             :   /**
     445             :    * Usually, this method would build the nodal soln from the
     446             :    * element soln.  But infinite elements require additional
     447             :    * simulation-specific data to compute physically correct
     448             :    * results.  Use \p compute_data() to compute results.  For
     449             :    * compatibility an empty vector is returned.
     450             :    */
     451             :   static void nodal_soln(const FEType & fet,
     452             :                          const Elem * elem,
     453             :                          const std::vector<Number> & elem_soln,
     454             :                          std::vector<Number> & nodal_soln);
     455             : 
     456             : 
     457           0 :   static Point map (const Elem * inf_elem,
     458             :                     const Point & reference_point)
     459             :   {
     460             :     // libmesh_deprecated(); // soon
     461           0 :     return InfFEMap::map(Dim, inf_elem, reference_point);
     462             :   }
     463             : 
     464             : 
     465           0 :   static Point inverse_map (const Elem * elem,
     466             :                             const Point & p,
     467             :                             const Real tolerance = TOLERANCE,
     468             :                             const bool secure = true)
     469             :   {
     470             :     // libmesh_deprecated(); // soon
     471           0 :     return InfFEMap::inverse_map(Dim, elem, p, tolerance, secure);
     472             :   }
     473             : 
     474             : 
     475           0 :   static void inverse_map (const Elem * elem,
     476             :                            const std::vector<Point> & physical_points,
     477             :                            std::vector<Point> &       reference_points,
     478             :                            const Real tolerance = TOLERANCE,
     479             :                            const bool secure = true)
     480             :   {
     481             :     // libmesh_deprecated(); // soon
     482           0 :     return InfFEMap::inverse_map(Dim, elem, physical_points,
     483           0 :                                  reference_points, tolerance, secure);
     484             :   }
     485             : 
     486             : 
     487             :   // The workhorses of InfFE. These are often used during matrix assembly.
     488             : 
     489             :   /**
     490             :    * This is at the core of this class. Use this for each
     491             :    * new element in the mesh.  Reinitializes all the physical
     492             :    * element-dependent data based on the current element
     493             :    * \p elem.
     494             :    * \note pts need to be in reference space coordinates, not physical ones.
     495             :    */
     496             :   virtual void reinit (const Elem * elem,
     497             :                        const std::vector<Point> * const pts = nullptr,
     498             :                        const std::vector<Real> * const weights = nullptr) override;
     499             : 
     500             :   /**
     501             :    * Reinitializes all the physical
     502             :    * element-dependent data based on the \p side of an infinite
     503             :    * element.
     504             :    */
     505             :   virtual void reinit (const Elem * inf_elem,
     506             :                        const unsigned int s,
     507             :                        const Real tolerance = TOLERANCE,
     508             :                        const std::vector<Point> * const pts = nullptr,
     509             :                        const std::vector<Real> * const weights = nullptr) override;
     510             : 
     511             :   /**
     512             :    * Not implemented yet.  Reinitializes all the physical
     513             :    * element-dependent data based on the \p edge of an infinite
     514             :    * element.
     515             :    */
     516             :   virtual void edge_reinit (const Elem * elem,
     517             :                             const unsigned int edge,
     518             :                             const Real tolerance = TOLERANCE,
     519             :                             const std::vector<Point> * const pts = nullptr,
     520             :                             const std::vector<Real> * const weights = nullptr) override;
     521             : 
     522             :   /**
     523             :    * Computes the reference space quadrature points on the side of
     524             :    * an element based on the side quadrature points.
     525             :    */
     526           0 :   virtual void side_map (const Elem * /* elem */,
     527             :                          const Elem * /* side */,
     528             :                          const unsigned int /* s */,
     529             :                          const std::vector<Point> & /* reference_side_points */,
     530             :                          std::vector<Point> & /* reference_points */) override
     531             :   {
     532           0 :     libmesh_not_implemented();
     533             :   }
     534             : 
     535             :   /**
     536             :    * The use of quadrature rules with the \p InfFE class is somewhat
     537             :    * different from the approach of the \p FE class.  While the
     538             :    * \p FE class requires an appropriately initialized quadrature
     539             :    * rule object, and simply uses it, the \p InfFE class requires only
     540             :    * the quadrature rule object of the current \p FE class.
     541             :    * From this \p QBase *, it determines the necessary data,
     542             :    * and builds two appropriate quadrature classes, one for radial,
     543             :    * and another for base integration, using the convenient
     544             :    * \p QBase::build() method.
     545             :    */
     546             :   virtual void attach_quadrature_rule (QBase * q) override;
     547             : 
     548             :   /**
     549             :    * \returns The number of shape functions associated with
     550             :    * this infinite element.
     551             :    */
     552           0 :   virtual unsigned int n_shape_functions () const override
     553           0 :   { return _n_total_approx_sf; }
     554             : 
     555             :   /**
     556             :    * \returns The total number of quadrature points.  Call this
     557             :    * to get an upper bound for the \p for loop in your simulation
     558             :    * for matrix assembly of the current element.
     559             :    */
     560        2592 :   virtual unsigned int n_quadrature_points () const override
     561        2592 :   { libmesh_assert(radial_qrule); return this->_n_total_qp; }
     562             : 
     563             :   /**
     564             :    * \returns the \p xyz spatial locations of the quadrature
     565             :    * points on the element.
     566             :    */
     567          15 :   virtual const std::vector<Point> & get_xyz () const override
     568           6 :   { libmesh_assert(!calculations_started || calculate_xyz);
     569          15 :     calculate_xyz = true; return xyz; }
     570             : 
     571             :   /**
     572             :    * \returns the Jacobian times quadrature weight.
     573             :    * Due to the divergence with increasing radial distance, this quantity
     574             :    * is numerically unstable.
     575             :    * Thus, it is safer to use \p get_JxWxdecay_sq() instead!
     576             :    */
     577           0 :   virtual const std::vector<Real> & get_JxW () const override
     578             :   {
     579           0 :     libmesh_assert(!calculations_started || calculate_jxw);
     580           0 :     calculate_jxw = true;
     581           0 :     return this->JxW;
     582             :   }
     583             : 
     584             :   /**
     585             :    * \returns Jacobian times quadrature weight times square of the
     586             :    *  decaying function \f$ decay= r^{-\frac{dim+1}{2}}\f$
     587             :    *
     588             :    * This function is the variant of \p get_JxW() for \p InfFE.
     589             :    * Since J diverges there, a respectize decay-function must be
     590             :    * applied to obtain well-defined quantities.
     591             :    */
     592        2597 :   virtual const std::vector<Real> & get_JxWxdecay_sq () const override
     593         866 :   { libmesh_assert(!calculations_started || calculate_map_scaled);
     594        2597 :     calculate_map_scaled = true; return this->JxWxdecay;}
     595             : 
     596             : 
     597             :   /**
     598             :    * \returns The shape function \p phi weighted by r/decay
     599             :    * where \f$ decay = r^{-\frac{dim+1}{2}} \f$
     600             :    *
     601             :    * To compensate for the decay function applied to the Jacobian (see \p get_JxWxdecay_sq),
     602             :    * the wave function \p phi should be divided by  this function.
     603             :    *
     604             :    * The factor r must be compensated for by the Sobolev \p weight.
     605             :    * (i.e. by using \p get_Sobolev_weightxR_sq())
     606             :    **/
     607        2597 :   virtual const std::vector<std::vector<OutputShape>> & get_phi_over_decayxR () const override
     608         866 :   { libmesh_assert(!calculations_started || calculate_phi_scaled);
     609        2597 :     calculate_phi_scaled = true; return phixr; }
     610             : 
     611             : 
     612             :   /**
     613             :    * \returns the gradient of the shape function (see \p get_dphi()),
     614             :    * but in case of \p InfFE, weighted with r/decay.
     615             :    * See \p  get_phi_over_decayxR() for details.
     616             :    */
     617        2597 :   virtual const std::vector<std::vector<OutputGradient>> & get_dphi_over_decayxR () const override
     618         866 :   { libmesh_assert(!calculations_started || calculate_dphi_scaled);
     619        2597 :     calculate_dphi_scaled = true; return dphixr; }
     620             : 
     621             : 
     622             :   /**
     623             :    * \returns the gradient of the shape function (see \p get_dphi()),
     624             :    * but in case of \p InfFE, weighted with 1/decay.
     625             :    *
     626             :    * In contrast to the shape function, its gradient stays finite
     627             :    * when divided by the decay function.
     628             :    */
     629           0 :   virtual const std::vector<std::vector<OutputGradient>> & get_dphi_over_decay () const override
     630           0 :   { libmesh_assert(!calculations_started || calculate_dphi_scaled);
     631           0 :     calculate_dphi_scaled = true; return dphixr_sq; }
     632             : 
     633             : 
     634             :   /**
     635             :    * \returns The element tangents in xi-direction at the quadrature
     636             :    * points.
     637             :    */
     638           0 :   virtual const std::vector<RealGradient> & get_dxyzdxi() const override
     639           0 :   { calculate_map = true; libmesh_not_implemented();}
     640             : 
     641             : 
     642             :   /**
     643             :    * \returns The element tangents in eta-direction at the quadrature
     644             :    * points.
     645             :    */
     646           0 :   virtual const std::vector<RealGradient> & get_dxyzdeta() const override
     647           0 :   { calculate_map = true; libmesh_not_implemented();}
     648             : 
     649             : 
     650             :   /**
     651             :    * \returns The element tangents in zeta-direction at the quadrature
     652             :    * points.
     653             :    */
     654           0 :   virtual const std::vector<RealGradient> & get_dxyzdzeta() const override
     655           0 :   { calculate_map = true; libmesh_not_implemented();}
     656             : 
     657             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     658             :   /**
     659             :    * \returns The second partial derivatives in xi.
     660             :    */
     661           0 :   virtual const std::vector<RealGradient> & get_d2xyzdxi2() const override
     662           0 :   { calculate_map = true; libmesh_not_implemented();}
     663             :   /**
     664             :    * \returns The second partial derivatives in eta.
     665             :    */
     666           0 :   virtual const std::vector<RealGradient> & get_d2xyzdeta2() const override
     667           0 :   { calculate_map = true; libmesh_not_implemented();}
     668             :   /**
     669             :    * \returns The second partial derivatives in zeta.
     670             :    */
     671           0 :   virtual const std::vector<RealGradient> & get_d2xyzdzeta2() const override
     672           0 :   { calculate_map = true; libmesh_not_implemented();}
     673             :   /**
     674             :    * \returns The second partial derivatives in xi-eta.
     675             :    */
     676           0 :   virtual const std::vector<RealGradient> & get_d2xyzdxideta() const override
     677           0 :   { calculate_map = true; libmesh_not_implemented();}
     678             :   /**
     679             :    * \returns The second partial derivatives in xi-zeta.
     680             :    */
     681           0 :   virtual const std::vector<RealGradient> & get_d2xyzdxidzeta() const override
     682           0 :   { calculate_map = true; libmesh_not_implemented();}
     683             :   /**
     684             :    * \returns The second partial derivatives in eta-zeta.
     685             :    */
     686           0 :   virtual const std::vector<RealGradient> & get_d2xyzdetadzeta() const override
     687           0 :   { calculate_map = true; libmesh_not_implemented();}
     688             : #endif
     689             : 
     690             :   /**
     691             :    * \returns The dxi/dx entry in the transformation
     692             :    * matrix from physical to local coordinates.
     693             :    */
     694           5 :   virtual const std::vector<Real> & get_dxidx() const override
     695           2 :   {libmesh_assert(!calculations_started || calculate_map);
     696           5 :     calculate_map = true; return dxidx_map;}
     697             : 
     698             : 
     699             :   /**
     700             :    * \returns The dxi/dy entry in the transformation
     701             :    * matrix from physical to local coordinates.
     702             :    */
     703           5 :   virtual const std::vector<Real> & get_dxidy() const override
     704           2 :   {libmesh_assert(!calculations_started || calculate_map);
     705           5 :     calculate_map = true; return dxidy_map;}
     706             : 
     707             : 
     708             :   /**
     709             :    * \returns The dxi/dz entry in the transformation
     710             :    * matrix from physical to local coordinates.
     711             :    */
     712           5 :   virtual const std::vector<Real> & get_dxidz() const override
     713           2 :   { libmesh_assert(!calculations_started || calculate_map);
     714           5 :     calculate_map = true; return dxidz_map;}
     715             : 
     716             : 
     717             :   /**
     718             :    * \returns The deta/dx entry in the transformation
     719             :    * matrix from physical to local coordinates.
     720             :    */
     721           5 :   virtual const std::vector<Real> & get_detadx() const override
     722           2 :   { libmesh_assert(!calculations_started || calculate_map);
     723           5 :     calculate_map = true; return detadx_map;}
     724             : 
     725             : 
     726             :   /**
     727             :    * \returns The deta/dy entry in the transformation
     728             :    * matrix from physical to local coordinates.
     729             :    */
     730           5 :   virtual const std::vector<Real> & get_detady() const override
     731           2 :   { libmesh_assert(!calculations_started || calculate_map);
     732           5 :     calculate_map = true; return detady_map;}
     733             : 
     734             : 
     735             :   /**
     736             :    * \returns The deta/dx entry in the transformation
     737             :    * matrix from physical to local coordinates.
     738             :    */
     739           5 :   virtual const std::vector<Real> & get_detadz() const override
     740           2 :   { libmesh_assert(!calculations_started || calculate_map);
     741           5 :     calculate_map = true; return detadz_map;}
     742             : 
     743             : 
     744             :   /**
     745             :    * \returns The dzeta/dx entry in the transformation
     746             :    * matrix from physical to local coordinates.
     747             :    */
     748          10 :   virtual const std::vector<Real> & get_dzetadx() const override
     749           4 :   { libmesh_assert(!calculations_started || calculate_map);
     750          10 :     calculate_map = true; return dzetadx_map;}
     751             : 
     752             : 
     753             :   /**
     754             :    * \returns The dzeta/dy entry in the transformation
     755             :    * matrix from physical to local coordinates.
     756             :    */
     757          10 :   virtual const std::vector<Real> & get_dzetady() const override
     758           4 :   { libmesh_assert(!calculations_started || calculate_map);
     759          10 :     calculate_map = true; return dzetady_map;}
     760             : 
     761             : 
     762             :   /**
     763             :    * \returns The dzeta/dz entry in the transformation
     764             :    * matrix from physical to local coordinates.
     765             :    */
     766          10 :   virtual const std::vector<Real> & get_dzetadz() const override
     767           4 :   { libmesh_assert(!calculations_started || calculate_map);
     768          10 :     calculate_map = true; return dzetadz_map;}
     769             : 
     770             : 
     771             :   /**
     772             :    * \returns The multiplicative weight at each quadrature point.
     773             :    * This weight is used for certain infinite element weak
     774             :    * formulations, so that weighted Sobolev spaces are
     775             :    * used for the trial function space.  This renders the
     776             :    * variational form easily computable.
     777             :    */
     778          15 :   virtual const std::vector<Real> & get_Sobolev_weight() const override
     779           6 :   { libmesh_assert(!calculations_started || calculate_phi);
     780          15 :     calculate_phi = true; return weight; }
     781             : 
     782             : 
     783             :   /**
     784             :    * \returns The first global derivative of the multiplicative
     785             :    * weight at each quadrature point. See \p get_Sobolev_weight()
     786             :    * for details.  In case of \p FE initialized to all zero.
     787             :    */
     788          10 :   virtual const std::vector<RealGradient> & get_Sobolev_dweight() const override
     789           4 :   {libmesh_assert(!calculations_started || calculate_dphi);
     790          10 :     calculate_dphi = true; return dweight; }
     791             : 
     792             : 
     793             : 
     794             :   /**
     795             :    * \returns The tangent vectors for face integration.
     796             :    */
     797           5 :   virtual const std::vector<std::vector<Point>> & get_tangents() const override
     798           2 :   { libmesh_assert(!calculations_started || calculate_map);
     799           5 :     calculate_map = true; return tangents; }
     800             : 
     801             :   /**
     802             :    * \returns The outward pointing normal vectors for face integration.
     803             :    */
     804           5 :   virtual const std::vector<Point> & get_normals() const override
     805           2 :   { libmesh_assert(!calculations_started || calculate_map);
     806           5 :     calculate_map = true; return normals; }
     807             : 
     808             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     809             :   /**
     810             :    * \returns The curvatures for use in face integration.
     811             :    */
     812           0 :   virtual const std::vector<Real> & get_curvatures() const override
     813           0 :   { calculate_map = true; libmesh_not_implemented();}
     814             : #endif
     815             : 
     816             :   /**
     817             :    * \returns The multiplicative weight (see \p get_Sobolev_weight())
     818             :    * but weighted with the radial coordinate square.
     819             :    *
     820             :    */
     821        2597 :   virtual const std::vector<Real> & get_Sobolev_weightxR_sq() const override
     822         866 :   { libmesh_assert(!calculations_started || calculate_phi_scaled);
     823        2597 :     calculate_phi_scaled = true; return weightxr_sq; }
     824             : 
     825             : 
     826             :   /**
     827             :    * \returns The first global derivative of the multiplicative
     828             :    * weight (see \p get_Sobolev_weight())
     829             :    * but weighted with the radial coordinate square.
     830             :    *
     831             :    */
     832        2597 :   virtual const std::vector<RealGradient> & get_Sobolev_dweightxR_sq() const override
     833         866 :   {libmesh_assert(!calculations_started || calculate_dphi_scaled);
     834        2597 :     calculate_dphi_scaled = true; return dweightxr_sq; }
     835             : 
     836             : 
     837             : #ifdef LIBMESH_ENABLE_AMR
     838             : 
     839             :   /**
     840             :    * Computes the constraint matrix contributions (for
     841             :    * non-conforming adapted meshes) corresponding to
     842             :    * variable number \p var_number, adapted to infinite elements.
     843             :    */
     844             :   static void inf_compute_constraints (DofConstraints & constraints,
     845             :                                        DofMap & dof_map,
     846             :                                        const unsigned int variable_number,
     847             :                                        const Elem * child_elem);
     848             : #endif
     849             : 
     850             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
     851             :   static void inf_compute_node_constraints (NodeConstraints & constraints,
     852             :                                             const Elem * elem);
     853             : #endif
     854             : 
     855             : 
     856             : protected:
     857             : 
     858             :   // static members used by the workhorses
     859             : 
     860             :   /**
     861             :    * \returns The value of the \f$ i^{th} \f$ polynomial evaluated
     862             :    * at \p v.  This method provides the approximation
     863             :    * in radial direction for the overall shape functions,
     864             :    * which is defined in \p InfFE::shape().
     865             :    * This method is allowed to be static, since it is independent
     866             :    * of dimension and base_family.  It is templated, though,
     867             :    * w.r.t. to radial \p FEFamily.
     868             :    *
     869             :    * \returns The value of the \f$ i^{th} \f$ mapping shape function
     870             :    * in radial direction evaluated at \p v when T_radial ==
     871             :    * INFINITE_MAP.  Currently, only one specific mapping shape is
     872             :    * used.  Namely the one by Marques JMMC, Owen DRJ: Infinite
     873             :    * elements in quasi-static materially nonlinear problems, Computers
     874             :    * and Structures, 1984.
     875             :    */
     876             :   static Real eval(Real v,
     877             :                    Order o_radial,
     878             :                    unsigned int i);
     879             : 
     880             :   /**
     881             :    * \returns The value of the first derivative of the
     882             :    * \f$ i^{th} \f$ polynomial at coordinate \p v.
     883             :    * See \p eval for details.
     884             :    */
     885             :   static Real eval_deriv(Real v,
     886             :                          Order o_radial,
     887             :                          unsigned int i);
     888             : 
     889             : 
     890             : 
     891             :   // Non-static members used by the workhorses
     892             : 
     893             :   /**
     894             :    * Updates the protected member \p base_elem to the appropriate base element
     895             :    * for the given \p inf_elem.
     896             :    */
     897             :   void update_base_elem (const Elem * inf_elem);
     898             : 
     899             :   /**
     900             :    * Do not use this derived member in \p InfFE<Dim,T_radial,T_map>.
     901             :    */
     902           0 :   virtual void init_base_shape_functions(const std::vector<Point> &,
     903             :                                          const Elem *) override
     904           0 :   { libmesh_not_implemented(); }
     905             : 
     906             :   /**
     907             :    * Determine which values are to be calculated, for both the FE
     908             :    * itself and for the FEMap.
     909             :    */
     910             :   virtual void determine_calculations() override;
     911             : 
     912             :   /**
     913             :    * Some of the member data only depend on the radial part of the
     914             :    * infinite element.  The parts that only change when the radial
     915             :    * order changes, are initialized here.
     916             :    */
     917             :   void init_radial_shape_functions(const Elem * inf_elem,
     918             :                                    const std::vector<Point> * radial_pts = nullptr);
     919             : 
     920             :   /**
     921             :    * Initialize all the data fields like \p weight, \p mode,
     922             :    * \p phi, \p dphidxi, \p dphideta, \p dphidzeta, etc.
     923             :    * for the current element.  This method prepares the data
     924             :    * related to the base part, and some of the combined fields.
     925             :    */
     926             :   void init_shape_functions(const std::vector<Point> & radial_qp,
     927             :                             const std::vector<Point> & base_qp,
     928             :                             const Elem * inf_elem);
     929             : 
     930             :   /**
     931             :    * Initialize all the data fields like \p weight,
     932             :    * \p phi, etc for the side \p s.
     933             :    */
     934             :   void init_face_shape_functions (const std::vector<Point> &,
     935             :                                   const Elem * inf_side);
     936             : 
     937             :   /**
     938             :    * After having updated the jacobian and the transformation
     939             :    * from local to global coordinates in FEAbstract::compute_map(),
     940             :    * the first derivatives of the shape functions are
     941             :    * transformed to global coordinates, giving \p dphi,
     942             :    * \p dphidx/y/z, \p dphasedx/y/z, \p dweight. This method
     943             :    * should barely be re-defined in derived classes, but
     944             :    * still should be usable for children. Therefore, keep
     945             :    * it protected.
     946             :    */
     947             :   void compute_shape_functions(const Elem * inf_elem,
     948             :                                const std::vector<Point> & base_qp,
     949             :                                const std::vector<Point> & radial_qp);
     950             : 
     951             :   void compute_face_functions();
     952             : 
     953             :   /**
     954             :    * Use \p compute_shape_functions(const Elem*, const std::vector<Point> &, const std::vector<Point> &)
     955             :    * instead.
     956             :    */
     957           0 :   virtual void compute_shape_functions(const Elem *, const std::vector<Point> & ) override
     958             :   {
     959             :     //FIXME: it seems this function cannot be left out because
     960             :     // it is pure virtual in \p FEBase
     961           0 :     libmesh_not_implemented();
     962             :   }
     963             : 
     964             :   /**
     965             :    * Are we calculating scaled mapping functions?
     966             :    */
     967             :   mutable bool calculate_map_scaled;
     968             : 
     969             :   /**
     970             :    * Are we calculating scaled shape functions?
     971             :    */
     972             :   mutable bool calculate_phi_scaled;
     973             : 
     974             :   /**
     975             :    * Are we calculating scaled shape function gradients?
     976             :    */
     977             :   mutable bool calculate_dphi_scaled;
     978             : 
     979             : 
     980             :   /**
     981             :    * Are we calculating the positions of quadrature points?
     982             :    */
     983             :   mutable bool calculate_xyz;
     984             : 
     985             : 
     986             :   /**
     987             :    * Are we calculating the unscaled jacobian?
     988             :    * We avoid it if not requested explicitly; this has the worst stability.
     989             :    */
     990             :   mutable bool calculate_jxw;
     991             : 
     992             :   // Miscellaneous static members
     993             : 
     994             :   /**
     995             :    * Computes the indices in the base \p base_node and in radial
     996             :    * direction \p radial_node (either 0 or 1) associated to the
     997             :    * node \p outer_node_index of an infinite element of type
     998             :    * \p inf_elem_type.
     999             :    */
    1000             :   static void compute_node_indices (const ElemType inf_elem_type,
    1001             :                                     const unsigned int outer_node_index,
    1002             :                                     unsigned int & base_node,
    1003             :                                     unsigned int & radial_node);
    1004             : 
    1005             :   /**
    1006             :    * Does the same as \p compute_node_indices(), but stores
    1007             :    * the maps for the current element type.  Provided the
    1008             :    * infinite element type changes seldom, this is probably
    1009             :    * faster than using \p compute_node_indices () alone.
    1010             :    * This is possible since the number of nodes is not likely
    1011             :    * to change.
    1012             :    */
    1013             :   static void compute_node_indices_fast (const ElemType inf_elem_type,
    1014             :                                          const unsigned int outer_node_index,
    1015             :                                          unsigned int & base_node,
    1016             :                                          unsigned int & radial_node);
    1017             : 
    1018             : #ifdef LIBMESH_ENABLE_DEPRECATED
    1019             :   /*
    1020             :    * \deprecated Call the version of this function that takes an Elem * instead.
    1021             :    */
    1022             :   static void compute_shape_indices (const FEType & fet,
    1023             :                                      const ElemType inf_elem_type,
    1024             :                                      const unsigned int i,
    1025             :                                      unsigned int & base_shape,
    1026             :                                      unsigned int & radial_shape);
    1027             : #endif // LIBMESH_ENABLE_DEPRECATED
    1028             : 
    1029             :   /**
    1030             :    * Computes the indices of shape functions in the base \p base_shape and
    1031             :    * in radial direction \p radial_shape (0 in the base, \f$ \ge 1 \f$ further
    1032             :    * out) associated to the shape with global index \p i of an infinite element
    1033             :    * \p inf_elem.
    1034             :    */
    1035             :   static void compute_shape_indices (const FEType & fet,
    1036             :                                      const Elem * inf_elem,
    1037             :                                      const unsigned int i,
    1038             :                                      unsigned int & base_shape,
    1039             :                                      unsigned int & radial_shape);
    1040             : 
    1041             :   /**
    1042             :    * Physical quadrature points.
    1043             :    * Usually, this is obtained from the \p FEMap class,
    1044             :    * but here FEMap does not know enough to compute it.
    1045             :    */
    1046             :   std::vector<Point> xyz;
    1047             : 
    1048             :   std::vector<Real> weightxr_sq;
    1049             :   /**
    1050             :    * the additional radial weight \f$ 1/{r^2} \f$ in local coordinates,
    1051             :    * over all quadrature points. The weight does not vary in base
    1052             :    * direction.  However, for uniform access to the data fields from the
    1053             :    * outside, this data field is expanded to all quadrature points.
    1054             :    */
    1055             :   std::vector<Real> dweightdv;
    1056             : 
    1057             :   std::vector<RealGradient> dweightxr_sq;
    1058             : 
    1059             :   /**
    1060             :    * the radial decay \f$ 1/r \f$ in local coordinates.  Needed when
    1061             :    * setting up the overall shape functions.
    1062             :    *
    1063             :    * \note It is this decay which ensures that the Sommerfeld
    1064             :    * radiation condition is satisfied in advance.
    1065             :    */
    1066             :   std::vector<Real> som;
    1067             :   /**
    1068             :    * the first local derivative of the radial decay \f$ 1/r \f$ in local
    1069             :    * coordinates.  Needed when setting up the overall shape functions.
    1070             :    */
    1071             :   std::vector<Real> dsomdv;
    1072             : 
    1073             :   /**
    1074             :    * the radial approximation shapes in local coordinates
    1075             :    * Needed when setting up the overall shape functions.
    1076             :    */
    1077             :   std::vector<std::vector<Real>> mode;
    1078             : 
    1079             :   /**
    1080             :    * the first local derivative of the radial approximation shapes.
    1081             :    * Needed when setting up the overall shape functions.
    1082             :    */
    1083             :   std::vector<std::vector<Real>> dmodedv;
    1084             : 
    1085             :   // mapping of reference element to physical element
    1086             :   // These vectors usually belong to \p this->fe_map
    1087             :   // but for infinite elements, \p FEMap cannot
    1088             :   // compute them.
    1089             :   std::vector<Real> dxidx_map;
    1090             :   std::vector<Real> dxidy_map;
    1091             :   std::vector<Real> dxidz_map;
    1092             :   std::vector<Real> detadx_map;
    1093             :   std::vector<Real> detady_map;
    1094             :   std::vector<Real> detadz_map;
    1095             :   std::vector<Real> dzetadx_map;
    1096             :   std::vector<Real> dzetady_map;
    1097             :   std::vector<Real> dzetadz_map;
    1098             : 
    1099             :   // scaled mapping: Similar to the above
    1100             :   // vectors, but scaled by radial (infinite) coordinate.
    1101             :   std::vector<Real> dxidx_map_scaled;
    1102             :   std::vector<Real> dxidy_map_scaled;
    1103             :   std::vector<Real> dxidz_map_scaled;
    1104             :   std::vector<Real> detadx_map_scaled;
    1105             :   std::vector<Real> detady_map_scaled;
    1106             :   std::vector<Real> detadz_map_scaled;
    1107             :   std::vector<Real> dzetadx_map_scaled;
    1108             :   std::vector<Real> dzetady_map_scaled;
    1109             :   std::vector<Real> dzetadz_map_scaled;
    1110             : 
    1111             : 
    1112             :   // respectively weighted shape functions.
    1113             :   //FIXME: these names are correct only in 3D
    1114             :   //      but avoid long and clumbsy names...
    1115             :   std::vector<std::vector<Real>> phixr;
    1116             :   std::vector<std::vector<RealGradient>> dphixr;
    1117             :   std::vector<std::vector<RealGradient>> dphixr_sq;
    1118             : 
    1119             :   std::vector<Real> JxWxdecay;
    1120             :   std::vector<Real> JxW;
    1121             : 
    1122             :   std::vector<Point> normals;
    1123             :   std::vector<std::vector<Point>> tangents;
    1124             : 
    1125             :   // numbering scheme maps
    1126             : 
    1127             :   /**
    1128             :    * The internal structure of the \p InfFE
    1129             :    * -- tensor product of base element times radial
    1130             :    * nodes -- has to be determined from the node numbering
    1131             :    * of the current infinite element.  This vector
    1132             :    * maps the infinite \p Elem node number to the
    1133             :    * radial node (either 0 or 1).
    1134             :    */
    1135             :   std::vector<unsigned int> _radial_node_index;
    1136             : 
    1137             :   /**
    1138             :    * The internal structure of the \p InfFE
    1139             :    * -- tensor product of base element times radial
    1140             :    * nodes -- has to be determined from the node numbering
    1141             :    * of the current element.  This vector
    1142             :    * maps the infinite \p Elem node number to the
    1143             :    * associated node in the base element.
    1144             :    */
    1145             :   std::vector<unsigned int> _base_node_index;
    1146             : 
    1147             :   /**
    1148             :    * The internal structure of the \p InfFE
    1149             :    * -- tensor product of base element shapes times radial
    1150             :    * shapes -- has to be determined from the dof numbering
    1151             :    * scheme of the current infinite element.  This vector
    1152             :    * maps the infinite \p Elem dof index to the radial
    1153             :    * \p InfFE shape index (\p 0..radial_order+1 ).
    1154             :    */
    1155             :   std::vector<unsigned int> _radial_shape_index;
    1156             : 
    1157             :   /**
    1158             :    * The internal structure of the \p InfFE
    1159             :    * -- tensor product of base element shapes times radial
    1160             :    * shapes -- has to be determined from the dof numbering
    1161             :    * scheme of the current infinite element.  This vector
    1162             :    * maps the infinite \p Elem dof index to the associated
    1163             :    * dof in the base \p FE.
    1164             :    */
    1165             :   std::vector<unsigned int> _base_shape_index;
    1166             : 
    1167             :   // some more protected members
    1168             : 
    1169             :   /**
    1170             :    * The number of total approximation shape functions for
    1171             :    * the current configuration
    1172             :    */
    1173             :   unsigned int _n_total_approx_sf;
    1174             : 
    1175             :   /**
    1176             :    * this vector contains the combined integration weights, so
    1177             :    * that \p FEAbstract::compute_map() can still be used
    1178             :    */
    1179             :   std::vector<Real> _total_qrule_weights;
    1180             : 
    1181             :   /**
    1182             :    * The quadrature rule for the base element associated
    1183             :    * with the current infinite element
    1184             :    */
    1185             :   std::unique_ptr<QBase> base_qrule;
    1186             : 
    1187             :   /**
    1188             :    * The quadrature rule for the base element associated
    1189             :    * with the current infinite element
    1190             :    */
    1191             :   std::unique_ptr<QBase> radial_qrule;
    1192             : 
    1193             :   /**
    1194             :    * The "base" (aka non-infinite) element associated with the current
    1195             :    * infinite element. We treat is as const since the InfFE should not
    1196             :    * have to modify the geometric Elem in order to do its calculations.
    1197             :    */
    1198             :   std::unique_ptr<const Elem> base_elem;
    1199             : 
    1200             :   /**
    1201             :    * Have a \p FE<Dim-1,T_base> handy for base approximation.
    1202             :    * Since this one is created using the \p FEBase::build() method,
    1203             :    * the \p InfFE class is not required to be templated w.r.t.
    1204             :    * to the base approximation shape.
    1205             :    */
    1206             :   std::unique_ptr<FEBase> base_fe;
    1207             : 
    1208             :   /**
    1209             :    * This \p FEType stores the characteristics for which the data
    1210             :    * structures \p phi, \p phi_map etc are currently initialized.
    1211             :    * This avoids re-initializing the radial part.
    1212             :    *
    1213             :    * \note Currently only \p order may change, both the FE families
    1214             :    * and \p base_order must remain constant.
    1215             :    */
    1216             :   FEType current_fe_type;
    1217             : 
    1218             : 
    1219             : private:
    1220             : 
    1221             :   /**
    1222             :    * \returns \p false, currently not required.
    1223             :    */
    1224             :   virtual bool shapes_need_reinit() const override;
    1225             : 
    1226             :   /**
    1227             :    * When \p compute_node_indices_fast() is used, this static
    1228             :    * variable remembers the element type for which the
    1229             :    * static variables in  \p compute_node_indices_fast()
    1230             :    * are currently set.  Using a class member for the
    1231             :    * element type helps initializing it to a default value.
    1232             :    */
    1233             :   static ElemType _compute_node_indices_fast_current_elem_type;
    1234             : 
    1235             : 
    1236             : #ifdef DEBUG
    1237             : 
    1238             :   /**
    1239             :    * static members that are used to issue warning messages only once.
    1240             :    */
    1241             :   static bool _warned_for_nodal_soln;
    1242             :   static bool _warned_for_shape;
    1243             :   static bool _warned_for_dshape;
    1244             : 
    1245             : #endif
    1246             : 
    1247             :   /**
    1248             :    * Make all \p InfFE<Dim,T_radial,T_map> classes
    1249             :    * friends of each other, so that the protected
    1250             :    * \p eval() may be accessed.
    1251             :    */
    1252             :   template <unsigned int friend_Dim, FEFamily friend_T_radial, InfMapType friend_T_map>
    1253             :   friend class InfFE;
    1254             : 
    1255             :   friend class InfFEMap;
    1256             : };
    1257             : 
    1258             : 
    1259             : 
    1260             : // InfFERadial class inline members
    1261             : // FIXME: decay in 3D is a/r
    1262             : //   thus, this function fixes the mapping v<->r explicitly.
    1263             : //   This is consistent with the current InfFEMap, which, however, is
    1264             : //   written such that more general mappings can be implemented.
    1265             : inline
    1266        1896 : Real InfFERadial::decay(const unsigned int dim, const Real v)
    1267             : {
    1268        1896 :   switch (dim)
    1269             :     {
    1270        1896 :     case 3:
    1271        1896 :       return (1.-v)/2.;
    1272             : 
    1273           0 :     case 2:
    1274             :       // according to P. Bettess "Infinite Elements",
    1275             :       // the 2D case is rather tricky:
    1276             :       //  - the sqrt() requires special integration rules
    1277             :       //    if not both trial- and test function are involved
    1278             :       //  - the analytic solutions contain not only the sqrt, but
    1279             :       //    also a polynomial with rather many terms, so convergence
    1280             :       //    might be bad.
    1281           0 :       return sqrt((1.-v)/2.);
    1282             : 
    1283           0 :     case 1:
    1284           0 :       return 1.;
    1285             : 
    1286           0 :     default:
    1287           0 :       libmesh_error_msg("Invalid dim = " << dim);
    1288             :     }
    1289             : }
    1290             : 
    1291             : inline
    1292         560 : Real InfFERadial::decay_deriv (const unsigned int dim, const Real v)
    1293             : {
    1294         560 :   switch (dim)
    1295             :     {
    1296         224 :     case 3:
    1297         224 :       return -0.5;
    1298             : 
    1299           0 :     case 2:
    1300             :       // according to P. Bettess "Infinite Elements",
    1301             :       // the 2D case is rather tricky:
    1302             :       //  - the sqrt() requires special integration rules
    1303             :       //    if not both trial- and test function are involved
    1304             :       //  - the analytic solutions contain not only the sqrt, but
    1305             :       //    also a polynomial with rather many terms, so convergence
    1306             :       //    might be bad.
    1307             : 
    1308           0 :       libmesh_assert (-1.-1.e-5 <= v && v < 1.);
    1309           0 :       return -0.25/sqrt(1.-v);
    1310             : 
    1311           0 :     case 1:
    1312           0 :       return 0.;
    1313             : 
    1314           0 :     default:
    1315           0 :       libmesh_error_msg("Invalid dim = " << dim);
    1316             :     }
    1317             : }
    1318             : 
    1319             : } // namespace libMesh
    1320             : 
    1321             : 
    1322             : #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    1323             : 
    1324             : 
    1325             : #endif // LIBMESH_INF_FE_H

Generated by: LCOV version 1.14