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

Generated by: LCOV version 1.14