LCOV - code coverage report
Current view: top level - src/systems - fem_context.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4343 (6ea38c) with base 8c3130 Lines: 526 821 64.1 %
Date: 2026-10-13 21:47:33 Functions: 82 216 38.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             : #include "libmesh/fem_context.h"
      21             : 
      22             : #include "libmesh/boundary_info.h"
      23             : #include "libmesh/diff_system.h"
      24             : #include "libmesh/dof_map.h"
      25             : #include "libmesh/elem.h"
      26             : #include "libmesh/fe_base.h"
      27             : #include "libmesh/fe_interface.h"
      28             : #include "libmesh/libmesh_logging.h"
      29             : #include "libmesh/mesh_base.h"
      30             : #include "libmesh/numeric_vector.h"
      31             : #include "libmesh/quadrature.h"
      32             : #include "libmesh/system.h"
      33             : #include "libmesh/time_solver.h"
      34             : #include "libmesh/unsteady_solver.h" // For euler_residual
      35             : 
      36             : namespace libMesh
      37             : {
      38             : 
      39     2463762 : FEMContext::FEMContext (const System & sys,
      40             :                         const std::vector<unsigned int> * active_vars,
      41     2463762 :                         bool allocate_local_matrices)
      42     2463762 :   : FEMContext(sys, sys.extra_quadrature_order, active_vars,
      43     2463762 :                allocate_local_matrices)
      44             : {
      45     2463762 : }
      46             : 
      47     2463762 : FEMContext::FEMContext (const System & sys,
      48             :                         int extra_quadrature_order,
      49             :                         const std::vector<unsigned int> * active_vars,
      50     2463762 :                         bool allocate_local_matrices)
      51             :   : DiffContext(sys, allocate_local_matrices),
      52     2305736 :     side(0), edge(0),
      53     2305736 :     _mesh_sys(nullptr),
      54     2305736 :     _mesh_x_var(0),
      55     2305736 :     _mesh_y_var(0),
      56     2305736 :     _mesh_z_var(0),
      57     2305736 :     _atype(CURRENT),
      58     2305736 :     _custom_solution(nullptr),
      59     2463762 :     _boundary_info(sys.get_mesh().get_boundary_info()),
      60     2305736 :     _elem(nullptr),
      61     2463762 :     _dim(cast_int<unsigned char>(sys.get_mesh().mesh_dimension())),
      62     2305736 :     _elem_dim(0), /* This will be reset in set_elem(). */
      63      237039 :     _elem_dims(sys.get_mesh().elem_dimensions()),
      64     2305736 :     _element_qrule(4),
      65     2305736 :     _side_qrule(4),
      66     4927524 :     _extra_quadrature_order(extra_quadrature_order)
      67             : {
      68     2463762 :   if (active_vars)
      69             :     {
      70       60364 :       libmesh_assert(!active_vars->empty());
      71             :       auto vars_copy =
      72     2038977 :         std::make_unique<std::vector<unsigned int>>(*active_vars);
      73             : 
      74             :       // We want to do quick binary_search later
      75     1978613 :       std::sort(vars_copy->begin(), vars_copy->end());
      76             : 
      77     1918249 :       _active_vars = std::move(vars_copy);
      78     1857885 :     }
      79             : 
      80     2463762 :   init_internal_data(sys);
      81     2463762 : }
      82             : 
      83             : 
      84             : 
      85     2489641 : FEType FEMContext::find_hardest_fe_type()
      86             : {
      87      159694 :   const System & sys = this->get_system();
      88             :   FEType hardest_fe_type =
      89     2329947 :     sys.variable_type(_active_vars ?
      90     2489641 :                       (*_active_vars)[0] : 0);
      91             : 
      92     5992167 :   auto check_var = [&hardest_fe_type, &sys](unsigned int v)
      93             :     {
      94     2948808 :       FEType fe_type = sys.variable_type(v);
      95             : 
      96             :       // Make sure we find a non-SCALAR FE family, even in the case
      97             :       // where the first variable(s) weren't
      98     2948808 :       if (hardest_fe_type.family == SCALAR)
      99             :         {
     100           0 :           hardest_fe_type.family = fe_type.family;
     101           0 :           hardest_fe_type.order = fe_type.order;
     102             :         }
     103             : 
     104             :       // FIXME - we don't yet handle mixed finite elements from
     105             :       // different families which require different quadrature rules
     106             :       // libmesh_assert_equal_to (fe_type.family, hardest_fe_type.family);
     107             : 
     108             :       // We need to detect SCALAR's so we can prepare FE objects for
     109             :       // them, and so we don't mistake high order scalars as a reason
     110             :       // to crank up the quadrature order on other types.
     111     2948808 :       if (fe_type.family != SCALAR && fe_type.order > hardest_fe_type.order)
     112        4260 :         hardest_fe_type = fe_type;
     113     2598768 :     };
     114             : 
     115     2489641 :   if (_active_vars)
     116     4107037 :     for (auto v : *_active_vars)
     117     2128424 :       check_var(v);
     118             :   else
     119     1331412 :     for (auto v : make_range(sys.n_vars()))
     120      820384 :       check_var(v);
     121             : 
     122     2569488 :   return hardest_fe_type;
     123             : }
     124             : 
     125             : 
     126     2489449 : void FEMContext::attach_quadrature_rules()
     127             : {
     128      159662 :   const System & sys = this->get_system();
     129             : 
     130     3473415 :   auto attach_rules = [this, &sys](unsigned int v)
     131             :     {
     132     5924571 :       for (const auto & dim : _elem_dims)
     133             :         {
     134     2975955 :           FEType fe_type = sys.variable_type(v);
     135             : 
     136     3071254 :           _element_fe[dim][fe_type]->attach_quadrature_rule(_element_qrule[dim].get());
     137     2975955 :           if (dim)
     138     3025150 :             _side_fe[dim][fe_type]->attach_quadrature_rule(_side_qrule[dim].get());
     139     2975955 :           if (dim == 3)
     140      918832 :             _edge_fe[fe_type]->attach_quadrature_rule(_edge_qrule.get());
     141             :         };
     142     2598560 :     };
     143             : 
     144     2489449 :   if (_active_vars)
     145     4107037 :     for (auto v : *_active_vars)
     146     2128424 :       attach_rules(v);
     147             :   else
     148     1331028 :     for (auto v : make_range(sys.n_vars()))
     149      820192 :       attach_rules(v);
     150     2489449 : }
     151             : 
     152             : 
     153             : 
     154     2463762 : void FEMContext::use_default_quadrature_rules(int extra_quadrature_order)
     155             : {
     156     2463762 :   _extra_quadrature_order = extra_quadrature_order;
     157             : 
     158     2463762 :   FEType hardest_fe_type = this->find_hardest_fe_type();
     159             : 
     160     4939558 :   for (const auto & dim : _elem_dims)
     161             :     {
     162             :       // Create an adequate quadrature rule
     163     2475796 :       _element_qrule[dim] =
     164     4872225 :         hardest_fe_type.default_quadrature_rule(dim, _extra_quadrature_order);
     165     2475796 :       if (dim)
     166     2448999 :         _side_qrule[dim] =
     167     4897998 :           hardest_fe_type.default_quadrature_rule(dim-1, _extra_quadrature_order);
     168     2475796 :       if (dim == 3)
     169     1500340 :         _edge_qrule = hardest_fe_type.default_quadrature_rule(1, _extra_quadrature_order);
     170             :     }
     171             : 
     172     2463762 :   this->attach_quadrature_rules();
     173     2463762 : }
     174             : 
     175             : 
     176       24125 : void FEMContext::use_unweighted_quadrature_rules(int extra_quadrature_order)
     177             : {
     178       24125 :   _extra_quadrature_order = extra_quadrature_order;
     179             : 
     180       24125 :   FEType hardest_fe_type = this->find_hardest_fe_type();
     181             : 
     182       48250 :   for (const auto & dim : _elem_dims)
     183             :     {
     184             :       // Create an adequate quadrature rule
     185       24125 :       _element_qrule[dim] =
     186       47476 :         hardest_fe_type.unweighted_quadrature_rule(dim, _extra_quadrature_order);
     187       24125 :       _side_qrule[dim] =
     188       47476 :         hardest_fe_type.unweighted_quadrature_rule(dim-1, _extra_quadrature_order);
     189       24125 :       if (dim == 3)
     190        2800 :         _edge_qrule = hardest_fe_type.unweighted_quadrature_rule(1, _extra_quadrature_order);
     191             :     }
     192             : 
     193       24125 :   this->attach_quadrature_rules();
     194       24125 : }
     195             : 
     196             : 
     197        1562 : void FEMContext::use_quadrature_rules(QuadratureType qt, int extra_quadrature_order)
     198             : {
     199        1562 :   _extra_quadrature_order = extra_quadrature_order;
     200             : 
     201        1562 :   const FEType hardest_fe_type = this->find_hardest_fe_type();
     202             : 
     203             :   // Match the accuracy of the default rule (which over-integrates a mass
     204             :   // matrix), then add any requested extra order on top.
     205             :   const Order order = static_cast<Order>(hardest_fe_type.default_quadrature_order()
     206          44 :                                          + extra_quadrature_order);
     207             : 
     208        3124 :   for (const auto & dim : _elem_dims)
     209             :     {
     210             :       // Create the requested quadrature rule for the element and its
     211             :       // lower-dimensional sides/edges
     212        1562 :       _element_qrule[dim] = QBase::build(qt, dim, order);
     213        1562 :       if (dim)
     214        1650 :         _side_qrule[dim] = QBase::build(qt, cast_int<unsigned int>(dim - 1), order);
     215        1562 :       if (dim == 3)
     216           0 :         _edge_qrule = QBase::build(qt, 1, order);
     217             :     }
     218             : 
     219        1562 :   this->attach_quadrature_rules();
     220        1562 : }
     221             : 
     222             : 
     223     2463762 : void FEMContext::init_internal_data(const System & sys)
     224             : {
     225             :   // Reserve space for the FEAbstract and QBase objects for each
     226             :   // element dimension possibility (0,1,2,3)
     227             : 
     228             :   // Note: we would simply resize() all four of these vectors, but
     229             :   // some compilers (ICC 19, MSVC) generate a diagnostic about copying
     230             :   // a std::unique_ptr in this case, so the following two lines are a
     231             :   // workaround.
     232     2463762 :   _element_fe = std::vector<std::map<FEType, std::unique_ptr<FEAbstract>>>(4);
     233     2463762 :   _side_fe = std::vector<std::map<FEType, std::unique_ptr<FEAbstract>>>(4);
     234     2463762 :   _element_fe_var.resize(4);
     235     2463762 :   _side_fe_var.resize(4);
     236             : 
     237             :   // We need to know which of our variables has the hardest
     238             :   // shape functions to numerically integrate.
     239             : 
     240     2463762 :   unsigned int nv = sys.n_vars();
     241       79013 :   libmesh_assert (nv);
     242             : 
     243       79013 :   bool have_scalar = false;
     244             : 
     245     2463762 :   if (_active_vars)
     246             :     {
     247     4107037 :       for (auto v : *_active_vars)
     248     2128424 :         if (sys.variable_type(v).family == SCALAR)
     249             :           {
     250           0 :             have_scalar = true;
     251           0 :             break;
     252             :           }
     253             :     }
     254             :   else
     255             :     {
     256     1276110 :       for (auto v : make_range(sys.n_vars()))
     257      792943 :         if (sys.variable_type(v).family == SCALAR)
     258             :           {
     259          56 :             have_scalar = true;
     260          56 :             break;
     261             :           }
     262             :     }
     263             : 
     264     2463762 :   if (have_scalar)
     265             :     // SCALAR FEs have dimension 0 by assumption
     266        1982 :     _elem_dims.insert(0);
     267             : 
     268     2759832 :   auto build_var_fe = [this, &sys](unsigned int dim,
     269     7357703 :                                    unsigned int i)
     270             :     {
     271     2948706 :       FEType fe_type = sys.variable_type(i);
     272     2948706 :       const bool add_p_level = fe_type.p_refinement;
     273             : 
     274     3043143 :       auto & element_fe = _element_fe[dim][fe_type];
     275     3043143 :       auto & side_fe = _side_fe[dim][fe_type];
     276     2948706 :       if (!element_fe)
     277             :         {
     278     5196681 :           element_fe = FEAbstract::build(dim, fe_type);
     279       84959 :           element_fe->add_p_level_in_reinit(add_p_level);
     280     5196681 :           side_fe = FEAbstract::build(dim, fe_type);
     281       84959 :           side_fe->add_p_level_in_reinit(add_p_level);
     282             : 
     283     2640820 :           if (dim == 3)
     284             :           {
     285      779380 :             auto & edge_fe = _edge_fe[fe_type];
     286     1536126 :             edge_fe = FEAbstract::build(dim, fe_type);
     287       22634 :             edge_fe->add_p_level_in_reinit(add_p_level);
     288             :           }
     289             :         }
     290             : 
     291     3137580 :       _element_fe_var[dim][i] = element_fe.get();
     292     3043143 :       _side_fe_var[dim][i] = side_fe.get();
     293     2948706 :       if ((dim) == 3)
     294      917412 :         _edge_fe_var[i] = _edge_fe[fe_type].get();
     295     2573623 :     };
     296             : 
     297     4939558 :   for (const auto & dim : _elem_dims)
     298             :     {
     299             :       // Create finite element objects
     300     2555163 :       _element_fe_var[dim].resize(nv);
     301     2555163 :       _side_fe_var[dim].resize(nv);
     302     2475796 :       if (dim == 3)
     303      761228 :         _edge_fe_var.resize(nv);
     304             : 
     305     2475796 :       if (_active_vars)
     306     4115149 :         for (auto v : *_active_vars)
     307     2132480 :           build_var_fe(dim, v);
     308             :       else
     309     1309353 :         for (auto v : make_range(nv))
     310      816226 :           build_var_fe(dim, v);
     311             :     }
     312             : 
     313     2463762 :   this->use_default_quadrature_rules(_extra_quadrature_order);
     314     2463762 : }
     315             : 
     316     3116915 : FEMContext::~FEMContext()
     317             : {
     318     7469232 : }
     319             : 
     320             : 
     321             : 
     322     2459104 : bool FEMContext::has_side_boundary_id(boundary_id_type id) const
     323             : {
     324     2459104 :   return _boundary_info.has_boundary_id(&(this->get_elem()), side, id);
     325             : }
     326             : 
     327             : 
     328             : 
     329           0 : void FEMContext::side_boundary_ids(std::vector<boundary_id_type> & vec_to_fill) const
     330             : {
     331           0 :   _boundary_info.boundary_ids(&(this->get_elem()), side, vec_to_fill);
     332           0 : }
     333             : 
     334             : 
     335             : 
     336             : template<typename OutputType,
     337             :          typename FEMContext::FENeeded<OutputType>::value_getter fe_getter,
     338             :          FEMContext::diff_subsolution_getter subsolution_getter>
     339   294957647 : void FEMContext::some_value(unsigned int var, unsigned int qp, OutputType & u) const
     340             : {
     341             :   // Get local-to-global dof index lookup
     342    25411290 :   const unsigned int n_dofs = cast_int<unsigned int>
     343    50822580 :     (this->get_dof_indices(var).size());
     344             : 
     345             :   // Get current local coefficients
     346    25411290 :   const DenseSubVector<Number> & coef = (this->*subsolution_getter)(var);
     347    25411290 :   libmesh_assert_equal_to(coef.size(), n_dofs);
     348             : 
     349             :   // Get finite element object
     350    25411290 :   typename FENeeded<OutputType>::value_base * fe = nullptr;
     351    25411290 :   (this->*fe_getter)( var, fe, this->get_elem_dim() );
     352             : 
     353             :   // Get shape function values at quadrature point
     354             :   const std::vector<std::vector
     355    25411290 :                     <typename FENeeded<OutputType>::value_shape>> & phi = fe->get_phi();
     356    25411290 :   libmesh_assert_equal_to(phi.size(), n_dofs);
     357             : 
     358             :   // Accumulate solution value
     359   277836286 :   u = 0.;
     360             : 
     361  2398008052 :   for (unsigned int l=0; l != n_dofs; l++)
     362             :     {
     363   179827914 :       libmesh_assert_less(qp, phi[l].size());
     364  2641443843 :       u += phi[l][qp] * coef(l);
     365             :     }
     366   294957647 : }
     367             : 
     368             : 
     369             : 
     370             : template<typename OutputType,
     371             :          typename FEMContext::FENeeded<OutputType>::grad_getter fe_getter,
     372             :          FEMContext::diff_subsolution_getter subsolution_getter>
     373   276579940 : void FEMContext::some_gradient(unsigned int var, unsigned int qp, OutputType & du) const
     374             : {
     375             :   // Get local-to-global dof index lookup
     376             :   const unsigned int n_dofs = cast_int<unsigned int>
     377    48169212 :     (this->get_dof_indices(var).size());
     378             : 
     379             :   // Get current local coefficients
     380    24084606 :   const DenseSubVector<Number> & coef = (this->*subsolution_getter)(var);
     381             : 
     382             :   // Get finite element object
     383    24084606 :   typename FENeeded<OutputType>::grad_base * fe = nullptr;
     384    24084606 :   (this->*fe_getter)( var, fe, this->get_elem_dim() );
     385             : 
     386             :   // Get shape function values at quadrature point
     387             :   const std::vector<std::vector
     388             :                     <typename FENeeded<OutputType>::grad_base::OutputGradient>>
     389    24084606 :     & dphi = fe->get_dphi();
     390             : 
     391             :   // Accumulate solution derivatives
     392    24084606 :   du = 0;
     393             : 
     394  2360939544 :   for (unsigned int l=0; l != n_dofs; l++)
     395  2264506286 :     du.add_scaled(dphi[l][qp], coef(l));
     396             : 
     397   300664546 :   return;
     398             : }
     399             : 
     400             : 
     401             : 
     402             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     403             : template<typename OutputType,
     404             :          typename FEMContext::FENeeded<OutputType>::hess_getter fe_getter,
     405             :          FEMContext::diff_subsolution_getter subsolution_getter>
     406           0 : void FEMContext::some_hessian(unsigned int var, unsigned int qp, OutputType & d2u) const
     407             : {
     408             :   // Get local-to-global dof index lookup
     409             :   const unsigned int n_dofs = cast_int<unsigned int>
     410           0 :     (this->get_dof_indices(var).size());
     411             : 
     412             :   // Get current local coefficients
     413           0 :   const DenseSubVector<Number> & coef = (this->*subsolution_getter)(var);
     414             : 
     415             :   // Get finite element object
     416           0 :   typename FENeeded<OutputType>::hess_base * fe = nullptr;
     417           0 :   (this->*fe_getter)( var, fe, this->get_elem_dim() );
     418             : 
     419             :   // Get shape function values at quadrature point
     420             :   const std::vector<std::vector
     421             :                     <typename FENeeded<OutputType>::hess_base::OutputTensor>>
     422           0 :     & d2phi = fe->get_d2phi();
     423             : 
     424             :   // Accumulate solution second derivatives
     425           0 :   d2u = 0.0;
     426             : 
     427           0 :   for (unsigned int l=0; l != n_dofs; l++)
     428           0 :     d2u.add_scaled(d2phi[l][qp], coef(l));
     429             : 
     430           0 :   return;
     431             : }
     432             : #endif
     433             : 
     434             : 
     435             : 
     436     1856380 : Number FEMContext::interior_value(unsigned int var, unsigned int qp) const
     437             : {
     438        8269 :   Number u;
     439             : 
     440      330304 :   this->interior_value( var, qp, u );
     441             : 
     442     1856380 :   return u;
     443             : }
     444             : 
     445             : template<typename OutputType>
     446   101215152 : void FEMContext::interior_value(unsigned int var, unsigned int qp,
     447             :                                 OutputType & u) const
     448             : {
     449    17173600 :   this->some_value<OutputType,
     450             :                    &FEMContext::get_element_fe<typename TensorTools::MakeReal<OutputType>::type>,
     451    85567628 :                    &DiffContext::get_elem_solution>(var, qp, u);
     452   101215152 : }
     453             : 
     454             : 
     455             : template<typename OutputType>
     456     2173248 : void FEMContext::interior_values (unsigned int var,
     457             :                                   const NumericVector<Number> & _system_vector,
     458             :                                   std::vector<OutputType> & u_vals) const
     459             : {
     460             :   typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
     461             : 
     462             :   // Get local-to-global dof index lookup
     463             :   const unsigned int n_dofs = cast_int<unsigned int>
     464      395136 :     (this->get_dof_indices(var).size());
     465             : 
     466             :   // Get current local coefficients
     467     2173248 :   const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
     468             : 
     469             :   // Get the finite element object
     470      197568 :   FEGenericBase<OutputShape> * fe = nullptr;
     471      197568 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     472             : 
     473             :   // Get shape function values at quadrature point
     474      197568 :   const std::vector<std::vector<OutputShape>> & phi = fe->get_phi();
     475             : 
     476             :   // Loop over all the q_points on this element
     477    12344640 :   for (auto qp : index_range(u_vals))
     478             :     {
     479      924672 :       OutputType & u = u_vals[qp];
     480             : 
     481             :       // Compute the value at this q_point
     482    10171392 :       u = 0.;
     483             : 
     484    50856960 :       for (unsigned int l=0; l != n_dofs; l++)
     485    51781632 :         u += phi[l][qp] * coef(l);
     486             :     }
     487             : 
     488     2370816 :   return;
     489             : }
     490             : 
     491   116032860 : Gradient FEMContext::interior_gradient(unsigned int var,
     492             :                                        unsigned int qp) const
     493             : {
     494    10669062 :   Gradient du;
     495             : 
     496    21338124 :   this->interior_gradient( var, qp, du );
     497             : 
     498   116032860 :   return du;
     499             : }
     500             : 
     501             : 
     502             : 
     503             : template<typename OutputType>
     504   181885204 : void FEMContext::interior_gradient(unsigned int var,
     505             :                                    unsigned int qp,
     506             :                                    OutputType & du) const
     507             : {
     508    48169212 :   this->some_gradient<OutputType,
     509             :                       &FEMContext::get_element_fe<typename TensorTools::MakeReal
     510             :                                                   <typename TensorTools::DecrementRank
     511             :                                                    <OutputType>::type>::type>,
     512   228410728 :                       &DiffContext::get_elem_solution>(var, qp, du);
     513   181885204 : }
     514             : 
     515             : 
     516             : 
     517             : template<typename OutputType>
     518           0 : void FEMContext::interior_gradients(unsigned int var,
     519             :                                     const NumericVector<Number> & _system_vector,
     520             :                                     std::vector<OutputType> & du_vals) const
     521             : {
     522             :   typedef typename TensorTools::MakeReal
     523             :     <typename TensorTools::DecrementRank<OutputType>::type>::type
     524             :     OutputShape;
     525             : 
     526             :   // Get local-to-global dof index lookup
     527             :   const unsigned int n_dofs = cast_int<unsigned int>
     528           0 :     (this->get_dof_indices(var).size());
     529             : 
     530             :   // Get current local coefficients
     531           0 :   const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
     532             : 
     533             :   // Get finite element object
     534           0 :   FEGenericBase<OutputShape> * fe = nullptr;
     535           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     536             : 
     537             :   // Get shape function values at quadrature point
     538           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = fe->get_dphi();
     539             : 
     540             :   // Loop over all the q_points in this finite element
     541           0 :   for (auto qp : index_range(du_vals))
     542             :     {
     543           0 :       OutputType & du = du_vals[qp];
     544             : 
     545             :       // Compute the gradient at this q_point
     546           0 :       du = 0;
     547             : 
     548           0 :       for (unsigned int l=0; l != n_dofs; l++)
     549           0 :         du.add_scaled(dphi[l][qp], coef(l));
     550             :     }
     551             : 
     552           0 :   return;
     553             : }
     554             : 
     555             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     556           0 : Tensor FEMContext::interior_hessian(unsigned int var, unsigned int qp) const
     557             : {
     558           0 :   Tensor d2u;
     559             : 
     560           0 :   this->interior_hessian( var, qp, d2u );
     561             : 
     562           0 :   return d2u;
     563             : }
     564             : 
     565             : template<typename OutputType>
     566           0 : void FEMContext::interior_hessian(unsigned int var, unsigned int qp,
     567             :                                   OutputType & d2u) const
     568             : {
     569           0 :   this->some_hessian<OutputType,
     570             :                      &FEMContext::get_element_fe
     571             :                      <typename TensorTools::MakeReal
     572             :                       <typename TensorTools::DecrementRank
     573             :                        <typename TensorTools::DecrementRank
     574             :                         <OutputType>::type>::type>::type>,
     575           0 :                      &DiffContext::get_elem_solution>(var, qp, d2u);
     576           0 : }
     577             : 
     578             : 
     579             : template<typename OutputType>
     580           0 : void FEMContext::interior_hessians(unsigned int var,
     581             :                                    const NumericVector<Number> & _system_vector,
     582             :                                    std::vector<OutputType> & d2u_vals) const
     583             : {
     584             :   typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
     585             :   typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
     586             :   typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
     587             : 
     588             :   // Get local-to-global dof index lookup
     589             :   const unsigned int n_dofs = cast_int<unsigned int>
     590           0 :     (this->get_dof_indices(var).size());
     591             : 
     592             :   // Get current local coefficients
     593           0 :   const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
     594             : 
     595             :   // Get finite element object
     596           0 :   FEGenericBase<OutputShape> * fe = nullptr;
     597           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     598             : 
     599             :   // Get shape function values at quadrature point
     600           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> & d2phi = fe->get_d2phi();
     601             : 
     602             :   // Loop over all the q_points in this finite element
     603           0 :   for (auto qp : index_range(d2u_vals))
     604             :     {
     605           0 :       OutputType & d2u = d2u_vals[qp];
     606             : 
     607             :       // Compute the gradient at this q_point
     608           0 :       d2u = 0;
     609             : 
     610           0 :       for (unsigned int l=0; l != n_dofs; l++)
     611           0 :         d2u.add_scaled(d2phi[l][qp], coef(l));
     612             :     }
     613             : 
     614           0 :   return;
     615             : }
     616             : 
     617             : 
     618             : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     619             : 
     620             : 
     621             : template<typename OutputType>
     622     2139648 : void FEMContext::interior_curl(unsigned int var, unsigned int qp,
     623             :                                OutputType & curl_u) const
     624             : {
     625             :   typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
     626             : 
     627             :   // Get local-to-global dof index lookup
     628             :   const unsigned int n_dofs = cast_int<unsigned int>
     629      265856 :     (this->get_dof_indices(var).size());
     630             : 
     631             :   // Get current local coefficients
     632      132928 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
     633      132928 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
     634             : 
     635             :   // Get finite element object
     636      132928 :   FEGenericBase<OutputShape> * fe = nullptr;
     637      132928 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     638             : 
     639             :   // Get shape function values at quadrature point
     640      352320 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputShape>> & curl_phi = fe->get_curl_phi();
     641             : 
     642             :   // Accumulate solution curl
     643      132928 :   curl_u = 0.;
     644             : 
     645    16677888 :   for (unsigned int l=0; l != n_dofs; l++)
     646    15502080 :     curl_u.add_scaled(curl_phi[l][qp], coef(l));
     647             : 
     648     2272576 :   return;
     649             : }
     650             : 
     651             : 
     652             : template<typename OutputType>
     653           0 : void FEMContext::interior_div(unsigned int var, unsigned int qp,
     654             :                               OutputType & div_u) const
     655             : {
     656             :   typedef typename
     657             :     TensorTools::IncrementRank
     658             :     <typename TensorTools::MakeReal<OutputType>::type>::type OutputShape;
     659             : 
     660             :   // Get local-to-global dof index lookup
     661             :   const unsigned int n_dofs = cast_int<unsigned int>
     662           0 :     (this->get_dof_indices(var).size());
     663             : 
     664             :   // Get current local coefficients
     665           0 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
     666           0 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
     667             : 
     668             :   // Get finite element object
     669           0 :   FEGenericBase<OutputShape> * fe = nullptr;
     670           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     671             : 
     672             :   // Get shape function values at quadrature point
     673           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputDivergence>> & div_phi = fe->get_div_phi();
     674             : 
     675             :   // Accumulate solution curl
     676           0 :   div_u = 0.;
     677             : 
     678           0 :   for (unsigned int l=0; l != n_dofs; l++)
     679           0 :     div_u += div_phi[l][qp] * coef(l);
     680             : 
     681           0 :   return;
     682             : }
     683             : 
     684             : 
     685     3159219 : Number FEMContext::side_value(unsigned int var,
     686             :                               unsigned int qp) const
     687             : {
     688     3159219 :   Number u = 0.;
     689             : 
     690      705124 :   this->side_value( var, qp, u );
     691             : 
     692     3159219 :   return u;
     693             : }
     694             : 
     695             : 
     696             : template<typename OutputType>
     697      970852 : void FEMContext::side_value(unsigned int var,
     698             :                             unsigned int qp,
     699             :                             OutputType & u) const
     700             : {
     701      738020 :   this->some_value<OutputType,
     702             :                    &FEMContext::get_side_fe<typename TensorTools::MakeReal<OutputType>::type>,
     703     2686927 :                    &DiffContext::get_elem_solution>(var, qp, u);
     704      970852 : }
     705             : 
     706             : 
     707             : template<typename OutputType>
     708           0 : void FEMContext::side_values(unsigned int var,
     709             :                              const NumericVector<Number> & _system_vector,
     710             :                              std::vector<OutputType> & u_vals) const
     711             : {
     712             :   typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
     713             : 
     714             :   // Get local-to-global dof index lookup
     715             :   const unsigned int n_dofs = cast_int<unsigned int>
     716           0 :     (this->get_dof_indices(var).size());
     717             : 
     718             :   // Get current local coefficients
     719           0 :   const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
     720             : 
     721             :   // Get the finite element object
     722           0 :   FEGenericBase<OutputShape> * the_side_fe = nullptr;
     723           0 :   this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
     724             : 
     725             :   // Get shape function values at quadrature point
     726           0 :   const std::vector<std::vector<OutputShape>> & phi = the_side_fe->get_phi();
     727             : 
     728             :   // Loop over all the q_points on this element
     729           0 :   for (auto qp : index_range(u_vals))
     730             :     {
     731           0 :       OutputType & u = u_vals[qp];
     732             : 
     733             :       // Compute the value at this q_point
     734           0 :       u = 0.;
     735             : 
     736           0 :       for (unsigned int l=0; l != n_dofs; l++)
     737           0 :         u += phi[l][qp] * coef(l);
     738             :     }
     739             : 
     740           0 :   return;
     741             : }
     742             : 
     743     5031971 : Gradient FEMContext::side_gradient(unsigned int var, unsigned int qp) const
     744             : {
     745      560627 :   Gradient du;
     746             : 
     747     5031971 :   this->side_gradient( var, qp, du );
     748             : 
     749     5031971 :   return du;
     750             : }
     751             : 
     752             : 
     753             : template<typename OutputType>
     754     5031971 : void FEMContext::side_gradient(unsigned int var, unsigned int qp,
     755             :                                OutputType & du) const
     756             : {
     757             :   typedef typename TensorTools::MakeReal
     758             :     <typename TensorTools::DecrementRank<OutputType>::type>::type
     759             :     OutputShape;
     760             : 
     761             :   // Get local-to-global dof index lookup
     762             :   const unsigned int n_dofs = cast_int<unsigned int>
     763     1121254 :     (this->get_dof_indices(var).size());
     764             : 
     765             :   // Get current local coefficients
     766      560627 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
     767      560627 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
     768             : 
     769             :   // Get finite element object
     770      560627 :   FEGenericBase<OutputShape> * the_side_fe = nullptr;
     771      560627 :   this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
     772             : 
     773             :   // Get shape function values at quadrature point
     774      560627 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = the_side_fe->get_dphi();
     775             : 
     776             :   // Accumulate solution derivatives
     777      560627 :   du = 0.;
     778             : 
     779    39480564 :   for (unsigned int l=0; l != n_dofs; l++)
     780    38243248 :     du.add_scaled(dphi[l][qp], coef(l));
     781             : 
     782     5592598 :   return;
     783             : }
     784             : 
     785             : 
     786             : 
     787             : template<typename OutputType>
     788           0 : void FEMContext::side_gradients(unsigned int var,
     789             :                                 const NumericVector<Number> & _system_vector,
     790             :                                 std::vector<OutputType> & du_vals) const
     791             : {
     792             :   typedef typename TensorTools::MakeReal
     793             :     <typename TensorTools::DecrementRank<OutputType>::type>::type
     794             :     OutputShape;
     795             : 
     796             :   // Get local-to-global dof index lookup
     797             :   const unsigned int n_dofs = cast_int<unsigned int>
     798           0 :     (this->get_dof_indices(var).size());
     799             : 
     800             :   // Get current local coefficients
     801           0 :   const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
     802             : 
     803             :   // Get finite element object
     804           0 :   FEGenericBase<OutputShape> * the_side_fe = nullptr;
     805           0 :   this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
     806             : 
     807             :   // Get shape function values at quadrature point
     808           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = the_side_fe->get_dphi();
     809             : 
     810             :   // Loop over all the q_points in this finite element
     811           0 :   for (auto qp : index_range(du_vals))
     812             :     {
     813           0 :       OutputType & du = du_vals[qp];
     814             : 
     815           0 :       du = 0;
     816             : 
     817             :       // Compute the gradient at this q_point
     818           0 :       for (unsigned int l=0; l != n_dofs; l++)
     819           0 :         du.add_scaled(dphi[l][qp], coef(l));
     820             :     }
     821             : 
     822           0 :   return;
     823             : }
     824             : 
     825             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     826           0 : Tensor FEMContext::side_hessian(unsigned int var,
     827             :                                 unsigned int qp) const
     828             : {
     829           0 :   Tensor d2u;
     830             : 
     831           0 :   this->side_hessian( var, qp, d2u );
     832             : 
     833           0 :   return d2u;
     834             : }
     835             : 
     836             : 
     837             : 
     838             : template<typename OutputType>
     839           0 : void FEMContext::side_hessian(unsigned int var,
     840             :                               unsigned int qp,
     841             :                               OutputType & d2u) const
     842             : {
     843           0 :   this->some_hessian<OutputType,
     844             :                      &FEMContext::get_side_fe
     845             :                      <typename TensorTools::MakeReal
     846             :                       <typename TensorTools::DecrementRank
     847             :                        <typename TensorTools::DecrementRank
     848             :                         <OutputType>::type>::type>::type>,
     849           0 :                      &DiffContext::get_elem_solution>(var, qp, d2u);
     850           0 : }
     851             : 
     852             : 
     853             : 
     854             : template<typename OutputType>
     855           0 : void FEMContext::side_hessians(unsigned int var,
     856             :                                const NumericVector<Number> & _system_vector,
     857             :                                std::vector<OutputType> & d2u_vals) const
     858             : {
     859             :   typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
     860             :   typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
     861             :   typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
     862             : 
     863             :   // Get local-to-global dof index lookup
     864             :   const unsigned int n_dofs = cast_int<unsigned int>
     865           0 :     (this->get_dof_indices(var).size());
     866             : 
     867             :   // Get current local coefficients
     868           0 :   const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
     869             : 
     870             :   // Get finite element object
     871           0 :   FEGenericBase<OutputShape> * the_side_fe = nullptr;
     872           0 :   this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
     873             : 
     874             :   // Get shape function values at quadrature point
     875           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> & d2phi = the_side_fe->get_d2phi();
     876             : 
     877             :   // Loop over all the q_points in this finite element
     878           0 :   for (auto qp : index_range(d2u_vals))
     879             :     {
     880           0 :       OutputType & d2u = d2u_vals[qp];
     881             : 
     882             :       // Compute the gradient at this q_point
     883           0 :       d2u = 0;
     884             : 
     885           0 :       for (unsigned int l=0; l != n_dofs; l++)
     886           0 :         d2u.add_scaled(d2phi[l][qp], coef(l));
     887             :     }
     888             : 
     889           0 :   return;
     890             : }
     891             : 
     892             : 
     893             : 
     894             : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     895             : 
     896             : 
     897             : 
     898       61472 : Number FEMContext::point_value(unsigned int var, const Point & p) const
     899             : {
     900       61472 :   Number u = 0.;
     901             : 
     902       61472 :   this->point_value( var, p, u );
     903             : 
     904       61472 :   return u;
     905             : }
     906             : 
     907             : template<typename OutputType>
     908     7847356 : void FEMContext::point_value(unsigned int var,
     909             :                              const Point & p,
     910             :                              OutputType & u,
     911             :                              const Real tolerance) const
     912             : {
     913             :   typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
     914             : 
     915             :   // Get local-to-global dof index lookup
     916             :   const unsigned int n_dofs = cast_int<unsigned int>
     917     1325824 :     (this->get_dof_indices(var).size());
     918             : 
     919             :   // Get current local coefficients
     920      662912 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
     921      662912 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
     922             : 
     923             :   // Get finite element object
     924      662912 :   FEGenericBase<OutputShape> * fe = nullptr;
     925      662912 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     926             : 
     927             :   // Build a FE for calculating u(p)
     928     1325824 :   FEGenericBase<OutputShape> * fe_new =
     929     6521532 :     this->build_new_fe( fe, p, tolerance, 0 );
     930             : 
     931             :   // Get the values of the shape function derivatives
     932      662912 :   const std::vector<std::vector<OutputShape>> &  phi = fe_new->get_phi();
     933             : 
     934     7491734 :   u = 0.;
     935             : 
     936   111510770 :   for (unsigned int l=0; l != n_dofs; l++)
     937   120748064 :     u += phi[l][0] * coef(l);
     938             : 
     939     8510268 :   return;
     940             : }
     941             : 
     942             : 
     943             : 
     944       61472 : Gradient FEMContext::point_gradient(unsigned int var, const Point & p) const
     945             : {
     946        5440 :   Gradient grad_u;
     947             : 
     948       61472 :   this->point_gradient( var, p, grad_u );
     949             : 
     950       61472 :   return grad_u;
     951             : }
     952             : 
     953             : 
     954             : 
     955             : template<typename OutputType>
     956      255322 : void FEMContext::point_gradient(unsigned int var,
     957             :                                 const Point & p,
     958             :                                 OutputType & grad_u,
     959             :                                 const Real tolerance) const
     960             : {
     961             :   typedef typename TensorTools::MakeReal
     962             :     <typename TensorTools::DecrementRank<OutputType>::type>::type
     963             :     OutputShape;
     964             : 
     965             :   // Get local-to-global dof index lookup
     966             :   const unsigned int n_dofs = cast_int<unsigned int>
     967       40592 :     (this->get_dof_indices(var).size());
     968             : 
     969             :   // Get current local coefficients
     970       20296 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
     971       20296 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
     972             : 
     973             :   // Get finite element object
     974       20296 :   FEGenericBase<OutputShape> * fe = nullptr;
     975       20296 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
     976             : 
     977             :   // Build a FE for calculating u(p)
     978       40592 :   FEGenericBase<OutputShape> * fe_new =
     979      214730 :     this->build_new_fe( fe, p, tolerance, 1 );
     980             : 
     981             :   // Get the values of the shape function derivatives
     982       20296 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> &  dphi = fe_new->get_dphi();
     983             : 
     984       20296 :   grad_u = 0.0;
     985             : 
     986     3105058 :   for (unsigned int l=0; l != n_dofs; l++)
     987     3073240 :     grad_u.add_scaled(dphi[l][0], coef(l));
     988             : 
     989      275618 :   return;
     990             : }
     991             : 
     992             : 
     993             : 
     994             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
     995             : 
     996           0 : Tensor FEMContext::point_hessian(unsigned int var, const Point & p) const
     997             : {
     998           0 :   Tensor hess_u;
     999             : 
    1000           0 :   this->point_hessian( var, p, hess_u );
    1001             : 
    1002           0 :   return hess_u;
    1003             : }
    1004             : 
    1005             : 
    1006             : template<typename OutputType>
    1007          39 : void FEMContext::point_hessian(unsigned int var,
    1008             :                                const Point & p,
    1009             :                                OutputType & hess_u,
    1010             :                                const Real tolerance) const
    1011             : {
    1012             :   typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
    1013             :   typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
    1014             :   typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
    1015             : 
    1016             :   // Get local-to-global dof index lookup
    1017             :   const unsigned int n_dofs = cast_int<unsigned int>
    1018           6 :     (this->get_dof_indices(var).size());
    1019             : 
    1020             :   // Get current local coefficients
    1021           3 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
    1022           3 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
    1023             : 
    1024             :   // Get finite element object
    1025           3 :   FEGenericBase<OutputShape> * fe = nullptr;
    1026           3 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
    1027             : 
    1028             :   // Build a FE for calculating u(p)
    1029           6 :   FEGenericBase<OutputShape> * fe_new =
    1030          33 :     this->build_new_fe( fe, p, tolerance, 2 );
    1031             : 
    1032             :   // Get the values of the shape function derivatives
    1033           3 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> &  d2phi = fe_new->get_d2phi();
    1034             : 
    1035           3 :   hess_u = 0.0;
    1036             : 
    1037         351 :   for (unsigned int l=0; l != n_dofs; l++)
    1038         336 :     hess_u.add_scaled(d2phi[l][0], coef(l));
    1039             : 
    1040          42 :   return;
    1041             : }
    1042             : 
    1043             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
    1044             : 
    1045             : 
    1046             : template<typename OutputType>
    1047           0 : void FEMContext::point_curl(unsigned int var,
    1048             :                             const Point & p,
    1049             :                             OutputType & curl_u,
    1050             :                             const Real tolerance) const
    1051             : {
    1052             :   typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
    1053             : 
    1054             :   // Get local-to-global dof index lookup
    1055             :   const unsigned int n_dofs = cast_int<unsigned int>
    1056           0 :     (this->get_dof_indices(var).size());
    1057             : 
    1058             :   // Get current local coefficients
    1059           0 :   libmesh_assert_greater (this->_elem_subsolutions.size(), var);
    1060           0 :   const DenseSubVector<Number> & coef = this->get_elem_solution(var);
    1061             : 
    1062             :   // Get finite element object
    1063           0 :   FEGenericBase<OutputShape> * fe = nullptr;
    1064           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
    1065             : 
    1066             :   // Build a FE for calculating u(p)
    1067           0 :   FEGenericBase<OutputShape> * fe_new =
    1068           0 :     this->build_new_fe( fe, p, tolerance, 3 );
    1069             : 
    1070             :   // Get the values of the shape function derivatives
    1071           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputShape>> &  curl_phi = fe_new->get_curl_phi();
    1072             : 
    1073           0 :   curl_u = 0.0;
    1074             : 
    1075           0 :   for (unsigned int l=0; l != n_dofs; l++)
    1076           0 :     curl_u.add_scaled(curl_phi[l][0], coef(l));
    1077             : 
    1078           0 :   return;
    1079             : }
    1080             : 
    1081             : 
    1082             : 
    1083           0 : Number FEMContext::fixed_interior_value(unsigned int var, unsigned int qp) const
    1084             : {
    1085           0 :   Number u = 0.;
    1086             : 
    1087           0 :   this->fixed_interior_value( var, qp, u );
    1088             : 
    1089           0 :   return u;
    1090             : }
    1091             : 
    1092             : 
    1093             : 
    1094             : template<typename OutputType>
    1095           0 : void FEMContext::fixed_interior_value(unsigned int var, unsigned int qp,
    1096             :                                       OutputType & u) const
    1097             : {
    1098           0 :   this->some_value<OutputType,
    1099             :                    &FEMContext::get_element_fe
    1100             :                    <typename TensorTools::MakeReal<OutputType>::type>,
    1101           0 :                    &DiffContext::get_elem_fixed_solution>(var, qp, u);
    1102           0 : }
    1103             : 
    1104             : 
    1105             : 
    1106           0 : Gradient FEMContext::fixed_interior_gradient(unsigned int var, unsigned int qp) const
    1107             : {
    1108           0 :   Gradient du;
    1109             : 
    1110           0 :   this->fixed_interior_gradient( var, qp, du );
    1111             : 
    1112           0 :   return du;
    1113             : }
    1114             : 
    1115             : 
    1116             : template<typename OutputType>
    1117           0 : void FEMContext::fixed_interior_gradient(unsigned int var, unsigned int qp,
    1118             :                                          OutputType & du) const
    1119             : {
    1120           0 :   this->some_gradient
    1121             :     <OutputType,
    1122             :      &FEMContext::get_element_fe
    1123             :      <typename TensorTools::MakeReal
    1124             :       <typename TensorTools::DecrementRank
    1125             :        <OutputType>::type>::type>,
    1126             :      &DiffContext::get_elem_fixed_solution>
    1127           0 :     (var, qp, du);
    1128           0 : }
    1129             : 
    1130             : 
    1131             : 
    1132             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1133           0 : Tensor FEMContext::fixed_interior_hessian(unsigned int var, unsigned int qp) const
    1134             : {
    1135           0 :   Tensor d2u;
    1136             : 
    1137           0 :   this->fixed_interior_hessian( var, qp, d2u );
    1138             : 
    1139           0 :   return d2u;
    1140             : }
    1141             : 
    1142             : 
    1143             : template<typename OutputType>
    1144           0 : void FEMContext::fixed_interior_hessian(unsigned int var, unsigned int qp,
    1145             :                                         OutputType & d2u) const
    1146             : {
    1147           0 :   this->some_hessian<OutputType,
    1148             :                      &FEMContext::get_element_fe
    1149             :                      <typename TensorTools::MakeReal
    1150             :                       <typename TensorTools::DecrementRank
    1151             :                        <typename TensorTools::DecrementRank
    1152             :                         <OutputType>::type>::type>::type>,
    1153           0 :                      &DiffContext::get_elem_fixed_solution>(var, qp, d2u);
    1154           0 : }
    1155             : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1156             : 
    1157             : 
    1158             : 
    1159           0 : Number FEMContext::fixed_side_value(unsigned int var, unsigned int qp) const
    1160             : {
    1161           0 :   Number u = 0.;
    1162             : 
    1163           0 :   this->fixed_side_value( var, qp, u );
    1164             : 
    1165           0 :   return u;
    1166             : }
    1167             : 
    1168             : 
    1169             : template<typename OutputType>
    1170           0 : void FEMContext::fixed_side_value(unsigned int var, unsigned int qp,
    1171             :                                   OutputType & u) const
    1172             : {
    1173           0 :   this->some_value
    1174             :     <OutputType,
    1175             :      &FEMContext::get_side_fe
    1176             :      <typename TensorTools::MakeReal<OutputType>::type>,
    1177             :      &DiffContext::get_elem_fixed_solution>
    1178           0 :     (var, qp, u);
    1179           0 : }
    1180             : 
    1181             : 
    1182             : 
    1183           0 : Gradient FEMContext::fixed_side_gradient(unsigned int var, unsigned int qp) const
    1184             : {
    1185           0 :   Gradient du;
    1186             : 
    1187           0 :   this->fixed_side_gradient( var, qp, du );
    1188             : 
    1189           0 :   return du;
    1190             : }
    1191             : 
    1192             : 
    1193             : template<typename OutputType>
    1194           0 : void FEMContext::fixed_side_gradient(unsigned int var, unsigned int qp,
    1195             :                                      OutputType & du) const
    1196             : {
    1197           0 :   this->some_gradient<OutputType,
    1198             :                       &FEMContext::get_side_fe
    1199             :                       <typename TensorTools::MakeReal
    1200             :                        <typename TensorTools::DecrementRank
    1201             :                         <OutputType>::type>::type>,
    1202           0 :                       &DiffContext::get_elem_fixed_solution>(var, qp, du);
    1203           0 : }
    1204             : 
    1205             : 
    1206             : 
    1207             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1208           0 : Tensor FEMContext::fixed_side_hessian(unsigned int var, unsigned int qp) const
    1209             : {
    1210           0 :   Tensor d2u;
    1211             : 
    1212           0 :   this->fixed_side_hessian( var, qp, d2u );
    1213             : 
    1214           0 :   return d2u;
    1215             : }
    1216             : 
    1217             : template<typename OutputType>
    1218           0 : void FEMContext::fixed_side_hessian(unsigned int var, unsigned int qp,
    1219             :                                     OutputType & d2u) const
    1220             : {
    1221           0 :   this->some_hessian<OutputType,
    1222             :                      &FEMContext::get_side_fe
    1223             :                      <typename TensorTools::MakeReal
    1224             :                       <typename TensorTools::DecrementRank
    1225             :                        <typename TensorTools::DecrementRank
    1226             :                         <OutputType>::type>::type>::type>,
    1227           0 :                      &DiffContext::get_elem_fixed_solution>(var, qp, d2u);
    1228           0 : }
    1229             : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1230             : 
    1231             : 
    1232             : 
    1233           0 : Number FEMContext::fixed_point_value(unsigned int var, const Point & p) const
    1234             : {
    1235           0 :   Number u = 0.;
    1236             : 
    1237           0 :   this->fixed_point_value( var, p, u );
    1238             : 
    1239           0 :   return u;
    1240             : }
    1241             : 
    1242             : template<typename OutputType>
    1243           0 : void FEMContext::fixed_point_value(unsigned int var,
    1244             :                                    const Point & p,
    1245             :                                    OutputType & u,
    1246             :                                    const Real tolerance) const
    1247             : {
    1248             :   typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
    1249             : 
    1250             :   // Get local-to-global dof index lookup
    1251             :   const unsigned int n_dofs = cast_int<unsigned int>
    1252           0 :     (this->get_dof_indices(var).size());
    1253             : 
    1254             :   // Get current local coefficients
    1255           0 :   libmesh_assert_greater (_elem_fixed_subsolutions.size(), var);
    1256           0 :   const DenseSubVector<Number> & coef = this->get_elem_fixed_solution(var);
    1257             : 
    1258             :   // Get finite element object
    1259           0 :   FEGenericBase<OutputShape> * fe = nullptr;
    1260           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
    1261             : 
    1262             :   // Build a FE for calculating u(p)
    1263           0 :   FEGenericBase<OutputShape> * fe_new =
    1264           0 :     this->build_new_fe( fe, p, tolerance, 0 );
    1265             : 
    1266             :   // Get the values of the shape function derivatives
    1267           0 :   const std::vector<std::vector<OutputShape>> &  phi = fe_new->get_phi();
    1268             : 
    1269           0 :   u = 0.;
    1270             : 
    1271           0 :   for (unsigned int l=0; l != n_dofs; l++)
    1272           0 :     u += phi[l][0] * coef(l);
    1273             : 
    1274           0 :   return;
    1275             : }
    1276             : 
    1277             : 
    1278             : 
    1279           0 : Gradient FEMContext::fixed_point_gradient(unsigned int var, const Point & p) const
    1280             : {
    1281           0 :   Gradient grad_u;
    1282             : 
    1283           0 :   this->fixed_point_gradient( var, p, grad_u );
    1284             : 
    1285           0 :   return grad_u;
    1286             : }
    1287             : 
    1288             : 
    1289             : 
    1290             : template<typename OutputType>
    1291           0 : void FEMContext::fixed_point_gradient(unsigned int var,
    1292             :                                       const Point & p,
    1293             :                                       OutputType & grad_u,
    1294             :                                       const Real tolerance) const
    1295             : {
    1296             :   typedef typename TensorTools::MakeReal
    1297             :     <typename TensorTools::DecrementRank<OutputType>::type>::type
    1298             :     OutputShape;
    1299             : 
    1300             :   // Get local-to-global dof index lookup
    1301             :   const unsigned int n_dofs = cast_int<unsigned int>
    1302           0 :     (this->get_dof_indices(var).size());
    1303             : 
    1304             :   // Get current local coefficients
    1305           0 :   libmesh_assert_greater (_elem_fixed_subsolutions.size(), var);
    1306           0 :   const DenseSubVector<Number> & coef = this->get_elem_fixed_solution(var);
    1307             : 
    1308             :   // Get finite element object
    1309           0 :   FEGenericBase<OutputShape> * fe = nullptr;
    1310           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
    1311             : 
    1312             :   // Build a FE for calculating u(p)
    1313           0 :   FEGenericBase<OutputShape> * fe_new =
    1314           0 :     this->build_new_fe( fe, p, tolerance, 1 );
    1315             : 
    1316             :   // Get the values of the shape function derivatives
    1317           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> &  dphi = fe_new->get_dphi();
    1318             : 
    1319           0 :   grad_u = 0.0;
    1320             : 
    1321           0 :   for (unsigned int l=0; l != n_dofs; l++)
    1322           0 :     grad_u.add_scaled(dphi[l][0], coef(l));
    1323             : 
    1324           0 :   return;
    1325             : }
    1326             : 
    1327             : 
    1328             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    1329             : 
    1330           0 : Tensor FEMContext::fixed_point_hessian(unsigned int var, const Point & p) const
    1331             : {
    1332           0 :   Tensor hess_u;
    1333             : 
    1334           0 :   this->fixed_point_hessian( var, p, hess_u );
    1335             : 
    1336           0 :   return hess_u;
    1337             : }
    1338             : 
    1339             : 
    1340             : 
    1341             : template<typename OutputType>
    1342           0 : void FEMContext::fixed_point_hessian(unsigned int var,
    1343             :                                      const Point & p,
    1344             :                                      OutputType & hess_u,
    1345             :                                      const Real tolerance) const
    1346             : {
    1347             :   typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
    1348             :   typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
    1349             :   typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
    1350             : 
    1351             :   // Get local-to-global dof index lookup
    1352             :   const unsigned int n_dofs = cast_int<unsigned int>
    1353           0 :     (this->get_dof_indices(var).size());
    1354             : 
    1355             :   // Get current local coefficients
    1356           0 :   libmesh_assert_greater (_elem_fixed_subsolutions.size(), var);
    1357           0 :   const DenseSubVector<Number> & coef = this->get_elem_fixed_solution(var);
    1358             : 
    1359             :   // Get finite element object
    1360           0 :   FEGenericBase<OutputShape> * fe = nullptr;
    1361           0 :   this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
    1362             : 
    1363             :   // Build a FE for calculating u(p)
    1364           0 :   FEGenericBase<OutputShape> * fe_new =
    1365           0 :     this->build_new_fe( fe, p, tolerance, 2 );
    1366             : 
    1367             :   // Get the values of the shape function derivatives
    1368           0 :   const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> &  d2phi = fe_new->get_d2phi();
    1369             : 
    1370           0 :   hess_u = 0.0;
    1371             : 
    1372           0 :   for (unsigned int l=0; l != n_dofs; l++)
    1373           0 :     hess_u.add_scaled(d2phi[l][0], coef(l));
    1374             : 
    1375           0 :   return;
    1376             : }
    1377             : 
    1378             : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
    1379             : 
    1380             : 
    1381             : 
    1382             : template<typename OutputType>
    1383   149658848 : void FEMContext::interior_rate(unsigned int var, unsigned int qp,
    1384             :                                OutputType & u) const
    1385             : {
    1386    26171416 :   this->some_value<OutputType,
    1387             :                    &FEMContext::get_element_fe
    1388             :                    <typename TensorTools::MakeReal<OutputType>::type>,
    1389   123487432 :                    &DiffContext::get_elem_solution_rate>(var, qp, u);
    1390   149658848 : }
    1391             : 
    1392             : template<typename OutputType>
    1393           0 : void FEMContext::interior_rate_gradient(unsigned int var, unsigned int qp,
    1394             :                                         OutputType & dudot) const
    1395             : {
    1396           0 :   this->some_gradient<OutputType,
    1397             :                       &FEMContext::get_element_fe<typename TensorTools::MakeReal
    1398             :                                                   <typename TensorTools::DecrementRank
    1399             :                                                    <OutputType>::type>::type>,
    1400           0 :                       &DiffContext::get_elem_solution_rate>(var, qp, dudot);
    1401           0 : }
    1402             : 
    1403             : template<typename OutputType>
    1404           0 : void FEMContext::side_rate(unsigned int var, unsigned int qp,
    1405             :                            OutputType & u) const
    1406             : {
    1407           0 :   this->some_value<OutputType,
    1408             :                    &FEMContext::get_side_fe
    1409             :                    <typename TensorTools::MakeReal<OutputType>::type>,
    1410           0 :                    &DiffContext::get_elem_solution_rate>(var, qp, u);
    1411           0 : }
    1412             : 
    1413             : template<typename OutputType>
    1414    39132624 : void FEMContext::interior_accel(unsigned int var, unsigned int qp,
    1415             :                                 OutputType & u) const
    1416             : {
    1417     6739544 :   this->some_value<OutputType,
    1418             :                    &FEMContext::get_element_fe
    1419             :                    <typename TensorTools::MakeReal<OutputType>::type>,
    1420    32393080 :                    &DiffContext::get_elem_solution_accel>(var, qp, u);
    1421    39132624 : }
    1422             : 
    1423             : 
    1424             : 
    1425             : template<typename OutputType>
    1426           0 : void FEMContext::side_accel(unsigned int var, unsigned int qp,
    1427             :                             OutputType & u) const
    1428             : {
    1429           0 :   this->some_value<OutputType,
    1430             :                    &FEMContext::get_side_fe
    1431             :                    <typename TensorTools::MakeReal<OutputType>::type>,
    1432           0 :                    &DiffContext::get_elem_solution_accel>(var, qp, u);
    1433           0 : }
    1434             : 
    1435             : 
    1436             : 
    1437    39070656 : void FEMContext::elem_reinit(Real theta)
    1438             : {
    1439             :   // Update the "time" variable of this context object
    1440    39070656 :   this->_update_time_from_system(theta);
    1441             : 
    1442             :   // Handle a moving element if necessary.
    1443    39070656 :   if (_mesh_sys)
    1444             :     {
    1445             :       // We assume that the ``default'' state
    1446             :       // of the mesh is its final, theta=1.0
    1447             :       // position, so we don't bother with
    1448             :       // mesh motion in that case.
    1449           0 :       if (theta != 1.0)
    1450             :         {
    1451             :           // FIXME - ALE is not threadsafe yet!
    1452           0 :           libmesh_assert_equal_to (libMesh::n_threads(), 1);
    1453             : 
    1454           0 :           elem_position_set(theta);
    1455             :         }
    1456           0 :       elem_fe_reinit();
    1457             :     }
    1458    39070656 : }
    1459             : 
    1460             : 
    1461     4215200 : void FEMContext::elem_side_reinit(Real theta)
    1462             : {
    1463             :   // Update the "time" variable of this context object
    1464     4215200 :   this->_update_time_from_system(theta);
    1465             : 
    1466             :   // Handle a moving element if necessary
    1467     4215200 :   if (_mesh_sys)
    1468             :     {
    1469             :       // FIXME - not threadsafe yet!
    1470           0 :       elem_position_set(theta);
    1471           0 :       side_fe_reinit();
    1472             :     }
    1473     4215200 : }
    1474             : 
    1475             : 
    1476           0 : void FEMContext::elem_edge_reinit(Real theta)
    1477             : {
    1478             :   // Update the "time" variable of this context object
    1479           0 :   this->_update_time_from_system(theta);
    1480             : 
    1481             :   // Handle a moving element if necessary
    1482           0 :   if (_mesh_sys)
    1483             :     {
    1484             :       // FIXME - not threadsafe yet!
    1485           0 :       elem_position_set(theta);
    1486           0 :       edge_fe_reinit();
    1487             :     }
    1488           0 : }
    1489             : 
    1490             : 
    1491           0 : void FEMContext::nonlocal_reinit(Real theta)
    1492             : {
    1493             :   // Update the "time" variable of this context object
    1494           0 :   this->_update_time_from_system(theta);
    1495             : 
    1496             :   // We can reuse the Elem FE safely here.
    1497           0 :   elem_fe_reinit();
    1498           0 : }
    1499             : 
    1500             : 
    1501    40161130 : void FEMContext::elem_fe_reinit(const std::vector<Point> * const pts)
    1502             : {
    1503             :   // Initialize all the interior FE objects on elem.
    1504             :   // Logging of FE::reinit is done in the FE functions
    1505             :   // We only reinit the FE objects for the current element
    1506             :   // dimension
    1507     3578136 :   const unsigned char dim = this->get_elem_dim();
    1508             : 
    1509     3578136 :   libmesh_assert( !_element_fe[dim].empty() );
    1510             : 
    1511    84724812 :   for (const auto & pr : _element_fe[dim])
    1512             :     {
    1513    44563682 :       if (this->has_elem())
    1514    44563682 :         pr.second->reinit(&(this->get_elem()), pts);
    1515             :         // If !this->has_elem(), then still might need to reinit for a
    1516             :         // SCALAR variable; everything else will depend on an elem
    1517           0 :       else if (pr.first.family == SCALAR)
    1518           0 :         pr.second->reinit(nullptr);
    1519             :     }
    1520    40161130 : }
    1521             : 
    1522             : 
    1523     9636531 : void FEMContext::side_fe_reinit ()
    1524             : {
    1525             :   // Initialize all the side FE objects on elem/side.
    1526             :   // Logging of FE::reinit is done in the FE functions
    1527             :   // We only reinit the FE objects for the current element
    1528             :   // dimension
    1529      987044 :   const unsigned char dim = this->get_elem_dim();
    1530             : 
    1531      987044 :   libmesh_assert( !_side_fe[dim].empty() );
    1532             : 
    1533    19804649 :   for (auto & pr : _side_fe[dim])
    1534    10168118 :     pr.second->reinit(&(this->get_elem()), this->get_side());
    1535     9636531 : }
    1536             : 
    1537             : 
    1538             : 
    1539      134166 : void FEMContext::edge_fe_reinit ()
    1540             : {
    1541        9690 :   libmesh_assert_equal_to (this->get_elem_dim(), 3);
    1542             : 
    1543             :   // Initialize all the interior FE objects on elem/edge.
    1544             :   // Logging of FE::reinit is done in the FE functions
    1545      306930 :   for (auto & pr : _edge_fe)
    1546      172764 :     pr.second->edge_reinit(&(this->get_elem()), this->get_edge());
    1547      134166 : }
    1548             : 
    1549             : 
    1550             : 
    1551         576 : void FEMContext::elem_position_get()
    1552             : {
    1553             :   // This is too expensive to call unless we've been asked to move the mesh
    1554           0 :   libmesh_assert (_mesh_sys);
    1555             : 
    1556             :   // This will probably break with threading when two contexts are
    1557             :   // operating on elements which share a node
    1558           0 :   libmesh_assert_equal_to (libMesh::n_threads(), 1);
    1559             : 
    1560             :   // If the coordinate data is in our own system, it's already
    1561             :   // been set up for us
    1562             :   //  if (_mesh_sys == this->number())
    1563             :   //    {
    1564         576 :   unsigned int n_nodes = this->get_elem().n_nodes();
    1565             : 
    1566             : #ifndef NDEBUG
    1567           0 :   const unsigned char dim = this->get_elem_dim();
    1568             : 
    1569             :   // For simplicity we demand that mesh coordinates be stored
    1570             :   // in a format that allows a direct copy
    1571           0 :   libmesh_assert(this->get_mesh_x_var() == libMesh::invalid_uint ||
    1572             :                  (this->get_element_fe(this->get_mesh_x_var(), dim)->get_fe_type().family
    1573             :                   == FEMap::map_fe_type(this->get_elem()) &&
    1574             :                   this->get_element_fe(this->get_mesh_x_var(), dim)->get_fe_type().order.get_order()
    1575             :                   == this->get_elem().default_order()));
    1576           0 :   libmesh_assert(this->get_mesh_y_var() == libMesh::invalid_uint ||
    1577             :                  (this->get_element_fe(this->get_mesh_y_var(), dim)->get_fe_type().family
    1578             :                   == FEMap::map_fe_type(this->get_elem()) &&
    1579             :                   this->get_element_fe(this->get_mesh_y_var(), dim)->get_fe_type().order.get_order()
    1580             :                   == this->get_elem().default_order()));
    1581           0 :   libmesh_assert(this->get_mesh_z_var() == libMesh::invalid_uint ||
    1582             :                  (this->get_element_fe(this->get_mesh_z_var(), dim)->get_fe_type().family
    1583             :                   == FEMap::map_fe_type(this->get_elem()) &&
    1584             :                   this->get_element_fe(this->get_mesh_z_var(), dim)->get_fe_type().order.get_order()
    1585             :                   == this->get_elem().default_order()));
    1586             : #endif
    1587             : 
    1588             :   // Get degree of freedom coefficients from point coordinates
    1589         576 :   if (this->get_mesh_x_var() != libMesh::invalid_uint)
    1590        5184 :     for (unsigned int i=0; i != n_nodes; ++i)
    1591        4608 :       (this->get_elem_solution(this->get_mesh_x_var()))(i) = this->get_elem().point(i)(0);
    1592             : 
    1593         576 :   if (this->get_mesh_y_var() != libMesh::invalid_uint)
    1594        5184 :     for (unsigned int i=0; i != n_nodes; ++i)
    1595        4608 :       (this->get_elem_solution(this->get_mesh_y_var()))(i) = this->get_elem().point(i)(1);
    1596             : 
    1597         576 :   if (this->get_mesh_z_var() != libMesh::invalid_uint)
    1598        5184 :     for (unsigned int i=0; i != n_nodes; ++i)
    1599        4608 :       (this->get_elem_solution(this->get_mesh_z_var()))(i) = this->get_elem().point(i)(2);
    1600             :   //    }
    1601             :   // FIXME - If the coordinate data is not in our own system, someone
    1602             :   // had better get around to implementing that... - RHS
    1603             :   //  else
    1604             :   //    {
    1605             :   //      libmesh_not_implemented();
    1606             :   //    }
    1607         576 : }
    1608             : 
    1609             : 
    1610             : 
    1611           0 : void FEMContext::set_jacobian_tolerance(Real tol)
    1612             : {
    1613           0 :   for (auto & m : _element_fe)
    1614           0 :     for (auto & pr : m)
    1615           0 :       pr.second->get_fe_map().set_jacobian_tolerance(tol);
    1616             : 
    1617           0 :   for (auto & m : _side_fe)
    1618           0 :     for (auto & pr : m)
    1619           0 :       pr.second->get_fe_map().set_jacobian_tolerance(tol);
    1620             : 
    1621           0 :   for (auto & pr : _edge_fe)
    1622           0 :     pr.second->get_fe_map().set_jacobian_tolerance(tol);
    1623           0 : }
    1624             : 
    1625             : 
    1626             : 
    1627             : // We can ignore the theta argument in the current use of this
    1628             : // function, because elem_subsolutions will already have been set to
    1629             : // the theta value.
    1630             : //
    1631             : // To enable loose mesh movement coupling things will need to change.
    1632       23040 : void FEMContext::_do_elem_position_set(Real)
    1633             : {
    1634             :   // This is too expensive to call unless we've been asked to move the mesh
    1635           0 :   libmesh_assert (_mesh_sys);
    1636             : 
    1637             :   // This will probably break with threading when two contexts are
    1638             :   // operating on elements which share a node
    1639           0 :   libmesh_assert_equal_to (libMesh::n_threads(), 1);
    1640             : 
    1641             :   // If the coordinate data is in our own system, it's already
    1642             :   // been set up for us, and we can ignore our input parameter theta
    1643             :   //  if (_mesh_sys == this->number())
    1644             :   //    {
    1645       23040 :   unsigned int n_nodes = this->get_elem().n_nodes();
    1646             : 
    1647             : #ifndef NDEBUG
    1648           0 :   const unsigned char dim = this->get_elem_dim();
    1649             : 
    1650             :   // For simplicity we demand that mesh coordinates be stored
    1651             :   // in a format that allows a direct copy
    1652           0 :   libmesh_assert(this->get_mesh_x_var() == libMesh::invalid_uint ||
    1653             :                  (this->get_element_fe(this->get_mesh_x_var(), dim)->get_fe_type().family
    1654             :                   == FEMap::map_fe_type(this->get_elem()) &&
    1655             :                   this->get_elem_solution(this->get_mesh_x_var()).size() == n_nodes));
    1656           0 :   libmesh_assert(this->get_mesh_y_var() == libMesh::invalid_uint ||
    1657             :                  (this->get_element_fe(this->get_mesh_y_var(), dim)->get_fe_type().family
    1658             :                   == FEMap::map_fe_type(this->get_elem()) &&
    1659             :                   this->get_elem_solution(this->get_mesh_y_var()).size() == n_nodes));
    1660           0 :   libmesh_assert(this->get_mesh_z_var() == libMesh::invalid_uint ||
    1661             :                  (this->get_element_fe(this->get_mesh_z_var(), dim)->get_fe_type().family
    1662             :                   == FEMap::map_fe_type(this->get_elem()) &&
    1663             :                   this->get_elem_solution(this->get_mesh_z_var()).size() == n_nodes));
    1664             : #endif
    1665             : 
    1666             :   // Set the new point coordinates
    1667       23040 :   if (this->get_mesh_x_var() != libMesh::invalid_uint)
    1668      207360 :     for (unsigned int i=0; i != n_nodes; ++i)
    1669      184320 :       const_cast<Elem &>(this->get_elem()).point(i)(0) =
    1670      163840 :         libmesh_real(this->get_elem_solution(this->get_mesh_x_var())(i));
    1671             : 
    1672       23040 :   if (this->get_mesh_y_var() != libMesh::invalid_uint)
    1673      207360 :     for (unsigned int i=0; i != n_nodes; ++i)
    1674      184320 :       const_cast<Elem &>(this->get_elem()).point(i)(1) =
    1675      163840 :         libmesh_real(this->get_elem_solution(this->get_mesh_y_var())(i));
    1676             : 
    1677       23040 :   if (this->get_mesh_z_var() != libMesh::invalid_uint)
    1678      207360 :     for (unsigned int i=0; i != n_nodes; ++i)
    1679      184320 :       const_cast<Elem &>(this->get_elem()).point(i)(2) =
    1680      163840 :         libmesh_real(this->get_elem_solution(this->get_mesh_z_var())(i));
    1681             :   //    }
    1682             :   // FIXME - If the coordinate data is not in our own system, someone
    1683             :   // had better get around to implementing that... - RHS
    1684             :   //  else
    1685             :   //    {
    1686             :   //      libmesh_not_implemented();
    1687             :   //    }
    1688       23040 : }
    1689             : 
    1690             : 
    1691             : 
    1692             : 
    1693             : 
    1694             : /*
    1695             :   void FEMContext::reinit(const FEMSystem & sys, Elem * e)
    1696             :   {
    1697             :   // Initialize our elem pointer, algebraic objects
    1698             :   this->pre_fe_reinit(e);
    1699             : 
    1700             :   // Moving the mesh may be necessary
    1701             :   // Reinitializing the FE objects is definitely necessary
    1702             :   this->elem_reinit(1.);
    1703             :   }
    1704             : */
    1705             : 
    1706             : 
    1707             : 
    1708    52873736 : void FEMContext::pre_fe_reinit(const System & sys, const Elem * e)
    1709             : {
    1710    52873736 :   this->set_elem(e);
    1711             : 
    1712    53551314 :   if (algebraic_type() == CURRENT ||
    1713      677578 :       algebraic_type() == DOFS_ONLY)
    1714             :     {
    1715             :       // Initialize the per-element data for elem.
    1716    49500011 :       if (this->has_elem())
    1717    49500011 :         sys.get_dof_map().dof_indices (&(this->get_elem()), this->get_dof_indices());
    1718             :       else
    1719             :         // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
    1720           0 :         sys.get_dof_map().dof_indices
    1721           0 :           (static_cast<Elem*>(nullptr), this->get_dof_indices());
    1722             :     }
    1723             : #ifdef LIBMESH_ENABLE_AMR
    1724     3379173 :   else if (algebraic_type() == OLD ||
    1725        5448 :            algebraic_type() == OLD_DOFS_ONLY)
    1726             :     {
    1727             :       // Initialize the per-element data for elem.
    1728     3373725 :       if (this->has_elem())
    1729     3373725 :         sys.get_dof_map().old_dof_indices (&(this->get_elem()), this->get_dof_indices());
    1730             :       else
    1731             :         // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
    1732           0 :         sys.get_dof_map().old_dof_indices
    1733           0 :           (static_cast<Elem*>(nullptr), this->get_dof_indices());
    1734             :     }
    1735             : #endif // LIBMESH_ENABLE_AMR
    1736             : 
    1737             :   const unsigned int n_dofs = cast_int<unsigned int>
    1738     9458216 :     (this->get_dof_indices().size());
    1739     4729159 :   const unsigned int n_qoi = sys.n_qois();
    1740             : 
    1741    57602895 :   if (this->algebraic_type() != NONE &&
    1742   101470404 :       this->algebraic_type() != DOFS_ONLY &&
    1743     4338822 :       this->algebraic_type() != OLD_DOFS_ONLY)
    1744             :     {
    1745             :       // This also resizes elem_solution
    1746    48143148 :       if (_custom_solution == nullptr)
    1747    44832606 :         sys.current_local_solution->get(this->get_dof_indices(), this->get_elem_solution().get_values());
    1748             :       else
    1749     3310542 :         _custom_solution->get(this->get_dof_indices(), this->get_elem_solution().get_values());
    1750             : 
    1751    48143148 :       if (sys.use_fixed_solution)
    1752           0 :         this->get_elem_fixed_solution().resize(n_dofs);
    1753             : 
    1754             :       // Only make space for these if we're using DiffSystem
    1755             :       // This is assuming *only* DiffSystem is using elem_solution_rate/accel
    1756    48143148 :       const DifferentiableSystem * diff_system = dynamic_cast<const DifferentiableSystem *>(&sys);
    1757    48143148 :       if (diff_system)
    1758             :         {
    1759             :           // Now, we only need these if the solver is unsteady
    1760    40503949 :           if (!diff_system->get_time_solver().is_steady())
    1761             :             {
    1762    32254728 :               this->get_elem_solution_rate().resize(n_dofs);
    1763             : 
    1764             :               // We only need accel space if the TimeSolver is second order
    1765     3201982 :               const UnsteadySolver & time_solver = cast_ref<const UnsteadySolver &>(diff_system->get_time_solver());
    1766             : 
    1767    35456714 :               if (time_solver.time_order() >= 2 || !diff_system->get_second_order_vars().empty())
    1768      829704 :                 this->get_elem_solution_accel().resize(n_dofs);
    1769             :             }
    1770             :         }
    1771             : 
    1772    48143148 :       if (algebraic_type() != OLD)
    1773             :         {
    1774             :           // These resize calls also zero out the residual and jacobian
    1775    40781025 :           this->get_elem_residual().resize(n_dofs);
    1776    44832606 :           if (this->_have_local_matrices)
    1777    36272517 :             this->get_elem_jacobian().resize(n_dofs, n_dofs);
    1778             : 
    1779    44832606 :           this->get_qoi_derivatives().resize(n_qoi);
    1780    44832606 :           this->_elem_qoi_subderivatives.resize(n_qoi);
    1781    78959154 :           for (std::size_t q=0; q != n_qoi; ++q)
    1782    34126548 :             (this->get_qoi_derivatives())[q].resize(n_dofs);
    1783             :         }
    1784             :     }
    1785             : 
    1786             :   // Initialize the per-variable data for elem.
    1787             :   {
    1788     4729159 :     unsigned int sub_dofs = 0;
    1789   118239999 :     for (auto i : make_range(sys.n_vars()))
    1790             :       {
    1791    66099981 :         if (algebraic_type() == CURRENT ||
    1792      733718 :             algebraic_type() == DOFS_ONLY)
    1793             :           {
    1794    61774377 :             if (this->has_elem())
    1795    67249785 :               sys.get_dof_map().dof_indices (&(this->get_elem()), this->get_dof_indices(i), i);
    1796             :             else
    1797             :               // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
    1798           0 :               sys.get_dof_map().dof_indices
    1799           0 :                 (static_cast<Elem*>(nullptr), this->get_dof_indices(i), i);
    1800             :           }
    1801             : #ifdef LIBMESH_ENABLE_AMR
    1802     3608136 :         else if (algebraic_type() == OLD ||
    1803       16250 :                  algebraic_type() == OLD_DOFS_ONLY)
    1804             :           {
    1805     3591886 :             if (this->has_elem())
    1806     3591886 :               sys.get_dof_map().old_dof_indices (&(this->get_elem()), this->get_dof_indices(i), i);
    1807             :             else
    1808             :               // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
    1809           0 :               sys.get_dof_map().old_dof_indices
    1810           0 :                 (static_cast<Elem*>(nullptr), this->get_dof_indices(i), i);
    1811             :           }
    1812             : #endif // LIBMESH_ENABLE_AMR
    1813             : 
    1814    71147384 :         if (this->algebraic_type() != NONE &&
    1815   126034721 :             this->algebraic_type() != DOFS_ONLY &&
    1816     5353116 :             this->algebraic_type() != OLD_DOFS_ONLY)
    1817             :           {
    1818             :             const unsigned int n_dofs_var = cast_int<unsigned int>
    1819    16010026 :               (this->get_dof_indices(i).size());
    1820             : 
    1821             : 
    1822    60906398 :             if (!_active_vars ||
    1823     5092163 :                 std::binary_search(_active_vars->begin(),
    1824             :                                    _active_vars->end(), i))
    1825             :               {
    1826    16010535 :                 this->get_elem_solution(i).reposition
    1827     5336845 :                   (sub_dofs, n_dofs_var);
    1828             : 
    1829             :                 // Only make space for these if we're using DiffSystem
    1830             :                 // This is assuming *only* DiffSystem is using elem_solution_rate/accel
    1831    60051752 :                 const DifferentiableSystem * diff_system = dynamic_cast<const DifferentiableSystem *>(&sys);
    1832    60051752 :                 if (diff_system)
    1833             :                   {
    1834             :                     // Now, we only need these if the solver is unsteady
    1835    49994989 :                     if (!diff_system->get_time_solver().is_steady())
    1836             :                       {
    1837    11536434 :                         this->get_elem_solution_rate(i).reposition
    1838     3845478 :                           (sub_dofs, n_dofs_var);
    1839             : 
    1840             :                         // We only need accel space if the TimeSolver is second order
    1841     3845478 :                         const UnsteadySolver & time_solver = cast_ref<const UnsteadySolver &>(diff_system->get_time_solver());
    1842             : 
    1843    42982426 :                         if (time_solver.time_order() >= 2 || !diff_system->get_second_order_vars().empty())
    1844     1108752 :                           this->get_elem_solution_accel(i).reposition
    1845      369584 :                             (sub_dofs, n_dofs_var);
    1846             :                       }
    1847             :                   }
    1848             : 
    1849    60051752 :                 if (sys.use_fixed_solution)
    1850           0 :                   this->get_elem_fixed_solution(i).reposition
    1851           0 :                     (sub_dofs, n_dofs_var);
    1852             : 
    1853    60051752 :                 if (algebraic_type() != OLD)
    1854             :                   {
    1855    15142194 :                     this->get_elem_residual(i).reposition
    1856     5047398 :                       (sub_dofs, n_dofs_var);
    1857             : 
    1858    90872699 :                     for (std::size_t q=0; q != n_qoi; ++q)
    1859     9318924 :                       this->get_qoi_derivatives(q,i).reposition
    1860     3106308 :                         (sub_dofs, n_dofs_var);
    1861             : 
    1862    56648507 :                     if (this->_have_local_matrices)
    1863             :                       {
    1864    72452874 :                         for (unsigned int j=0; j != i; ++j)
    1865             :                           {
    1866             :                             const unsigned int n_dofs_var_j =
    1867             :                               cast_int<unsigned int>
    1868     3553132 :                               (this->get_dof_indices(j).size());
    1869             : 
    1870     5329698 :                             this->get_elem_jacobian(i,j).reposition
    1871     3553132 :                               (sub_dofs, this->get_elem_residual(j).i_off(),
    1872             :                                n_dofs_var, n_dofs_var_j);
    1873     5329698 :                             this->get_elem_jacobian(j,i).reposition
    1874     3553132 :                               (this->get_elem_residual(j).i_off(), sub_dofs,
    1875             :                                n_dofs_var_j, n_dofs_var);
    1876             :                           }
    1877    13605729 :                         this->get_elem_jacobian(i,i).reposition
    1878     4535243 :                           (sub_dofs, sub_dofs,
    1879             :                            n_dofs_var,
    1880             :                            n_dofs_var);
    1881             :                       }
    1882             :                   }
    1883             :               }
    1884             : 
    1885    60052004 :             sub_dofs += n_dofs_var;
    1886             :           }
    1887             :       }
    1888             : 
    1889    14187375 :     if (this->algebraic_type() != NONE &&
    1890     9067981 :         this->algebraic_type() != DOFS_ONLY &&
    1891    13797140 :         this->algebraic_type() != OLD &&
    1892     4057029 :         this->algebraic_type() != OLD_DOFS_ONLY)
    1893     4051581 :       libmesh_assert_equal_to (sub_dofs, n_dofs);
    1894             :   }
    1895             : 
    1896             :   // Now do the localization for the user requested vectors
    1897    57602895 :   if (this->algebraic_type() != NONE &&
    1898   101470404 :       this->algebraic_type() != DOFS_ONLY &&
    1899     4338822 :       this->algebraic_type() != OLD_DOFS_ONLY)
    1900             :     {
    1901     4333374 :       DiffContext::localized_vectors_iterator localized_vec_it = this->_localized_vectors.begin();
    1902     4333374 :       const DiffContext::localized_vectors_iterator localized_vec_end = this->_localized_vectors.end();
    1903             : 
    1904    74177772 :       for (; localized_vec_it != localized_vec_end; ++localized_vec_it)
    1905             :         {
    1906    26034624 :           const NumericVector<Number> & current_localized_vector = *localized_vec_it->first;
    1907     2366784 :           DenseVector<Number> & target_vector = localized_vec_it->second.first;
    1908             : 
    1909    26034624 :           current_localized_vector.get(this->get_dof_indices(), target_vector.get_values());
    1910             : 
    1911             :           // Initialize the per-variable data for elem.
    1912    26034624 :           unsigned int sub_dofs = 0;
    1913    30768192 :           auto init_localized_var_data = [this, localized_vec_it, &sub_dofs](unsigned int i)
    1914             :             {
    1915             :               const unsigned int n_dofs_var = cast_int<unsigned int>
    1916     4733568 :                 (this->get_dof_indices(i).size());
    1917             : 
    1918             :               // This is redundant with earlier initialization, isn't it? - RHS
    1919             :               // sys.get_dof_map().dof_indices (&(this->get_elem()), this->get_dof_indices(i), i);
    1920             : 
    1921     4733568 :               localized_vec_it->second.second[i].reposition
    1922    26034624 :                 (sub_dofs, n_dofs_var);
    1923             : 
    1924    28401408 :               sub_dofs += n_dofs_var;
    1925    26034624 :             };
    1926             : 
    1927    26034624 :           if (_active_vars)
    1928           0 :             for (auto v : *_active_vars)
    1929           0 :               init_localized_var_data(v);
    1930             :           else
    1931    52069248 :             for (auto v : make_range(sys.n_vars()))
    1932    23667840 :               init_localized_var_data(v);
    1933             : 
    1934     2366784 :           libmesh_assert_equal_to (sub_dofs, n_dofs);
    1935             :         }
    1936             :     }
    1937    52873736 : }
    1938             : 
    1939    52873736 : void FEMContext::set_elem( const Elem * e )
    1940             : {
    1941    52873736 :   this->_elem = e;
    1942             : 
    1943             :   // If e is nullptr, we assume it's SCALAR and set _elem_dim to 0.
    1944    52873736 :   this->_elem_dim =
    1945    52873736 :     cast_int<unsigned char>(this->_elem ? this->_elem->dim() : 0);
    1946    52873736 : }
    1947             : 
    1948    43285856 : void FEMContext::_update_time_from_system(Real theta)
    1949             : {
    1950             :   // Update the "time" variable based on the value of theta.  For this
    1951             :   // to work, we need to know the value of deltat, a pointer to which is now
    1952             :   // stored by our parent DiffContext class.  Note: get_deltat_value() will
    1953             :   // assert in debug mode if the requested pointer is nullptr.
    1954    43285856 :   const Real deltat = this->get_deltat_value();
    1955             : 
    1956    43285856 :   this->set_time(theta*(this->get_system_time() + deltat) + (1.-theta)*this->get_system_time());
    1957    43285856 : }
    1958             : 
    1959             : 
    1960             : 
    1961             : template<>
    1962             : FEGenericBase<Real> *
    1963     8157554 : FEMContext::cached_fe( const unsigned int elem_dim,
    1964             :                        const FEType fe_type,
    1965             :                        const int get_derivative_level ) const
    1966             : {
    1967             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    1968             :   const bool fe_needs_inf =
    1969     1688516 :     this->has_elem() && this->get_elem().infinite();
    1970             : #endif
    1971             : 
    1972     8769530 :   if (!_real_fe ||
    1973     2364365 :       elem_dim != _real_fe->get_dim() ||
    1974    10212677 :       fe_type != _real_fe->get_fe_type() ||
    1975     8064071 :       get_derivative_level != _real_fe_derivative_level)
    1976             :     {
    1977       93509 :       _real_fe_derivative_level = get_derivative_level;
    1978             : 
    1979             :       _real_fe =
    1980             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    1981       25838 :         fe_needs_inf ?
    1982             :         FEGenericBase<Real>::build_InfFE(elem_dim, fe_type) :
    1983             : #endif
    1984      166359 :         FEGenericBase<Real>::build(elem_dim, fe_type);
    1985             :     }
    1986             : 
    1987             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    1988     1675597 :   else if (fe_needs_inf && !_real_fe_is_inf)
    1989         378 :     _real_fe =
    1990         630 :       FEGenericBase<Real>::build_InfFE(elem_dim, fe_type);
    1991     1675053 :   else if (!fe_needs_inf && _real_fe_is_inf)
    1992             :     _real_fe =
    1993         638 :       FEGenericBase<Real>::build(elem_dim, fe_type);
    1994             : 
    1995     1688516 :   _real_fe_is_inf =
    1996     1688516 :     (this->has_elem() && this->get_elem().infinite());
    1997             : #endif
    1998             : 
    1999     8157554 :   return _real_fe.get();
    2000             : }
    2001             : 
    2002             : 
    2003             : template<>
    2004             : FEGenericBase<RealGradient> *
    2005       64602 : FEMContext::cached_fe( const unsigned int elem_dim,
    2006             :                        const FEType fe_type,
    2007             :                        const int get_derivative_level ) const
    2008             : {
    2009             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    2010             :   const bool fe_needs_inf =
    2011       13227 :     this->has_elem() && this->get_elem().infinite();
    2012             : #endif
    2013             : 
    2014       66168 :   if (!_real_grad_fe ||
    2015       17421 :       elem_dim != _real_grad_fe->get_dim() ||
    2016       78039 :       fe_type != _real_grad_fe->get_fe_type() ||
    2017       61575 :       get_derivative_level != _real_grad_fe_derivative_level)
    2018             :     {
    2019        3027 :       _real_grad_fe_derivative_level = get_derivative_level;
    2020             : 
    2021             :       _real_grad_fe =
    2022             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    2023         570 :         fe_needs_inf ?
    2024             :         FEGenericBase<RealGradient>::build_InfFE(elem_dim, fe_type) :
    2025             : #endif
    2026        5598 :         FEGenericBase<RealGradient>::build(elem_dim, fe_type);
    2027             :     }
    2028             : 
    2029             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    2030       12942 :   else if (fe_needs_inf && !_real_grad_fe_is_inf)
    2031           0 :     _real_grad_fe =
    2032           0 :       FEGenericBase<RealGradient>::build_InfFE(elem_dim, fe_type);
    2033       12942 :   else if (!fe_needs_inf && _real_grad_fe_is_inf)
    2034             :     _real_grad_fe =
    2035           0 :       FEGenericBase<RealGradient>::build(elem_dim, fe_type);
    2036             : 
    2037       13227 :   _real_grad_fe_is_inf =
    2038       13227 :     (this->has_elem() && this->get_elem().infinite());
    2039             : #endif
    2040             : 
    2041       64602 :   return _real_grad_fe.get();
    2042             : }
    2043             : 
    2044             : 
    2045             : 
    2046             : template<typename OutputShape>
    2047             : FEGenericBase<OutputShape> *
    2048     8222156 : FEMContext::build_new_fe( const FEGenericBase<OutputShape>* fe,
    2049             :                           const Point & p,
    2050             :                           const Real tolerance,
    2051             :                           const int get_derivative_level) const
    2052             : {
    2053     7213976 :   FEType fe_type = fe->get_fe_type();
    2054             : 
    2055             :   // If we don't have an Elem to evaluate on, then the only functions
    2056             :   // we can sensibly evaluate are the scalar dofs which are the same
    2057             :   // everywhere.
    2058      693563 :   libmesh_assert(this->has_elem() || fe_type.family == SCALAR);
    2059             : 
    2060             : #ifdef LIBMESH_ENABLE_AMR
    2061     8222156 :   const int add_p_level = fe->add_p_level_in_reinit();
    2062     8893377 :   if ((algebraic_type() == OLD) &&
    2063     1342442 :       this->has_elem())
    2064             :     {
    2065     8637724 :       if (this->get_elem().p_refinement_flag() == Elem::JUST_REFINED)
    2066       25465 :         fe_type.order -= add_p_level;
    2067     7660339 :       else if (this->get_elem().p_refinement_flag() == Elem::JUST_COARSENED)
    2068         152 :         fe_type.order += add_p_level;
    2069             :     }
    2070             : #endif // LIBMESH_ENABLE_AMR
    2071             : 
    2072     8222156 :   const unsigned int elem_dim = this->has_elem() ? this->get_elem().dim() : 0;
    2073             : 
    2074     1387126 :   FEGenericBase<OutputShape>* fe_new =
    2075     6835030 :     cached_fe<OutputShape>(elem_dim, fe_type, get_derivative_level);
    2076             : #ifdef LIBMESH_ENABLE_AMR
    2077      693563 :   fe_new->add_p_level_in_reinit(add_p_level);
    2078             : #endif // LIBMESH_ENABLE_AMR
    2079             : 
    2080             :   // Map the physical co-ordinates to the master co-ordinates using the inverse_map from fe_interface.h
    2081             :   // Build a vector of point co-ordinates to send to reinit
    2082     8222156 :   Point master_point = this->has_elem() ?
    2083     8222156 :     FEMap::inverse_map (elem_dim, &this->get_elem(), p, tolerance) :
    2084             :     Point(0);
    2085             : 
    2086     8222156 :   std::vector<Point> coor(1, master_point);
    2087             : 
    2088     8222156 :   switch (get_derivative_level)
    2089             :     {
    2090       10352 :     case -1:
    2091       10352 :       fe_new->get_phi();
    2092       10352 :       fe_new->get_dphi();
    2093             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2094       10352 :       fe_new->get_d2phi();
    2095             : #endif
    2096       20704 :       fe_new->get_curl_phi();
    2097       10352 :       break;
    2098      662912 :     case 0:
    2099      662912 :       fe_new->get_phi();
    2100      662912 :       break;
    2101       20296 :     case 1:
    2102       20296 :       fe_new->get_dphi();
    2103       20296 :       break;
    2104           3 :     case 2:
    2105             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2106           3 :       fe_new->get_d2phi();
    2107             : #else
    2108             :       // here a different configuration is required.
    2109             :       libmesh_not_implemented();
    2110             : #endif
    2111           3 :       break;
    2112           0 :     case 3:
    2113           0 :       fe_new->get_curl_phi();
    2114           0 :       break;
    2115           0 :     default:
    2116           0 :       libmesh_error();
    2117             :     }
    2118             : 
    2119             :   // Reinitialize the element and compute the shape function values at coor
    2120     8222156 :   if (this->has_elem())
    2121     8222156 :     fe_new->reinit (&this->get_elem(), &coor);
    2122             :   else
    2123             :     // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
    2124           0 :     fe_new->reinit (nullptr, &coor);
    2125             : 
    2126     8915719 :   return fe_new;
    2127             : }
    2128             : 
    2129             : 
    2130             : 
    2131             : 
    2132             : 
    2133             : // Instantiate member function templates
    2134             : template LIBMESH_EXPORT void FEMContext::interior_value<Number>(unsigned int, unsigned int, Number &) const;
    2135             : template LIBMESH_EXPORT void FEMContext::interior_values<Number>(unsigned int, const NumericVector<Number> &,
    2136             :                                                   std::vector<Number> &) const;
    2137             : template LIBMESH_EXPORT void FEMContext::interior_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2138             : template LIBMESH_EXPORT void FEMContext::interior_values<Gradient>(unsigned int, const NumericVector<Number> &,
    2139             :                                                     std::vector<Gradient> &) const;
    2140             : 
    2141             : template LIBMESH_EXPORT void FEMContext::interior_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2142             : template LIBMESH_EXPORT void FEMContext::interior_gradients<Gradient>(unsigned int, const NumericVector<Number> &,
    2143             :                                                        std::vector<Gradient> &) const;
    2144             : template LIBMESH_EXPORT void FEMContext::interior_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2145             : template LIBMESH_EXPORT void FEMContext::interior_gradients<Tensor>(unsigned int, const NumericVector<Number> &,
    2146             :                                                      std::vector<Tensor> &) const;
    2147             : 
    2148             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2149             : template LIBMESH_EXPORT void FEMContext::interior_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2150             : template LIBMESH_EXPORT void FEMContext::interior_hessians<Tensor>(unsigned int, const NumericVector<Number> &,
    2151             :                                                     std::vector<Tensor> &) const;
    2152             : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
    2153             : //template LIBMESH_EXPORT void FEMContext::interior_hessian<??>(unsigned int, unsigned int, ??&) const;
    2154             : //template LIBMESH_EXPORT void FEMContext::interior_hessians<??>(unsigned int, const NumericVector<Number> &,
    2155             : //                                                std::vector<??> &) const;
    2156             : #endif
    2157             : 
    2158             : template LIBMESH_EXPORT void FEMContext::interior_curl<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2159             : 
    2160             : template LIBMESH_EXPORT void FEMContext::interior_div<Number>(unsigned int, unsigned int, Number &) const;
    2161             : 
    2162             : template LIBMESH_EXPORT void FEMContext::side_value<Number>(unsigned int, unsigned int, Number &) const;
    2163             : template LIBMESH_EXPORT void FEMContext::side_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2164             : template LIBMESH_EXPORT void FEMContext::side_values<Number>(unsigned int, const NumericVector<Number> &,
    2165             :                                               std::vector<Number> &) const;
    2166             : template LIBMESH_EXPORT void FEMContext::side_values<Gradient>(unsigned int, const NumericVector<Number> &,
    2167             :                                                 std::vector<Gradient> &) const;
    2168             : 
    2169             : template LIBMESH_EXPORT void FEMContext::side_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2170             : template LIBMESH_EXPORT void FEMContext::side_gradients<Gradient>(unsigned int, const NumericVector<Number> &,
    2171             :                                                    std::vector<Gradient> &) const;
    2172             : template LIBMESH_EXPORT void FEMContext::side_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2173             : template LIBMESH_EXPORT void FEMContext::side_gradients<Tensor>(unsigned int, const NumericVector<Number> &,
    2174             :                                                  std::vector<Tensor> &) const;
    2175             : 
    2176             : 
    2177             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2178             : template LIBMESH_EXPORT void FEMContext::side_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2179             : template LIBMESH_EXPORT void FEMContext::side_hessians<Tensor>(unsigned int, const NumericVector<Number> &,
    2180             :                                                 std::vector<Tensor> &) const;
    2181             : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
    2182             : //template LIBMESH_EXPORT void FEMContext::side_hessian<??>(unsigned int, unsigned int,
    2183             : //                                           ??&) const;
    2184             : //template LIBMESH_EXPORT void FEMContext::side_hessians<??>(unsigned int, const NumericVector<Number> &,
    2185             : //                                            std::vector<??> &) const;
    2186             : #endif
    2187             : 
    2188             : template LIBMESH_EXPORT void FEMContext::point_value<Number>(unsigned int, const Point &, Number &, const Real) const;
    2189             : template LIBMESH_EXPORT void FEMContext::point_value<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
    2190             : 
    2191             : template LIBMESH_EXPORT void FEMContext::point_gradient<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
    2192             : template LIBMESH_EXPORT void FEMContext::point_gradient<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
    2193             : 
    2194             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2195             : template LIBMESH_EXPORT void FEMContext::point_hessian<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
    2196             : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
    2197             : //template LIBMESH_EXPORT void FEMContext::point_hessian<??>(unsigned int, const Point &, ??&) const;
    2198             : #endif
    2199             : 
    2200             : template LIBMESH_EXPORT void FEMContext::point_curl<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
    2201             : 
    2202             : template LIBMESH_EXPORT void FEMContext::fixed_interior_value<Number>(unsigned int, unsigned int, Number &) const;
    2203             : template LIBMESH_EXPORT void FEMContext::fixed_interior_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2204             : 
    2205             : template LIBMESH_EXPORT void FEMContext::fixed_interior_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2206             : template LIBMESH_EXPORT void FEMContext::fixed_interior_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2207             : 
    2208             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2209             : template LIBMESH_EXPORT void FEMContext::fixed_interior_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2210             : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
    2211             : //template LIBMESH_EXPORT void FEMContext::fixed_interior_hessian<??>(unsigned int, unsigned int, ??&) const;
    2212             : #endif
    2213             : 
    2214             : template LIBMESH_EXPORT void FEMContext::fixed_side_value<Number>(unsigned int, unsigned int, Number &) const;
    2215             : template LIBMESH_EXPORT void FEMContext::fixed_side_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2216             : 
    2217             : template LIBMESH_EXPORT void FEMContext::fixed_side_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2218             : template LIBMESH_EXPORT void FEMContext::fixed_side_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2219             : 
    2220             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2221             : template LIBMESH_EXPORT void FEMContext::fixed_side_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2222             : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
    2223             : //template LIBMESH_EXPORT void FEMContext::fixed_side_hessian<??>(unsigned int, unsigned int, ??&) const;
    2224             : #endif
    2225             : 
    2226             : template LIBMESH_EXPORT void FEMContext::fixed_point_value<Number>(unsigned int, const Point &, Number &, const Real) const;
    2227             : template LIBMESH_EXPORT void FEMContext::fixed_point_value<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
    2228             : 
    2229             : template LIBMESH_EXPORT void FEMContext::fixed_point_gradient<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
    2230             : template LIBMESH_EXPORT void FEMContext::fixed_point_gradient<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
    2231             : 
    2232             : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
    2233             : template LIBMESH_EXPORT void FEMContext::fixed_point_hessian<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
    2234             : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
    2235             : //template LIBMESH_EXPORT void FEMContext::fixed_point_hessian<??>(unsigned int, const Point &, ??&) const;
    2236             : #endif
    2237             : 
    2238             : template LIBMESH_EXPORT void FEMContext::interior_rate<Number>(unsigned int, unsigned int, Number &) const;
    2239             : template LIBMESH_EXPORT void FEMContext::interior_rate<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2240             : 
    2241             : template LIBMESH_EXPORT void FEMContext::interior_rate_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2242             : template LIBMESH_EXPORT void FEMContext::interior_rate_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
    2243             : 
    2244             : template LIBMESH_EXPORT void FEMContext::side_rate<Number>(unsigned int, unsigned int, Number &) const;
    2245             : template LIBMESH_EXPORT void FEMContext::side_rate<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2246             : 
    2247             : template LIBMESH_EXPORT void FEMContext::interior_accel<Number>(unsigned int, unsigned int, Number &) const;
    2248             : template LIBMESH_EXPORT void FEMContext::interior_accel<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2249             : 
    2250             : template LIBMESH_EXPORT void FEMContext::side_accel<Number>(unsigned int, unsigned int, Number &) const;
    2251             : template LIBMESH_EXPORT void FEMContext::side_accel<Gradient>(unsigned int, unsigned int, Gradient &) const;
    2252             : 
    2253             : template LIBMESH_EXPORT FEGenericBase<Real> *
    2254             : FEMContext::build_new_fe(const FEGenericBase<Real>*,
    2255             :                          const Point &,
    2256             :                          const Real,
    2257             :                          const int) const;
    2258             : 
    2259             : template LIBMESH_EXPORT FEGenericBase<RealGradient> *
    2260             : FEMContext::build_new_fe(const FEGenericBase<RealGradient>*,
    2261             :                          const Point &,
    2262             :                          const Real,
    2263             :                          const int) const;
    2264             : 
    2265             : } // namespace libMesh

Generated by: LCOV version 1.14