LCOV - code coverage report
Current view: top level - src/fe - inf_fe.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 452 501 90.2 %
Date: 2025-08-19 19:27:09 Functions: 32 135 23.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : // Local includes
      21             : #include "libmesh/libmesh_config.h"
      22             : 
      23             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
      24             : 
      25             : #include "libmesh/inf_fe.h"
      26             : #include "libmesh/fe.h"
      27             : #include "libmesh/quadrature_gauss.h"
      28             : #include "libmesh/elem.h"
      29             : #include "libmesh/libmesh_logging.h"
      30             : #include "libmesh/int_range.h"
      31             : #include "libmesh/type_tensor.h"
      32             : #include "libmesh/fe_interface.h"
      33             : 
      34             : #include <memory>
      35             : 
      36             : namespace libMesh
      37             : {
      38             : 
      39             : 
      40             : 
      41             : // Constructor
      42             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      43         494 : InfFE<Dim,T_radial,T_map>::InfFE (const FEType & fet) :
      44             :   FEBase       (Dim, fet),
      45             : 
      46         120 :   calculate_map_scaled(false),
      47         120 :   calculate_phi_scaled(false),
      48         120 :   calculate_dphi_scaled(false),
      49         120 :   calculate_xyz(false),
      50         120 :   calculate_jxw(false),
      51         120 :   _n_total_approx_sf (0),
      52             : 
      53             :   // initialize the current_fe_type to all the same
      54             :   // values as \p fet (since the FE families and coordinate
      55             :   // map type should not change), but use an invalid order
      56             :   // for the radial part (since this is the only order
      57             :   // that may change!).
      58             :   // the data structures like \p phi etc are not initialized
      59             :   // through the constructor, but through reinit()
      60         374 :   current_fe_type (FEType(fet.order,
      61         494 :                           fet.family,
      62             :                           INVALID_ORDER,
      63         494 :                           fet.radial_family,
      64         494 :                           fet.inf_map))
      65             : 
      66             : {
      67             :   // Sanity checks
      68         189 :   libmesh_assert_equal_to (T_radial, fe_type.radial_family);
      69         189 :   libmesh_assert_equal_to (T_map, fe_type.inf_map);
      70             : 
      71             :   // build the base_fe object
      72             :   if (Dim != 1)
      73         614 :     base_fe = FEBase::build(Dim-1, fet);
      74         494 : }
      75             : 
      76             : 
      77             : 
      78             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
      79          90 : void InfFE<Dim,T_radial,T_map>::attach_quadrature_rule (QBase * q)
      80             : {
      81          36 :   libmesh_assert(q);
      82          36 :   libmesh_assert(base_fe);
      83             : 
      84          72 :   const Order base_int_order   = q->get_order();
      85          90 :   const Order radial_int_order = static_cast<Order>(2 * (static_cast<unsigned int>(fe_type.radial_order.get_order()) + 1) +2);
      86          72 :   const unsigned int qrule_dim = q->get_dim();
      87             : 
      88             :   if (Dim != 1)
      89             :     {
      90             :       // build a Dim-1 quadrature rule of the type that we received
      91         144 :       base_qrule = QBase::build(q->type(), qrule_dim-1, base_int_order);
      92         126 :       base_fe->attach_quadrature_rule(base_qrule.get());
      93             :     }
      94             : 
      95             :   // in radial direction, always use Gauss quadrature
      96          90 :   radial_qrule = std::make_unique<QGauss>(1, radial_int_order);
      97             : 
      98             :   // Maybe helpful to store the QBase *
      99             :   // with which we initialized our own quadrature rules.
     100             :   // Used e.g. in \p InfFE::reinit(elem,side)
     101          90 :   qrule = q;
     102          90 : }
     103             : 
     104             : 
     105             : 
     106             : 
     107             : 
     108             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_base>
     109        4003 : void InfFE<Dim,T_radial,T_base>::update_base_elem (const Elem * inf_elem)
     110             : {
     111        5572 :   base_elem = InfFEBase::build_elem(inf_elem);
     112        4003 : }
     113             : 
     114             : 
     115             : 
     116             : 
     117             : 
     118             : 
     119             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     120        3998 : void InfFE<Dim,T_radial,T_map>::reinit(const Elem * inf_elem,
     121             :                                        const std::vector<Point> * const pts,
     122             :                                        const std::vector<Real> * const weights)
     123             : {
     124        1215 :   libmesh_assert(base_fe.get());
     125        1215 :   libmesh_assert(inf_elem);
     126             : 
     127             :   // checks for consistency of requested calculations,
     128             :   // adds further quantities as needed.
     129        3998 :   this->determine_calculations();
     130             : 
     131        3998 :   if (pts == nullptr)
     132             :     {
     133         890 :       libmesh_assert(base_fe->qrule);
     134         890 :       libmesh_assert_equal_to (base_fe->qrule, base_qrule.get());
     135         890 :       libmesh_assert(radial_qrule.get());
     136             : 
     137         890 :       bool init_shape_functions_required = false;
     138             : 
     139             :       // init the radial data fields only when the radial order changes
     140        2657 :       if (current_fe_type.radial_order != fe_type.radial_order)
     141             :         {
     142          85 :           current_fe_type.radial_order = fe_type.radial_order;
     143             : 
     144             :           // Watch out: this call to QBase->init() only works for
     145             :           // current_fe_type = const!   To allow variable Order,
     146             :           // the init() of QBase has to be modified...
     147          85 :           radial_qrule->init(EDGE2);
     148             : 
     149             :           // initialize the radial shape functions
     150          85 :           this->init_radial_shape_functions(inf_elem);
     151             : 
     152          34 :           init_shape_functions_required=true;
     153             :         }
     154             : 
     155             : 
     156         890 :       bool update_base_elem_required=true;
     157             : 
     158             :       // update the type in accordance to the current cell
     159             :       // and reinit if the cell type has changed or (as in
     160             :       // the case of the hierarchics) the shape functions
     161             :       // depend on the particular element and need a reinit
     162         890 :       if ((Dim != 1) &&
     163        4603 :           ((this->get_type() != inf_elem->type())  ||
     164        1946 :            (base_fe->shapes_need_reinit())))
     165             :         {
     166             :           // store the new element type, update base_elem
     167             :           // here.  Through \p update_base_elem_required,
     168             :           // remember whether it has to be updated (see below).
     169         711 :           this->_elem = inf_elem;
     170         711 :           this->_elem_type = inf_elem->type();
     171         711 :           this->update_base_elem(inf_elem);
     172         242 :           update_base_elem_required=false;
     173             : 
     174             :           // initialize the base quadrature rule for the new element
     175         953 :           base_qrule->init(*base_elem);
     176         242 :           init_shape_functions_required=true;
     177             : 
     178             :         }
     179             :       else
     180        1946 :         this->_elem = inf_elem;
     181             : 
     182             :       // computing the reference-to-physical map and coordinates works
     183             :       // only, if we have the current base_elem stored.
     184             :       // This happens when fe_type is const,
     185             :       // the inf_elem->type remains the same.  Then we have to
     186             :       // update the base elem _here_.
     187         890 :       if (update_base_elem_required)
     188        1946 :         this->update_base_elem(inf_elem);
     189             : 
     190        2657 :       if (calculate_phi_scaled || calculate_dphi_scaled || calculate_phi || calculate_dphi)
     191             :         // initialize the shape functions in the base
     192        4437 :         base_fe->init_base_shape_functions(base_fe->qrule->get_points(),
     193             :                                            base_elem.get());
     194             : 
     195             :       // compute the shape functions and map functions of base_fe
     196             :       // before using them later in compute_shape_functions.
     197        4437 :       base_fe->_fe_map->compute_map (base_fe->dim, base_fe->qrule->get_weights(),
     198        2657 :                                      base_elem.get(), base_fe->calculate_d2phi);
     199        3547 :       base_fe->compute_shape_functions(base_elem.get(), base_fe->qrule->get_points());
     200             : 
     201             :       // when either the radial or base part change,
     202             :       // we have to init the whole fields
     203        2657 :       if (init_shape_functions_required)
     204         711 :         this->init_shape_functions (radial_qrule->get_points(),
     205         711 :                                     base_fe->qrule->get_points(),
     206             :                                     inf_elem);
     207             : 
     208             :       // Compute the shape functions and the derivatives
     209             :       // at all quadrature points.
     210        2657 :       this->compute_shape_functions (inf_elem,
     211        2657 :                                      base_fe->qrule->get_points(),
     212         890 :                                      radial_qrule->get_points()
     213             :                                      /* weights are computed inside the function*/
     214             :                                      );
     215             :     }
     216             : 
     217             :   else // if pts != nullptr
     218             :     {
     219             :       // update the elem
     220        1341 :       this->_elem = inf_elem;
     221        1341 :       this->_elem_type = inf_elem->type();
     222             : 
     223             :       // We'll assume that pts is a tensor product mesh of points.
     224             :       // pts[i] = pts[ angular_index + n_angular_pts * radial_index]
     225             :       // That will handle the pts.size()==1 case that we care about
     226             :       // right now, and it will generalize a bit, and it won't break
     227             :       // the assumptions elsewhere in InfFE.
     228         650 :       std::vector<Point> radial_pts;
     229        1341 :       if (pts->size() > 0)
     230             :         {
     231        1341 :           Real radius = (*pts)[0](Dim-1);
     232        1341 :           radial_pts.push_back(radius);
     233         325 :           unsigned int n_radial_pts=1;
     234         325 :           unsigned int n_angular_pts=1;
     235        1561 :           for (auto p : IntRange<std::size_t>(1, pts->size()))
     236             :             {
     237         220 :               radius = (*pts)[p](Dim-1);
     238             :               // check for changes of radius: The max. allowed distance is somewhat arbitrary
     239             :               // but the given value should not produce false positives...
     240         396 :               if (std::abs(radial_pts[n_radial_pts-1](0) - radius) > 1e-4)
     241             :                 {
     242             :                   // it may change only every n_angular_pts:
     243          65 :                   if (p == (n_radial_pts)*n_angular_pts)
     244             :                     {
     245          26 :                       radial_pts.push_back(radius);
     246          65 :                       ++n_radial_pts;
     247             :                     }
     248             :                   else
     249             :                     {
     250           0 :                       libmesh_error_msg("We assumed that the "<<pts->size()
     251             :                                         <<" points are of tensor-product type with "
     252             :                                         <<n_radial_pts<<" radial points and "
     253             :                                         <<n_angular_pts<< " angular points."<<std::endl
     254             :                                         <<"But apparently point "<<p+1
     255             :                                         <<" does not fit that scheme: Its radius is "
     256             :                                         <<radius <<"but should have "
     257             :                                         <<radial_pts[n_radial_pts*n_angular_pts-p]<<".");
     258             :                       //<<radial_pts[p-n_radial_pts*n_angular_pts]<<".");
     259             :                     }
     260             :                 }
     261             :               // if we are still at the first radial segment,
     262             :               // we consider another angular point
     263         155 :               else if (n_radial_pts == 1)
     264             :                 {
     265          50 :                   ++n_angular_pts;
     266             :                 }
     267             :               // if there was repetition but this does not, the assumed
     268             :               // format does not work:
     269             :             }
     270             :         }
     271             :       else
     272             :         {
     273             :           // I don't see any reason to call this function with no points.
     274           0 :           libmesh_error_msg("Calling reinit() with an empty point list is prohibited.\n");
     275             :         }
     276             : 
     277         650 :       const std::size_t radial_pts_size = radial_pts.size();
     278        1666 :       const std::size_t base_pts_size = pts->size() / radial_pts_size;
     279             :       // If we're a tensor product we should have no remainder
     280         325 :       libmesh_assert_equal_to
     281             :         (base_pts_size * radial_pts_size, pts->size());
     282             : 
     283             : 
     284         650 :       std::vector<Point> base_pts;
     285        1341 :       base_pts.reserve(base_pts_size);
     286        2732 :       for (std::size_t p=0; p != base_pts_size; ++p)
     287             :         {
     288        1391 :           Point pt = (*pts)[p];
     289        1391 :           pt(Dim-1) = 0;
     290        1391 :           base_pts.push_back(pt);
     291             :         }
     292             : 
     293             :       // init radial shapes
     294        1341 :       this->init_radial_shape_functions(inf_elem, &radial_pts);
     295             : 
     296             :       // update the base
     297        1341 :       this->update_base_elem(inf_elem);
     298             : 
     299             :       // the finite element on the ifem base
     300        2032 :       base_fe = FEBase::build(Dim-1, this->fe_type);
     301             : 
     302             :       // having a new base_fe, we need to redetermine the tasks...
     303        1341 :       this->determine_calculations();
     304             : 
     305        1666 :       base_fe->reinit( base_elem.get(), &base_pts);
     306             : 
     307        1341 :       this->init_shape_functions (radial_pts, base_pts, inf_elem);
     308             : 
     309             :       // finally compute the ifem shapes
     310        1341 :       if (weights != nullptr)
     311             :         {
     312           0 :           this->compute_shape_functions (inf_elem,base_pts,radial_pts);
     313             :         }
     314             :       else
     315             :         {
     316        1341 :           this->compute_shape_functions (inf_elem, base_pts, radial_pts);
     317             :         }
     318             : 
     319             :     }
     320             : 
     321        3998 :   if (this->calculate_dual)
     322           0 :     libmesh_not_implemented_msg("Dual shape support for infinite elements is "
     323             :                                 "not currently implemented");
     324        3998 : }
     325             : 
     326             : 
     327             : 
     328             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     329        5339 : void InfFE<Dim, T_radial, T_map>::determine_calculations()
     330             : {
     331        5339 :   this->calculations_started = true;
     332             : 
     333             :   // If the user forgot to request anything, but we're enabling
     334             :   // deprecated backwards compatibility, then we'll be safe and
     335             :   // calculate everything.  If we haven't enable deprecated backwards
     336             :   // compatibility then we'll scream and die.
     337             : #ifdef LIBMESH_ENABLE_DEPRECATED
     338        5339 :   if (!this->calculate_nothing &&
     339        5339 :       !this->calculate_phi && !this->calculate_dphi &&
     340        2592 :       !this->calculate_dphiref &&
     341        2592 :       !this->calculate_phi_scaled && !this->calculate_dphi_scaled &&
     342           0 :       !this->calculate_xyz && !this->calculate_jxw &&
     343           0 :       !this->calculate_map_scaled && !this->calculate_map &&
     344             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     345           0 :       !this->calculate_d2phi &&
     346             : #endif
     347           0 :       !this->calculate_curl_phi && !this->calculate_div_phi)
     348             :     {
     349             :       libmesh_deprecated();
     350           0 :       this->calculate_phi = this->calculate_dphi = this->calculate_jxw = true;
     351           0 :       this->calculate_dphiref = true;
     352             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     353           0 :       this->calculate_d2phi = true;
     354             : #endif
     355           0 :       this->calculate_phi_scaled = this->calculate_dphi_scaled = this->calculate_xyz = true;
     356           0 :       if (FEInterface::field_type(fe_type.family) == TYPE_VECTOR)
     357             :         {
     358           0 :           this->calculate_curl_phi = true;
     359           0 :           this->calculate_div_phi  = true;
     360             :         }
     361             :     }
     362             : #else //LIBMESH_ENABLE_DEPRECATED
     363             :   // ANSI C does not allow to embed the preprocessor-statement into the assert, so we
     364             :   // make two statements, just different by 'calculate_d2phi'.
     365             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     366             :   libmesh_assert (this->calculate_nothing || this->calculate_d2phi ||
     367             :                   this->calculate_phi || this->calculate_dphi ||
     368             :                   this->calculate_dphiref ||
     369             :                   this->calculate_phi_scaled || this->calculate_dphi_scaled ||
     370             :                   this->calculate_xyz || this->calculate_jxw ||
     371             :                   this->calculate_map_scaled || this->calculate_map ||
     372             :                   this->calculate_curl_phi || this->calculate_div_phi);
     373             : #else
     374             :   libmesh_assert (this->calculate_nothing ||
     375             :                   this->calculate_phi || this->calculate_dphi ||
     376             :                   this->calculate_dphiref ||
     377             :                   this->calculate_phi_scaled || this->calculate_dphi_scaled ||
     378             :                   this->calculate_xyz || this->calculate_jxw ||
     379             :                   this->calculate_map_scaled || this->calculate_map ||
     380             :                   this->calculate_curl_phi || this->calculate_div_phi);
     381             : #endif
     382             : #endif // LIBMESH_ENABLE_DEPRECATED
     383             : 
     384             :   // set further terms necessary to do the requested task
     385        5339 :   if (calculate_jxw)
     386           0 :     this->calculate_map = true;
     387        5339 :   if (this->calculate_dphi)
     388          85 :     this->calculate_map = true;
     389        5339 :   if (this->calculate_dphi_scaled)
     390        2612 :     this->calculate_map_scaled = true;
     391        5339 :   if (calculate_xyz && !calculate_map)
     392             :     // if Cartesian positions were requested but the calculation of map
     393             :     // was not triggered, we'll opt for the 'scaled' variant.
     394           0 :     this->calculate_map_scaled = true;
     395        4132 :   base_fe->calculate_phi = this->calculate_phi || this->calculate_phi_scaled
     396        6203 :                        || this->calculate_dphi || this->calculate_dphi_scaled;
     397        5339 :   base_fe->calculate_dphi = this->calculate_dphi || this->calculate_dphi_scaled;
     398        5339 :   if (this->calculate_map || this->calculate_map_scaled
     399        2652 :       || this->calculate_dphiref)
     400             :     {
     401        2687 :       base_fe->calculate_dphiref = true;
     402        2687 :       base_fe->get_xyz(); // trigger base_fe->fe_map to 'calculate_xyz'
     403        2687 :       base_fe->get_JxW(); //  trigger base_fe->fe_map to 'calculate_dxyz'
     404             :     }
     405        5339 :   base_fe->determine_calculations();
     406             : 
     407             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     408        5339 :   if (this->calculate_d2phi)
     409           0 :     libmesh_not_implemented();
     410             : #endif //LIBMESH_ENABLE_SECOND_DERIVATIVES
     411        5339 : }
     412             : 
     413             : 
     414             : 
     415             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     416             : void
     417        1431 : InfFE<Dim, T_radial, T_map>::
     418             : init_radial_shape_functions(const Elem * libmesh_dbg_var(inf_elem),
     419             :                             const std::vector<Point> * radial_pts)
     420             : {
     421         361 :   libmesh_assert(radial_qrule.get() || radial_pts);
     422         361 :   libmesh_assert(inf_elem);
     423             : 
     424             :   // Start logging the radial shape function initialization
     425         722 :   LOG_SCOPE("init_radial_shape_functions()", "InfFE");
     426             : 
     427             :   // initialize most of the things related to physical approximation
     428         722 :   const Order radial_approx_order = fe_type.radial_order;
     429             :   const unsigned int n_radial_approx_shape_functions =
     430         361 :     InfFERadial::n_dofs(radial_approx_order);
     431             : 
     432         722 :   const std::size_t n_radial_qp =
     433        1395 :     radial_pts ? radial_pts->size() : radial_qrule->n_points();
     434         722 :   const std::vector<Point> & radial_qp =
     435          36 :     radial_pts ? *radial_pts : radial_qrule->get_points();
     436             : 
     437             :   // the radial polynomials (eval)
     438        1431 :   if (calculate_phi || calculate_dphi || calculate_phi_scaled || calculate_dphi_scaled)
     439             :     {
     440        1431 :       mode.resize      (n_radial_approx_shape_functions);
     441        9490 :       for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
     442        9477 :         mode[i].resize (n_radial_qp);
     443             : 
     444             :       // evaluate the mode shapes in radial direction at radial quadrature points
     445        9490 :       for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
     446       17848 :         for (std::size_t p=0; p<n_radial_qp; ++p)
     447       11899 :           mode[i][p] = InfFE<Dim,T_radial,T_map>::eval (radial_qp[p](0), radial_approx_order, i);
     448             :     }
     449             : 
     450        1431 :   if (calculate_dphi || calculate_dphi_scaled)
     451             :     {
     452          95 :       dmodedv.resize   (n_radial_approx_shape_functions);
     453         430 :       for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
     454         469 :         dmodedv[i].resize (n_radial_qp);
     455             : 
     456             :       // evaluate the mode shapes in radial direction at radial quadrature points
     457         430 :       for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
     458        2400 :         for (std::size_t p=0; p<n_radial_qp; ++p)
     459        2891 :           dmodedv[i][p] = InfFE<Dim,T_radial,T_map>::eval_deriv (radial_qp[p](0), radial_approx_order, i);
     460             :     }
     461             : 
     462             :   // the (1-v)/2 weight.
     463        1431 :   if (calculate_phi || calculate_phi_scaled || calculate_dphi || calculate_dphi_scaled)
     464             :     {
     465        1431 :       som.resize       (n_radial_qp);
     466             :       // compute scalar values at radial quadrature points
     467        3327 :       for (std::size_t p=0; p<n_radial_qp; ++p)
     468        2443 :         som[p] = InfFERadial::decay (Dim, radial_qp[p](0));
     469             :     }
     470        1431 :   if (calculate_dphi || calculate_dphi_scaled)
     471             :     {
     472          95 :       dsomdv.resize    (n_radial_qp);
     473             :       // compute scalar values at radial quadrature points
     474         655 :       for (std::size_t p=0; p<n_radial_qp; ++p)
     475         784 :         dsomdv[p] = InfFERadial::decay_deriv (Dim, radial_qp[p](0));
     476             :     }
     477        1431 : }
     478             : 
     479             : 
     480             : 
     481             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     482        2052 : void InfFE<Dim,T_radial,T_map>::init_shape_functions(const std::vector<Point> & radial_qp,
     483             :                                                      const std::vector<Point> & base_qp,
     484             :                                                      const Elem * inf_elem)
     485             : {
     486         567 :   libmesh_assert(inf_elem);
     487             : 
     488             :   // Start logging the radial shape function initialization
     489        1134 :   LOG_SCOPE("init_shape_functions()", "InfFE");
     490             : 
     491             :   // fast access to some const ints for the radial data
     492        1134 :   const unsigned int n_radial_approx_sf  = InfFERadial::n_dofs(fe_type.radial_order);
     493        1134 :   const std::size_t  n_radial_qp         = radial_qp.size();
     494             : #ifdef DEBUG
     495         567 :   if (calculate_phi || calculate_dphi || calculate_phi_scaled || calculate_dphi_scaled)
     496         567 :     libmesh_assert_equal_to(n_radial_approx_sf, mode.size());
     497         567 :   if (calculate_phi || calculate_dphi || calculate_dphi_scaled)
     498         567 :     libmesh_assert_equal_to(som.size(), n_radial_qp);
     499             : #endif
     500             : 
     501             : 
     502             :   // initialize most of the quantities related to mapping
     503             : 
     504             :   // The element type and order to use in the base map
     505             :   //const Order base_mapping_order = base_elem->default_order();
     506             : 
     507             :   // the number of base shape functions used to construct the map
     508             :   // (Lagrange shape functions are used for mapping in the base)
     509             :   //unsigned int n_base_mapping_shape_functions =
     510             :   //  InfFEBase::n_base_mapping_sf(*base_elem,
     511             :   //                               base_mapping_order);
     512             : 
     513             :   // initialize most of the things related to physical approximation
     514             :   unsigned int n_base_approx_shape_functions;
     515             :   if (Dim > 1)
     516         567 :     n_base_approx_shape_functions =
     517        2052 :       FEInterface::n_dofs(base_fe->get_fe_type(), base_elem.get());
     518             :   else
     519           0 :     n_base_approx_shape_functions = 1;
     520             : 
     521             : 
     522             :   // update class member field
     523        2052 :   _n_total_approx_sf =
     524        2052 :     n_radial_approx_sf * n_base_approx_shape_functions;
     525             : 
     526             : 
     527             :   // The number of the base quadrature points.
     528        1134 :   const unsigned int n_base_qp = cast_int<unsigned int>(base_qp.size());
     529             : 
     530             :   // The total number of quadrature points.
     531        2052 :   _n_total_qp = n_radial_qp * n_base_qp;
     532             : 
     533             : 
     534             :   // initialize the node and shape numbering maps
     535             :   {
     536             :     // similar for the shapes: the i-th entry stores
     537             :     // the associated base/radial shape number
     538        2052 :     _radial_shape_index.resize(_n_total_approx_sf);
     539        2052 :     _base_shape_index.resize(_n_total_approx_sf);
     540             : 
     541             :     // fill the shape index map
     542       57883 :     for (unsigned int n=0; n<_n_total_approx_sf; ++n)
     543             :       {
     544       82871 :         compute_shape_indices (this->fe_type,
     545             :                                inf_elem,
     546             :                                n,
     547             :                                _base_shape_index[n],
     548             :                                _radial_shape_index[n]);
     549       13520 :         libmesh_assert_less (_base_shape_index[n], n_base_approx_shape_functions);
     550       13520 :         libmesh_assert_less (_radial_shape_index[n], n_radial_approx_sf);
     551             :       }
     552             :   }
     553             : 
     554             :   // resize the base data fields
     555             :   //dist.resize(n_base_mapping_shape_functions);
     556             : 
     557             :   // resize the total data fields
     558             : 
     559             :   // the phase term varies with xi, eta and zeta(v): store it for _all_ qp
     560             :   //
     561             :   // when computing the phase, we need the base approximations
     562             :   // therefore, initialize the phase here, but evaluate it
     563             :   // in compute_shape_functions().
     564             :   //
     565             :   // the weight, though, is only needed at the radial quadrature points, n_radial_qp.
     566             :   // but for a uniform interface to the protected data fields
     567             :   // the weight data field (which are accessible from the outside) are expanded to _n_total_qp.
     568        2052 :   if (calculate_phi || calculate_dphi)
     569        1406 :     weight.resize      (_n_total_qp);
     570        2052 :   if (calculate_phi_scaled || calculate_dphi_scaled)
     571         656 :     weightxr_sq.resize (_n_total_qp);
     572        2052 :   if (calculate_dphi || calculate_dphi_scaled)
     573         721 :     dweightdv.resize   (n_radial_qp);
     574        2052 :   if (calculate_dphi)
     575          75 :     dweight.resize     (_n_total_qp);
     576        2052 :   if (calculate_dphi_scaled)
     577         656 :     dweightxr_sq.resize(_n_total_qp);
     578             : 
     579        2052 :   if (calculate_dphi || calculate_dphi_scaled)
     580         721 :     dphase.resize      (_n_total_qp);
     581             : 
     582             :   // this vector contains the integration weights for the combined quadrature rule
     583             :   // if no quadrature rules are given, use only ones.
     584        2052 :   _total_qrule_weights.resize(_n_total_qp,1);
     585             : 
     586             :   // InfFE's data fields phi, dphi, dphidx, phi_map etc hold the _total_
     587             :   // shape and mapping functions, respectively
     588             :   {
     589        2052 :     if (calculate_map_scaled)
     590         661 :       JxWxdecay.resize(_n_total_qp);
     591        2052 :     if (calculate_jxw)
     592           0 :       JxW.resize(_n_total_qp);
     593        2052 :     if (calculate_map_scaled || calculate_map)
     594             :       {
     595         726 :         xyz.resize(_n_total_qp);
     596         726 :         dxidx_map_scaled.resize(_n_total_qp);
     597         726 :         dxidy_map_scaled.resize(_n_total_qp);
     598         726 :         dxidz_map_scaled.resize(_n_total_qp);
     599         726 :         detadx_map_scaled.resize(_n_total_qp);
     600         726 :         detady_map_scaled.resize(_n_total_qp);
     601         726 :         detadz_map_scaled.resize(_n_total_qp);
     602         726 :         dzetadx_map_scaled.resize(_n_total_qp);
     603         726 :         dzetady_map_scaled.resize(_n_total_qp);
     604         726 :         dzetadz_map_scaled.resize(_n_total_qp);
     605             :       }
     606        2052 :     if (calculate_map)
     607             :       {
     608          80 :         dxidx_map.resize(_n_total_qp);
     609          80 :         dxidy_map.resize(_n_total_qp);
     610          80 :         dxidz_map.resize(_n_total_qp);
     611          80 :         detadx_map.resize(_n_total_qp);
     612          80 :         detady_map.resize(_n_total_qp);
     613          80 :         detadz_map.resize(_n_total_qp);
     614          80 :         dzetadx_map.resize(_n_total_qp);
     615          80 :         dzetady_map.resize(_n_total_qp);
     616          80 :         dzetadz_map.resize(_n_total_qp);
     617             :       }
     618        2052 :     if (calculate_phi)
     619        1406 :       phi.resize     (_n_total_approx_sf);
     620        2052 :     if (calculate_phi_scaled)
     621         656 :       phixr.resize    (_n_total_approx_sf);
     622        2052 :     if (calculate_dphi)
     623             :       {
     624          75 :         dphi.resize    (_n_total_approx_sf);
     625          75 :         dphidx.resize  (_n_total_approx_sf);
     626          75 :         dphidy.resize  (_n_total_approx_sf);
     627          75 :         dphidz.resize  (_n_total_approx_sf);
     628             :       }
     629             : 
     630        2052 :     if (calculate_dphi_scaled)
     631             :       {
     632         656 :         dphixr.resize   (_n_total_approx_sf);
     633         656 :         dphixr_sq.resize(_n_total_approx_sf);
     634             :       }
     635             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     636             : 
     637        2052 :     if (calculate_d2phi)
     638             :       {
     639           0 :         libmesh_not_implemented();
     640             :         d2phi.resize     (_n_total_approx_sf);
     641             :         d2phidx2.resize  (_n_total_approx_sf);
     642             :         d2phidxdy.resize (_n_total_approx_sf);
     643             :         d2phidxdz.resize (_n_total_approx_sf);
     644             :         d2phidy2.resize  (_n_total_approx_sf);
     645             :         d2phidydz.resize (_n_total_approx_sf);
     646             :         d2phidz2.resize  (_n_total_approx_sf);
     647             :         d2phidxi2.resize (_n_total_approx_sf);
     648             : 
     649             :         if (Dim > 1)
     650             :           {
     651             :             d2phidxideta.resize(_n_total_approx_sf);
     652             :             d2phideta2.resize(_n_total_approx_sf);
     653             :           }
     654             : 
     655             :         if (Dim > 2)
     656             :           {
     657             :             d2phidetadzeta.resize(_n_total_approx_sf);
     658             :             d2phidxidzeta.resize(_n_total_approx_sf);
     659             :             d2phidzeta2.resize(_n_total_approx_sf);
     660             :           }
     661             :       }
     662             : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     663             : 
     664        2052 :     if (calculate_dphi || calculate_dphi_scaled)
     665             :       {
     666         721 :         dphidxi.resize (_n_total_approx_sf);
     667             : 
     668             :         if (Dim > 1)
     669         721 :           dphideta.resize(_n_total_approx_sf);
     670             : 
     671             :         if (Dim == 3)
     672         721 :           dphidzeta.resize(_n_total_approx_sf);
     673             :       }
     674             : 
     675             :   }
     676             : 
     677             :   // collect all the for loops, where inner vectors are
     678             :   // resized to the appropriate number of quadrature points
     679             :   {
     680        2052 :     if (calculate_phi)
     681       33232 :       for (unsigned int i=0; i<_n_total_approx_sf; ++i)
     682       37334 :         phi[i].resize         (_n_total_qp);
     683             : 
     684        2052 :     if (calculate_dphi)
     685        1025 :       for (unsigned int i=0; i<_n_total_approx_sf; ++i)
     686             :         {
     687        1330 :           dphi[i].resize        (_n_total_qp);
     688        1330 :           dphidx[i].resize      (_n_total_qp);
     689        1330 :           dphidy[i].resize      (_n_total_qp);
     690        1330 :           dphidz[i].resize      (_n_total_qp);
     691             :         }
     692             : 
     693        2052 :     if (calculate_phi_scaled)
     694       24741 :       for (unsigned int i=0; i<_n_total_approx_sf; ++i)
     695             :         {
     696       32129 :           phixr[i].resize (_n_total_qp);
     697             :         }
     698        2052 :     if (calculate_dphi_scaled)
     699       24741 :       for (unsigned int i=0; i<_n_total_approx_sf; ++i)
     700             :         {
     701       32129 :           dphixr[i].resize(_n_total_qp);
     702       32129 :           dphixr_sq[i].resize(_n_total_qp);
     703             :         }
     704             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     705        2052 :     if (calculate_d2phi)
     706           0 :       for (unsigned int i=0; i<_n_total_approx_sf; ++i)
     707             :         {
     708           0 :           d2phi[i].resize       (_n_total_qp);
     709           0 :           d2phidx2[i].resize    (_n_total_qp);
     710           0 :           d2phidxdy[i].resize   (_n_total_qp);
     711           0 :           d2phidxdz[i].resize   (_n_total_qp);
     712           0 :           d2phidy2[i].resize    (_n_total_qp);
     713           0 :           d2phidydz[i].resize   (_n_total_qp);
     714           0 :           d2phidy2[i].resize    (_n_total_qp);
     715           0 :           d2phidxi2[i].resize   (_n_total_qp);
     716             : 
     717             :           if (Dim > 1)
     718             :             {
     719           0 :               d2phidxideta[i].resize   (_n_total_qp);
     720           0 :               d2phideta2[i].resize     (_n_total_qp);
     721             :             }
     722             :           if (Dim > 2)
     723             :             {
     724           0 :               d2phidxidzeta[i].resize  (_n_total_qp);
     725           0 :               d2phidetadzeta[i].resize (_n_total_qp);
     726           0 :               d2phidzeta2[i].resize    (_n_total_qp);
     727             :             }
     728             :         }
     729             : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     730             : 
     731        2052 :     if (calculate_dphi || calculate_dphi_scaled)
     732       25676 :       for (unsigned int i=0; i<_n_total_approx_sf; ++i)
     733             :         {
     734       33347 :           dphidxi[i].resize     (_n_total_qp);
     735             : 
     736             :           if (Dim > 1)
     737       33347 :             dphideta[i].resize  (_n_total_qp);
     738             : 
     739             :           if (Dim == 3)
     740       33347 :             dphidzeta[i].resize (_n_total_qp);
     741             : 
     742             :         }
     743             : 
     744             :   }
     745             :   {
     746             :     // (a) compute scalar values at _all_ quadrature points  -- for uniform
     747             :     //     access from the outside to these fields
     748             :     // (b) form a std::vector<Real> which contains the appropriate weights
     749             :     //     of the combined quadrature rule!
     750         567 :     libmesh_assert_equal_to (radial_qp.size(), n_radial_qp);
     751             : 
     752        2052 :     if (radial_qrule && base_qrule)
     753             :       {
     754         244 :         const std::vector<Real> & radial_qw = radial_qrule->get_weights();
     755         244 :         const std::vector<Real> & base_qw = base_qrule->get_weights();
     756         244 :         libmesh_assert_equal_to (radial_qw.size(), n_radial_qp);
     757         244 :         libmesh_assert_equal_to (base_qw.size(), n_base_qp);
     758             : 
     759        5588 :         for (unsigned int rp=0; rp<n_radial_qp; ++rp)
     760       97938 :           for (unsigned int bp=0; bp<n_base_qp; ++bp)
     761      186492 :             _total_qrule_weights[bp + rp*n_base_qp] = radial_qw[rp] * base_qw[bp];
     762             :       }
     763             : 
     764             : 
     765        8325 :     for (unsigned int rp=0; rp<n_radial_qp; ++rp)
     766             :       {
     767        6273 :         if (calculate_phi || calculate_dphi)
     768        4717 :           for (unsigned int bp=0; bp<n_base_qp; ++bp)
     769        5880 :             weight[bp + rp*n_base_qp] = InfFERadial::D(radial_qp[rp](0));
     770             : 
     771        6273 :         if ( calculate_phi_scaled)
     772       96423 :           for (unsigned int bp=0; bp<n_base_qp; ++bp)
     773      122479 :             weightxr_sq[bp + rp*n_base_qp] = InfFERadial::Dxr_sq(radial_qp[rp](0));
     774             : 
     775        6273 :         if ( calculate_dphi || calculate_dphi_scaled)
     776        9982 :           dweightdv[rp] = InfFERadial::D_deriv(radial_qp[rp](0));
     777             :       }
     778             :   }
     779        2052 : }
     780             : 
     781             : 
     782             : 
     783             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
     784        3998 : void InfFE<Dim,T_radial,T_map>::compute_shape_functions(const Elem * inf_elem,
     785             :                                                         const std::vector<Point> & base_qp,
     786             :                                                         const std::vector<Point> & radial_qp
     787             :                                                         )
     788             : {
     789        1215 :   libmesh_assert(inf_elem);
     790             :   // at least check whether the base element type is correct.
     791             :   // otherwise this version of computing dist would give problems
     792        1215 :   libmesh_assert_equal_to (base_elem->type(),
     793             :                            InfFEBase::get_elem_type(inf_elem->type()));
     794             : 
     795             :   // Start logging the overall computation of shape functions
     796        2430 :   LOG_SCOPE("compute_shape_functions()", "InfFE");
     797             : 
     798             :   //const unsigned int n_radial_qp = cast_int<unsigned int>(som.size());
     799             :   //const unsigned int n_base_qp = cast_int<unsigned int>(S_map[0].size());
     800        2430 :   const std::size_t  n_radial_qp = radial_qp.size();
     801        3998 :   const unsigned int n_base_qp   = base_qp.size();
     802             : 
     803        1215 :   libmesh_assert_equal_to (_n_total_qp, n_radial_qp*n_base_qp);
     804        1215 :   libmesh_assert_equal_to (_n_total_qp, _total_qrule_weights.size());
     805             : #ifdef DEBUG
     806        1215 :   if (som.size() > 0)
     807        1215 :     libmesh_assert_equal_to(n_radial_qp, som.size());
     808             : 
     809        1215 :   if (this->calculate_map || this->calculate_map_scaled)
     810             :     {
     811             :       // these vectors are needed later; initialize here already to have access to
     812             :       // n_base_qp etc.
     813         896 :       const std::vector<std::vector<Real>> & S_map  = (base_fe->get_fe_map()).get_phi_map();
     814         896 :       if (S_map[0].size() > 0)
     815         896 :         libmesh_assert_equal_to(n_base_qp, S_map[0].size());
     816             :     }
     817        1215 :   if (radial_qrule)
     818         892 :     libmesh_assert_equal_to(n_radial_qp, radial_qrule->n_points());
     819        1215 :   if (base_qrule)
     820         892 :     libmesh_assert_equal_to(n_base_qp, base_qrule->n_points());
     821        1215 :   libmesh_assert_equal_to(_n_total_qp % n_radial_qp, 0); // "Error in the structure of quadrature points!");
     822             : #endif
     823             : 
     824             : 
     825        3998 :   _n_total_approx_sf = InfFERadial::n_dofs(fe_type.radial_order) *
     826        3998 :     FEInterface::n_dofs(base_fe->get_fe_type(), base_elem.get());
     827             : 
     828             : 
     829             : 
     830        3998 :   const Point origin = inf_elem->origin();
     831             : 
     832             :   // Compute the shape function values (and derivatives)
     833             :   // at the Quadrature points.  Note that the actual values
     834             :   // have already been computed via init_shape_functions
     835             : 
     836        3998 :   unsigned int elem_dim = inf_elem->dim();
     837             :   // Compute the value of the derivative shape function i at quadrature point p
     838        3998 :   switch (elem_dim)
     839             :     {
     840           0 :     case 1:
     841             :     case 2:
     842             :       {
     843           0 :         libmesh_not_implemented();
     844             :         break;
     845             :       }
     846        1215 :     case 3:
     847             :       {
     848        6428 :         std::vector<std::vector<Real>> S (0);
     849        6428 :         std::vector<std::vector<Real>> Ss(0);
     850        6428 :         std::vector<std::vector<Real>> St(0);
     851             : 
     852        5213 :         std::vector<Real> base_dxidx (0);
     853        5213 :         std::vector<Real> base_dxidy (0);
     854        5213 :         std::vector<Real> base_dxidz (0);
     855        5213 :         std::vector<Real> base_detadx(0);
     856        5213 :         std::vector<Real> base_detady(0);
     857        5213 :         std::vector<Real> base_detadz(0);
     858             : 
     859        5213 :         std::vector<Point> base_xyz (0);
     860             : 
     861        3998 :         if (calculate_phi  || calculate_phi_scaled ||
     862           0 :             calculate_dphi || calculate_dphi_scaled)
     863        3998 :           S=base_fe->phi;
     864             : 
     865             :         // fast access to the approximation and mapping shapes of base_fe
     866        3998 :         if (calculate_map || calculate_map_scaled)
     867             :           {
     868        2672 :             Ss = base_fe->dphidxi;
     869        2672 :             St = base_fe->dphideta;
     870             : 
     871        2672 :             base_dxidx = base_fe->get_dxidx();
     872        2672 :             base_dxidy = base_fe->get_dxidy();
     873        2672 :             base_dxidz = base_fe->get_dxidz();
     874        2672 :             base_detadx = base_fe->get_detadx();
     875        2672 :             base_detady = base_fe->get_detady();
     876        2672 :             base_detadz = base_fe->get_detadz();
     877             : 
     878        2672 :             base_xyz = base_fe->get_xyz();
     879             :           }
     880             : 
     881        3998 :         ElemType base_type= base_elem->type();
     882             : 
     883             : #ifdef DEBUG
     884        1215 :         if (calculate_phi)
     885         351 :           libmesh_assert_equal_to (phi.size(), _n_total_approx_sf);
     886        1215 :         if (calculate_dphi)
     887             :           {
     888          30 :             libmesh_assert_equal_to (dphidxi.size(), _n_total_approx_sf);
     889          30 :             libmesh_assert_equal_to (dphideta.size(), _n_total_approx_sf);
     890          30 :             libmesh_assert_equal_to (dphidzeta.size(), _n_total_approx_sf);
     891             :           }
     892             : #endif
     893             : 
     894        1215 :         unsigned int tp=0; // total qp
     895       22746 :         for (unsigned int rp=0; rp<n_radial_qp; ++rp)  // over radial qps
     896      244657 :           for (unsigned int bp=0; bp<n_base_qp; ++bp)  // over base qps
     897             : 
     898             :             { // First compute the map from base element quantities to physical space:
     899             : 
     900             :               // initialize them with invalid value to not use them
     901             :               // without setting them to the correct value before.
     902       75289 :               Point unit_r(NAN);
     903       75289 :               RealGradient grad_a_scaled(NAN);
     904       75289 :               Real a(NAN);
     905       75289 :               Real r_norm(NAN);
     906      225909 :               if (calculate_map || calculate_map_scaled)
     907             :                 {
     908      449493 :                   xyz[tp] = InfFEMap::map(elem_dim, inf_elem, Point(base_qp[bp](0),base_qp[bp](1),radial_qp[rp](0)));
     909             : 
     910       74970 :                   const Point r(xyz[tp]-origin);
     911      224583 :                   a=(base_xyz[bp]-origin).norm();
     912      149613 :                   r_norm = r.norm();
     913             : 
     914             :                   // check that 'som' == a/r.
     915             : #ifndef NDEVEL
     916       74970 :                   if (som.size())
     917       74970 :                     libmesh_assert_less(std::abs(som[rp] -a/r_norm) , 1e-7);
     918             : #endif
     919       74970 :                   unit_r=(r/r_norm);
     920             : 
     921             :                   // They are used for computing the normal and do not correspond to the direction of eta and xi in this element:
     922             :                   // Due to the stretch of these axes in radial direction, they are deformed.
     923      374523 :                   Point e_xi(base_dxidx[bp],
     924             :                              base_dxidy[bp],
     925             :                              base_dxidz[bp]);
     926      449493 :                   Point e_eta(base_detadx[bp],
     927             :                               base_detady[bp],
     928             :                               base_detadz[bp]);
     929             : 
     930      224583 :                   const RealGradient normal=e_eta.cross(e_xi).unit();
     931             : 
     932             :                   // grad a = a/r.norm() * grad_a_scaled
     933       74970 :                   grad_a_scaled=unit_r - normal/(normal*unit_r);
     934             : 
     935      374523 :                   const Real  dxi_er=base_dxidx[bp]* unit_r(0) + base_dxidy[bp] *unit_r(1) + base_dxidz[bp] *unit_r(2);
     936      449493 :                   const Real deta_er=base_detadx[bp]*unit_r(0) + base_detady[bp]*unit_r(1) + base_detadz[bp]*unit_r(2);
     937             : 
     938             :                   // in case of non-affine map, further terms need to be taken into account,
     939             :                   // involving \p e_eta and \p e_xi and thus recursive computation is needed
     940      224583 :                   if (!base_elem->has_affine_map())
     941             :                     {
     942             :                       /**
     943             :                        * The full form for 'a' is
     944             :                        * a =  (r0*normal)/(normal*unit_r);
     945             :                        * where r0 is some point on the base plane(!)
     946             :                        * when the base element is not a plane, r0 and normal are functions of space.
     947             :                        * Here, some approximation is used:
     948             :                        */
     949             : 
     950         200 :                       const unsigned int n_sf = base_elem->n_nodes();
     951          80 :                       RealGradient tmp(0.,0.,0.);
     952        2000 :                       for (unsigned int i=0; i< n_sf; ++i)
     953             :                         {
     954        3240 :                           RealGradient dL_da_i = (FE<2,LAGRANGE>::shape_deriv(base_type,
     955        1800 :                                                                               base_elem->default_order(),
     956         720 :                                                                               i, 0, base_qp[bp]) * e_xi
     957        3240 :                                                   +FE<2,LAGRANGE>::shape_deriv(base_type,
     958        1800 :                                                                                base_elem->default_order(),
     959         720 :                                                                                i, 1, base_qp[bp]) * e_eta);
     960             : 
     961        1080 :                           tmp += (base_elem->node_ref(i) -origin).norm()* dL_da_i;
     962             : 
     963             :                         }
     964          80 :                       libmesh_assert(tmp*unit_r < .95 ); // in a proper setup, tmp should have only a small radial component.
     965         200 :                       grad_a_scaled = ( tmp - (tmp*unit_r)*unit_r ) / ( 1. - tmp*unit_r);
     966             : 
     967             :                     }
     968             : 
     969             :                   // 'scale' = r/a
     970      299553 :                   dxidx_map_scaled[tp] = (grad_a_scaled(0) - unit_r(0))*dxi_er +base_dxidx[bp];
     971      299553 :                   dxidy_map_scaled[tp] = (grad_a_scaled(1) - unit_r(1))*dxi_er +base_dxidy[bp];
     972      299553 :                   dxidz_map_scaled[tp] = (grad_a_scaled(2) - unit_r(2))*dxi_er +base_dxidz[bp];
     973             : 
     974             :                   // 'scale' = r/a
     975      299553 :                   detadx_map_scaled[tp] = (grad_a_scaled(0) - unit_r(0))*deta_er + base_detadx[bp];
     976      299553 :                   detady_map_scaled[tp] = (grad_a_scaled(1) - unit_r(1))*deta_er + base_detady[bp];
     977      299553 :                   detadz_map_scaled[tp] = (grad_a_scaled(2) - unit_r(2))*deta_er + base_detadz[bp];
     978             : 
     979             :                   // 'scale' = (r/a)**2
     980      224583 :                   dzetadx_map_scaled[tp] =-2./a*(grad_a_scaled(0) - unit_r(0));
     981      224583 :                   dzetady_map_scaled[tp] =-2./a*(grad_a_scaled(1) - unit_r(1));
     982      299553 :                   dzetadz_map_scaled[tp] =-2./a*(grad_a_scaled(2) - unit_r(2));
     983             : 
     984             :                 }
     985             : 
     986      225909 :               if (calculate_map)
     987             :                 {
     988        2289 :                   dxidx_map[tp] = a/r_norm * dxidx_map_scaled[tp];
     989        2289 :                   dxidy_map[tp] = a/r_norm * dxidy_map_scaled[tp];
     990        2289 :                   dxidz_map[tp] = a/r_norm * dxidz_map_scaled[tp];
     991             : 
     992        2289 :                   detadx_map[tp] = a/r_norm * detadx_map_scaled[tp];
     993        2289 :                   detady_map[tp] = a/r_norm * detady_map_scaled[tp];
     994        2289 :                   detadz_map[tp] = a/r_norm * detadz_map_scaled[tp];
     995             : 
     996             :                   // dzetadx = dzetadr*dr/dx - 2/r * grad_a
     997             :                   //         = dzetadr*dr/dx - 2*a/r^2 * grad_a_scaled
     998        1635 :                   dzetadx_map[tp] =-2.*a/(r_norm*r_norm)*(grad_a_scaled(0) - unit_r(0));
     999        1635 :                   dzetady_map[tp] =-2.*a/(r_norm*r_norm)*(grad_a_scaled(1) - unit_r(1));
    1000        1635 :                   dzetadz_map[tp] =-2.*a/(r_norm*r_norm)*(grad_a_scaled(2) - unit_r(2));
    1001             : 
    1002        1635 :                   if (calculate_jxw)
    1003             :                     {
    1004           0 :                       Real inv_jac = (dxidx_map[tp]*( detady_map[tp]*dzetadz_map[tp]- dzetady_map[tp]*detadz_map[tp]) +
    1005           0 :                                       detadx_map[tp]*(dzetady_map[tp]* dxidz_map[tp]-  dxidy_map[tp]*dzetadz_map[tp]) +
    1006           0 :                                       dzetadx_map[tp]*( dxidy_map[tp]*detadz_map[tp]- detady_map[tp]*  dxidz_map[tp]));
    1007             : 
    1008           0 :                       if (inv_jac <= 1e-10)
    1009             :                         {
    1010           0 :                           libmesh_error_msg("ERROR: negative inverse Jacobian " \
    1011             :                                             << inv_jac \
    1012             :                                             << " at point " \
    1013             :                                             << xyz[tp] \
    1014             :                                             << " in element " \
    1015             :                                             << inf_elem->id());
    1016             :                         }
    1017             : 
    1018             : 
    1019           0 :                       JxW[tp] = _total_qrule_weights[tp]/inv_jac;
    1020             :                     }
    1021             : 
    1022             :                 }
    1023      225909 :               if (calculate_map_scaled)
    1024             :                 {
    1025      372003 :                   Real inv_jacxR_pow4 = (dxidx_map_scaled[tp]  *(  detady_map_scaled[tp]*dzetadz_map_scaled[tp]
    1026      297593 :                                                                 - dzetady_map_scaled[tp]* detadz_map_scaled[tp]) +
    1027      297593 :                                          detadx_map_scaled[tp] *( dzetady_map_scaled[tp]*  dxidz_map_scaled[tp]
    1028      223183 :                                                                 - dxidy_map_scaled[tp]*dzetadz_map_scaled[tp]) +
    1029      223183 :                                          dzetadx_map_scaled[tp]*( dxidy_map_scaled[tp]* detadz_map_scaled[tp]
    1030      223183 :                                                                 -detady_map_scaled[tp]*  dxidz_map_scaled[tp]));
    1031      223183 :                   if (inv_jacxR_pow4 <= 1e-7)
    1032             :                     {
    1033           0 :                       libmesh_error_msg("ERROR: negative weighted inverse Jacobian " \
    1034             :                                         << inv_jacxR_pow4 \
    1035             :                                         << " at point " \
    1036             :                                         << xyz[tp] \
    1037             :                                         << " in element " \
    1038             :                                         << inf_elem->id());
    1039             :                     }
    1040             : 
    1041      372003 :                   JxWxdecay[tp] = _total_qrule_weights[tp]/inv_jacxR_pow4;
    1042             :                 }
    1043             : 
    1044             :               // phase term mu(r)=i*k*(r-a).
    1045             :               // skip i*k: it is added separately during matrix assembly.
    1046             : 
    1047      225909 :               if (calculate_dphi || calculate_dphi_scaled)
    1048      299504 :                 dphase[tp] = unit_r - grad_a_scaled*a/r_norm;
    1049             : 
    1050      225909 :               if (calculate_dphi)
    1051             :                 {
    1052        2880 :                   dweight[tp](0) = dweightdv[rp] * dzetadx_map[tp];
    1053        1600 :                   dweight[tp](1) = dweightdv[rp] * dzetady_map[tp];
    1054        2240 :                   dweight[tp](2) = dweightdv[rp] * dzetadz_map[tp];
    1055             :                 }
    1056      225909 :               if (calculate_dphi_scaled)
    1057             :                 {
    1058      371940 :                   dweightxr_sq[tp](0) = dweightdv[rp] * dzetadx_map_scaled[tp];
    1059      223148 :                   dweightxr_sq[tp](1) = dweightdv[rp] * dzetady_map_scaled[tp];
    1060      297544 :                   dweightxr_sq[tp](2) = dweightdv[rp] * dzetadz_map_scaled[tp];
    1061             :                 }
    1062             : 
    1063      225909 :               if (calculate_phi || calculate_phi_scaled || calculate_dphi || calculate_dphi_scaled)
    1064             :                 // compute the shape-functions and derivative quantities:
    1065     7997773 :                 for (unsigned int i=0; i <_n_total_approx_sf ; ++i)
    1066             :                   {
    1067             :                     // let the index vectors take care of selecting the appropriate base/radial shape
    1068     7771864 :                     unsigned int bi = _base_shape_index  [i];
    1069     7771864 :                     unsigned int ri = _radial_shape_index[i];
    1070     7771864 :                     if (calculate_phi)
    1071      150828 :                       phi      [i][tp] = S [bi][bp] * mode[ri][rp] * som[rp];
    1072             : 
    1073     7771864 :                     if (calculate_phi_scaled)
    1074    23162044 :                       phixr    [i][tp] = S [bi][bp] * mode[ri][rp];
    1075             : 
    1076     7771864 :                     if (calculate_dphi || calculate_dphi_scaled)
    1077             :                       {
    1078    23230588 :                         dphidxi  [i][tp] = Ss[bi][bp] * mode[ri][rp] * som[rp];
    1079    15485608 :                         dphideta [i][tp] = St[bi][bp] * mode[ri][rp] * som[rp];
    1080    10322288 :                         dphidzeta[i][tp] = S [bi][bp]
    1081    20648928 :                           * (dmodedv[ri][rp] * som[rp] + mode[ri][rp] * dsomdv[rp]);
    1082             :                       }
    1083             : 
    1084     7771864 :                     if (calculate_dphi)
    1085             :                       {
    1086             : 
    1087             :                         // dphi/dx    = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx);
    1088       30464 :                         dphi[i][tp](0) =
    1089       56576 :                           dphidx[i][tp] = (dphidxi[i][tp]*dxidx_map[tp] +
    1090       39168 :                                            dphideta[i][tp]*detadx_map[tp] +
    1091       47872 :                                            dphidzeta[i][tp]*dzetadx_map[tp]);
    1092             : 
    1093             :                         // dphi/dy    = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy);
    1094       21760 :                         dphi[i][tp](1) =
    1095       39168 :                           dphidy[i][tp] = (dphidxi[i][tp]*dxidy_map[tp] +
    1096       21760 :                                            dphideta[i][tp]*detady_map[tp] +
    1097       30464 :                                            dphidzeta[i][tp]*dzetady_map[tp]);
    1098             : 
    1099             :                         // dphi/dz    = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz);
    1100       21760 :                         dphi[i][tp](2) =
    1101       39168 :                           dphidz[i][tp] = (dphidxi[i][tp]*dxidz_map[tp] +
    1102       21760 :                                            dphideta[i][tp]*detadz_map[tp] +
    1103       30464 :                                            dphidzeta[i][tp]*dzetadz_map[tp]);
    1104             : 
    1105             :                       }
    1106     7771864 :                     if (calculate_dphi_scaled)
    1107             :                       { // we don't distinguish between the different levels of scaling here...
    1108             : 
    1109    18014852 :                         dphixr[i][tp](0)= (dphidxi[i][tp]*dxidx_map_scaled[tp] +
    1110    12867660 :                                            dphideta[i][tp]*detadx_map_scaled[tp] +
    1111    18014852 :                                            dphidzeta[i][tp]*dzetadx_map_scaled[tp]*som[rp]);
    1112             : 
    1113    10294064 :                         dphixr[i][tp](1) = (dphidxi[i][tp]*dxidy_map_scaled[tp] +
    1114     7720468 :                                             dphideta[i][tp]*detady_map_scaled[tp] +
    1115     7720468 :                                             dphidzeta[i][tp]*dzetady_map_scaled[tp]*som[rp]);
    1116             : 
    1117    10294064 :                         dphixr[i][tp](2) = (dphidxi[i][tp]*dxidz_map_scaled[tp] +
    1118     7720468 :                                             dphideta[i][tp]*detadz_map_scaled[tp] +
    1119     7720468 :                                             dphidzeta[i][tp]*dzetadz_map_scaled[tp]*som[rp]);
    1120             : 
    1121    15441256 :                         const Real dphidxixr = Ss[bi][bp] * mode[ri][rp];
    1122    10294064 :                         const Real dphidetaxr= St[bi][bp] * mode[ri][rp];
    1123             : 
    1124    10294064 :                         dphixr_sq[i][tp](0)= (dphidxixr*dxidx_map_scaled[tp] +
    1125    10294064 :                                               dphidetaxr*detadx_map_scaled[tp] +
    1126     7720468 :                                               dphidzeta[i][tp]*dzetadx_map_scaled[tp]);
    1127             : 
    1128    15441256 :                         dphixr_sq[i][tp](1) = (dphidxixr*dxidy_map_scaled[tp] +
    1129    10294064 :                                                dphidetaxr*detady_map_scaled[tp] +
    1130     7720468 :                                                dphidzeta[i][tp]*dzetady_map_scaled[tp]);
    1131             : 
    1132    15441256 :                         dphixr_sq[i][tp](2) = (dphidxixr*dxidz_map_scaled[tp] +
    1133    10294064 :                                                dphidetaxr*detadz_map_scaled[tp] +
    1134     7720468 :                                                dphidzeta[i][tp]*dzetadz_map_scaled[tp]);
    1135             :                       }
    1136             : 
    1137             :                   }
    1138      225909 :               tp++;
    1139             :             }
    1140             : 
    1141        1215 :         break;
    1142        1568 :       }
    1143             : 
    1144           0 :     default:
    1145           0 :       libmesh_error_msg("Unsupported dim = " << dim);
    1146             :     }
    1147        3998 : }
    1148             : 
    1149             : 
    1150             : 
    1151             : template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
    1152           0 : bool InfFE<Dim,T_radial,T_map>::shapes_need_reinit() const
    1153             : {
    1154             :   // We never call this.
    1155           0 :   libmesh_not_implemented();
    1156             :   return false;
    1157             : }
    1158             : 
    1159             : } // namespace libMesh
    1160             : 
    1161             : 
    1162             : // Explicit instantiations
    1163             : #include "libmesh/inf_fe_instantiate_1D.h"
    1164             : #include "libmesh/inf_fe_instantiate_2D.h"
    1165             : #include "libmesh/inf_fe_instantiate_3D.h"
    1166             : 
    1167             : 
    1168             : 
    1169             : #endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS

Generated by: LCOV version 1.14