LCOV - code coverage report
Current view: top level - src/base - Assembly.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 2218 2769 80.1 %
Date: 2025-07-17 01:28:37 Functions: 161 190 84.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "Assembly.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "SubProblem.h"
      14             : #include "ArbitraryQuadrature.h"
      15             : #include "SystemBase.h"
      16             : #include "MooseTypes.h"
      17             : #include "MooseMesh.h"
      18             : #include "MooseVariableFE.h"
      19             : #include "MooseVariableScalar.h"
      20             : #include "XFEMInterface.h"
      21             : #include "DisplacedSystem.h"
      22             : #include "MooseMeshUtils.h"
      23             : 
      24             : // libMesh
      25             : #include "libmesh/coupling_matrix.h"
      26             : #include "libmesh/dof_map.h"
      27             : #include "libmesh/elem.h"
      28             : #include "libmesh/equation_systems.h"
      29             : #include "libmesh/fe_interface.h"
      30             : #include "libmesh/node.h"
      31             : #include "libmesh/quadrature_gauss.h"
      32             : #include "libmesh/sparse_matrix.h"
      33             : #include "libmesh/tensor_value.h"
      34             : #include "libmesh/vector_value.h"
      35             : #include "libmesh/fe.h"
      36             : #include "libmesh/static_condensation.h"
      37             : 
      38             : using namespace libMesh;
      39             : 
      40             : template <typename P, typename C>
      41             : void
      42  1823172886 : coordTransformFactor(const SubProblem & s,
      43             :                      const SubdomainID sub_id,
      44             :                      const P & point,
      45             :                      C & factor,
      46             :                      const SubdomainID neighbor_sub_id)
      47             : {
      48  1823172886 :   coordTransformFactor(s.mesh(), sub_id, point, factor, neighbor_sub_id);
      49  1823172886 : }
      50             : 
      51             : template <typename P, typename C>
      52             : void
      53  1826490689 : coordTransformFactor(const MooseMesh & mesh,
      54             :                      const SubdomainID sub_id,
      55             :                      const P & point,
      56             :                      C & factor,
      57             :                      const SubdomainID libmesh_dbg_var(neighbor_sub_id))
      58             : {
      59             :   mooseAssert(neighbor_sub_id != libMesh::Elem::invalid_subdomain_id
      60             :                   ? mesh.getCoordSystem(sub_id) == mesh.getCoordSystem(neighbor_sub_id)
      61             :                   : true,
      62             :               "Coordinate systems must be the same between element and neighbor");
      63  1826490689 :   const auto coord_type = mesh.getCoordSystem(sub_id);
      64             : 
      65  1826490689 :   if (coord_type == Moose::COORD_RZ)
      66             :   {
      67     3858246 :     if (mesh.usingGeneralAxisymmetricCoordAxes())
      68             :     {
      69     1065929 :       const auto & axis = mesh.getGeneralAxisymmetricCoordAxis(sub_id);
      70     1065929 :       MooseMeshUtils::coordTransformFactorRZGeneral(point, axis, factor);
      71             :     }
      72             :     else
      73     2792317 :       MooseMeshUtils::coordTransformFactor(
      74             :           point, factor, coord_type, mesh.getAxisymmetricRadialCoord());
      75             :   }
      76             :   else
      77  1822632443 :     MooseMeshUtils::coordTransformFactor(point, factor, coord_type, libMesh::invalid_uint);
      78  1826490689 : }
      79             : 
      80       66571 : Assembly::Assembly(SystemBase & sys, THREAD_ID tid)
      81       66571 :   : _sys(sys),
      82      133142 :     _subproblem(_sys.subproblem()),
      83       66571 :     _displaced(dynamic_cast<DisplacedSystem *>(&sys) ? true : false),
      84       66571 :     _nonlocal_cm(_subproblem.nonlocalCouplingMatrix(_sys.number())),
      85       66571 :     _computing_residual(_subproblem.currentlyComputingResidual()),
      86       66571 :     _computing_jacobian(_subproblem.currentlyComputingJacobian()),
      87       66571 :     _computing_residual_and_jacobian(_subproblem.currentlyComputingResidualAndJacobian()),
      88       66571 :     _dof_map(_sys.dofMap()),
      89       66571 :     _tid(tid),
      90       66571 :     _mesh(sys.mesh()),
      91       66571 :     _mesh_dimension(_mesh.dimension()),
      92       66571 :     _helper_type(_mesh.hasSecondOrderElements() ? SECOND : FIRST, LAGRANGE),
      93       66571 :     _user_added_fe_of_helper_type(false),
      94       66571 :     _user_added_fe_face_of_helper_type(false),
      95       66571 :     _user_added_fe_face_neighbor_of_helper_type(false),
      96       66571 :     _user_added_fe_neighbor_of_helper_type(false),
      97       66571 :     _user_added_fe_lower_of_helper_type(false),
      98       66571 :     _building_helpers(false),
      99       66571 :     _current_qrule(nullptr),
     100       66571 :     _current_qrule_volume(nullptr),
     101       66571 :     _current_qrule_arbitrary(nullptr),
     102       66571 :     _coord_type(Moose::COORD_XYZ),
     103       66571 :     _current_qrule_face(nullptr),
     104       66571 :     _current_qface_arbitrary(nullptr),
     105       66571 :     _current_qrule_neighbor(nullptr),
     106       66571 :     _need_JxW_neighbor(false),
     107       66571 :     _qrule_msm(nullptr),
     108       66571 :     _custom_mortar_qrule(false),
     109       66571 :     _current_qrule_lower(nullptr),
     110             : 
     111       66571 :     _current_elem(nullptr),
     112       66571 :     _current_elem_volume(0),
     113       66571 :     _current_side(0),
     114       66571 :     _current_side_elem(nullptr),
     115       66571 :     _current_side_volume(0),
     116       66571 :     _current_neighbor_elem(nullptr),
     117       66571 :     _current_neighbor_side(0),
     118       66571 :     _current_neighbor_side_elem(nullptr),
     119       66571 :     _need_neighbor_elem_volume(false),
     120       66571 :     _current_neighbor_volume(0),
     121       66571 :     _current_node(nullptr),
     122       66571 :     _current_neighbor_node(nullptr),
     123       66571 :     _current_elem_volume_computed(false),
     124       66571 :     _current_side_volume_computed(false),
     125             : 
     126       66571 :     _current_lower_d_elem(nullptr),
     127       66571 :     _current_neighbor_lower_d_elem(nullptr),
     128       66571 :     _need_lower_d_elem_volume(false),
     129       66571 :     _need_neighbor_lower_d_elem_volume(false),
     130       66571 :     _need_dual(false),
     131             : 
     132       66571 :     _residual_vector_tags(_subproblem.getVectorTags(Moose::VECTOR_TAG_RESIDUAL)),
     133       66571 :     _cached_residual_values(2), // The 2 is for TIME and NONTIME
     134       66571 :     _cached_residual_rows(2),   // The 2 is for TIME and NONTIME
     135       66571 :     _max_cached_residuals(0),
     136       66571 :     _max_cached_jacobians(0),
     137             : 
     138       66571 :     _block_diagonal_matrix(false),
     139       66571 :     _calculate_xyz(false),
     140       66571 :     _calculate_face_xyz(false),
     141       66571 :     _calculate_curvatures(false),
     142       66571 :     _calculate_ad_coord(false),
     143       66571 :     _have_p_refinement(false),
     144      266284 :     _sc(nullptr)
     145             : {
     146       66571 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
     147       66571 :   _building_helpers = true;
     148             :   // Build fe's for the helpers
     149       66571 :   buildFE(FEType(helper_order, LAGRANGE));
     150       66571 :   buildFaceFE(FEType(helper_order, LAGRANGE));
     151       66571 :   buildNeighborFE(FEType(helper_order, LAGRANGE));
     152       66571 :   buildFaceNeighborFE(FEType(helper_order, LAGRANGE));
     153       66571 :   buildLowerDFE(FEType(helper_order, LAGRANGE));
     154       66571 :   _building_helpers = false;
     155             : 
     156             :   // Build an FE helper object for this type for each dimension up to the dimension of the current
     157             :   // mesh
     158      258653 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     159             :   {
     160      192082 :     _holder_fe_helper[dim] = _fe[dim][FEType(helper_order, LAGRANGE)];
     161      192082 :     _holder_fe_face_helper[dim] = _fe_face[dim][FEType(helper_order, LAGRANGE)];
     162      192082 :     _holder_fe_face_neighbor_helper[dim] = _fe_face_neighbor[dim][FEType(helper_order, LAGRANGE)];
     163      192082 :     _holder_fe_neighbor_helper[dim] = _fe_neighbor[dim][FEType(helper_order, LAGRANGE)];
     164             :   }
     165             : 
     166      192082 :   for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
     167      125511 :     _holder_fe_lower_helper[dim] = _fe_lower[dim][FEType(helper_order, LAGRANGE)];
     168             : 
     169             :   // request phi, dphi, xyz, JxW, etc. data
     170       66571 :   helpersRequestData();
     171             : 
     172             :   // For 3D mortar, mortar segments are always TRI3 elements so we want FIRST LAGRANGE regardless
     173             :   // of discretization
     174       66571 :   _fe_msm = (_mesh_dimension == 2)
     175      133142 :                 ? FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(helper_order, LAGRANGE))
     176       66571 :                 : FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(FIRST, LAGRANGE));
     177             :   // This FE object should not take part in p-refinement
     178       66571 :   _fe_msm->add_p_level_in_reinit(false);
     179       66571 :   _JxW_msm = &_fe_msm->get_JxW();
     180             :   // Prerequest xyz so that it is computed for _fe_msm so that it can be used for calculating
     181             :   // _coord_msm
     182       66571 :   _fe_msm->get_xyz();
     183             : 
     184       66571 :   _extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
     185       66571 :   _neighbor_extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
     186       66571 : }
     187             : 
     188      122386 : Assembly::~Assembly()
     189             : {
     190      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     191      435440 :     for (auto & it : _fe[dim])
     192      258259 :       delete it.second;
     193             : 
     194      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     195      435440 :     for (auto & it : _fe_face[dim])
     196      258259 :       delete it.second;
     197             : 
     198      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     199      435440 :     for (auto & it : _fe_neighbor[dim])
     200      258259 :       delete it.second;
     201             : 
     202      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     203      435440 :     for (auto & it : _fe_face_neighbor[dim])
     204      258259 :       delete it.second;
     205             : 
     206      177181 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     207      278596 :     for (auto & it : _fe_lower[dim])
     208      162608 :       delete it.second;
     209             : 
     210      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     211      180190 :     for (auto & it : _vector_fe[dim])
     212        3009 :       delete it.second;
     213             : 
     214      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     215      180190 :     for (auto & it : _vector_fe_face[dim])
     216        3009 :       delete it.second;
     217             : 
     218      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     219      180190 :     for (auto & it : _vector_fe_neighbor[dim])
     220        3009 :       delete it.second;
     221             : 
     222      238374 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     223      180190 :     for (auto & it : _vector_fe_face_neighbor[dim])
     224        3009 :       delete it.second;
     225             : 
     226      177181 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     227      117536 :     for (auto & it : _vector_fe_lower[dim])
     228        1548 :       delete it.second;
     229             : 
     230      137803 :   for (auto & it : _ad_grad_phi_data)
     231       76610 :     it.second.release();
     232             : 
     233       62402 :   for (auto & it : _ad_vector_grad_phi_data)
     234        1209 :     it.second.release();
     235             : 
     236      131809 :   for (auto & it : _ad_grad_phi_data_face)
     237       70616 :     it.second.release();
     238             : 
     239       62402 :   for (auto & it : _ad_vector_grad_phi_data_face)
     240        1209 :     it.second.release();
     241             : 
     242       61193 :   _current_physical_points.release();
     243             : 
     244       61193 :   _coord.release();
     245       61193 :   _coord_neighbor.release();
     246       61193 :   _coord_msm.release();
     247             : 
     248       61193 :   _ad_JxW.release();
     249       61193 :   _ad_q_points.release();
     250       61193 :   _ad_JxW_face.release();
     251       61193 :   _ad_normals.release();
     252       61193 :   _ad_q_points_face.release();
     253       61193 :   _curvatures.release();
     254       61193 :   _ad_curvatures.release();
     255       61193 :   _ad_coord.release();
     256             : 
     257       61193 :   delete _qrule_msm;
     258      122386 : }
     259             : 
     260             : const MooseArray<Real> &
     261          93 : Assembly::JxWNeighbor() const
     262             : {
     263          93 :   _need_JxW_neighbor = true;
     264          93 :   return _current_JxW_neighbor;
     265             : }
     266             : 
     267             : void
     268      440628 : Assembly::buildFE(FEType type) const
     269             : {
     270      440628 :   if (!_building_helpers && type == _helper_type)
     271      195257 :     _user_added_fe_of_helper_type = true;
     272             : 
     273      440628 :   if (!_fe_shape_data[type])
     274       95647 :     _fe_shape_data[type] = std::make_unique<FEShapeData>();
     275             : 
     276             :   // Build an FE object for this type for each dimension up to the dimension of the current mesh
     277     1759972 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     278             :   {
     279     1319344 :     if (!_fe[dim][type])
     280      278159 :       _fe[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     281             : 
     282     1319344 :     _fe[dim][type]->get_phi();
     283     1319344 :     _fe[dim][type]->get_dphi();
     284             :     // Pre-request xyz.  We have always computed xyz, but due to
     285             :     // recent optimizations in libmesh, we now need to explicity
     286             :     // request it, since apps (Yak) may rely on it being computed.
     287     1319344 :     _fe[dim][type]->get_xyz();
     288     1319344 :     if (_need_second_derivative.count(type))
     289       80632 :       _fe[dim][type]->get_d2phi();
     290             :   }
     291      440628 : }
     292             : 
     293             : void
     294      414552 : Assembly::buildFaceFE(FEType type) const
     295             : {
     296      414552 :   if (!_building_helpers && type == _helper_type)
     297      190110 :     _user_added_fe_face_of_helper_type = true;
     298             : 
     299      414552 :   if (!_fe_shape_data_face[type])
     300       95647 :     _fe_shape_data_face[type] = std::make_unique<FEShapeData>();
     301             : 
     302             :   // Build an FE object for this type for each dimension up to the dimension of the current mesh
     303     1655608 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     304             :   {
     305     1241056 :     if (!_fe_face[dim][type])
     306      278159 :       _fe_face[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     307             : 
     308     1241056 :     _fe_face[dim][type]->get_phi();
     309     1241056 :     _fe_face[dim][type]->get_dphi();
     310     1241056 :     if (_need_second_derivative.count(type))
     311       16198 :       _fe_face[dim][type]->get_d2phi();
     312             :   }
     313      414552 : }
     314             : 
     315             : void
     316      409196 : Assembly::buildNeighborFE(FEType type) const
     317             : {
     318      409196 :   if (!_building_helpers && type == _helper_type)
     319      189998 :     _user_added_fe_neighbor_of_helper_type = true;
     320             : 
     321      409196 :   if (!_fe_shape_data_neighbor[type])
     322       95647 :     _fe_shape_data_neighbor[type] = std::make_unique<FEShapeData>();
     323             : 
     324             :   // Build an FE object for this type for each dimension up to the dimension of the current mesh
     325     1634171 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     326             :   {
     327     1224975 :     if (!_fe_neighbor[dim][type])
     328      278159 :       _fe_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     329             : 
     330     1224975 :     _fe_neighbor[dim][type]->get_phi();
     331     1224975 :     _fe_neighbor[dim][type]->get_dphi();
     332     1224975 :     if (_need_second_derivative_neighbor.count(type))
     333         117 :       _fe_neighbor[dim][type]->get_d2phi();
     334             :   }
     335      409196 : }
     336             : 
     337             : void
     338      409196 : Assembly::buildFaceNeighborFE(FEType type) const
     339             : {
     340      409196 :   if (!_building_helpers && type == _helper_type)
     341      189998 :     _user_added_fe_face_neighbor_of_helper_type = true;
     342             : 
     343      409196 :   if (!_fe_shape_data_face_neighbor[type])
     344       95647 :     _fe_shape_data_face_neighbor[type] = std::make_unique<FEShapeData>();
     345             : 
     346             :   // Build an FE object for this type for each dimension up to the dimension of the current mesh
     347     1634171 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     348             :   {
     349     1224975 :     if (!_fe_face_neighbor[dim][type])
     350      278159 :       _fe_face_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     351             : 
     352     1224975 :     _fe_face_neighbor[dim][type]->get_phi();
     353     1224975 :     _fe_face_neighbor[dim][type]->get_dphi();
     354     1224975 :     if (_need_second_derivative_neighbor.count(type))
     355         117 :       _fe_face_neighbor[dim][type]->get_d2phi();
     356             :   }
     357      409196 : }
     358             : 
     359             : void
     360      720463 : Assembly::buildLowerDFE(FEType type) const
     361             : {
     362      720463 :   if (!_building_helpers && type == _helper_type)
     363      379456 :     _user_added_fe_lower_of_helper_type = true;
     364             : 
     365      720463 :   if (!_fe_shape_data_lower[type])
     366       90821 :     _fe_shape_data_lower[type] = std::make_unique<FEShapeData>();
     367             : 
     368             :   // Build an FE object for this type for each dimension up to the dimension of
     369             :   // the current mesh minus one (because this is for lower-dimensional
     370             :   // elements!)
     371     2178546 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     372             :   {
     373     1458083 :     if (!_fe_lower[dim][type])
     374      175206 :       _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     375             : 
     376     1458083 :     _fe_lower[dim][type]->get_phi();
     377     1458083 :     _fe_lower[dim][type]->get_dphi();
     378     1458083 :     if (_need_second_derivative.count(type))
     379           0 :       _fe_lower[dim][type]->get_d2phi();
     380             :   }
     381      720463 : }
     382             : 
     383             : void
     384         540 : Assembly::buildLowerDDualFE(FEType type) const
     385             : {
     386         540 :   if (!_fe_shape_data_dual_lower[type])
     387         135 :     _fe_shape_data_dual_lower[type] = std::make_unique<FEShapeData>();
     388             : 
     389             :   // Build an FE object for this type for each dimension up to the dimension of
     390             :   // the current mesh minus one (because this is for lower-dimensional
     391             :   // elements!)
     392        1672 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     393             :   {
     394        1132 :     if (!_fe_lower[dim][type])
     395           0 :       _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     396             : 
     397        1132 :     _fe_lower[dim][type]->get_dual_phi();
     398        1132 :     _fe_lower[dim][type]->get_dual_dphi();
     399        1132 :     if (_need_second_derivative.count(type))
     400           0 :       _fe_lower[dim][type]->get_dual_d2phi();
     401             :   }
     402         540 : }
     403             : 
     404             : void
     405        6284 : Assembly::buildVectorLowerDFE(FEType type) const
     406             : {
     407        6284 :   if (!_vector_fe_shape_data_lower[type])
     408        1259 :     _vector_fe_shape_data_lower[type] = std::make_unique<VectorFEShapeData>();
     409             : 
     410             :   // Build an FE object for this type for each dimension up to the dimension of
     411             :   // the current mesh minus one (because this is for lower-dimensional
     412             :   // elements!)
     413        6284 :   unsigned int dim = ((type.family == LAGRANGE_VEC) || (type.family == MONOMIAL_VEC)) ? 0 : 2;
     414        6284 :   const auto ending_dim = cast_int<unsigned int>(_mesh_dimension - 1);
     415        6284 :   if (ending_dim < dim)
     416        1716 :     return;
     417       13536 :   for (; dim <= ending_dim; dim++)
     418             :   {
     419        8968 :     if (!_vector_fe_lower[dim][type])
     420        1663 :       _vector_fe_lower[dim][type] = FEVectorBase::build(dim, type).release();
     421             : 
     422        8968 :     _vector_fe_lower[dim][type]->get_phi();
     423        8968 :     _vector_fe_lower[dim][type]->get_dphi();
     424        8968 :     if (_need_second_derivative.count(type))
     425           0 :       _vector_fe_lower[dim][type]->get_d2phi();
     426             :   }
     427             : }
     428             : 
     429             : void
     430           0 : Assembly::buildVectorDualLowerDFE(FEType type) const
     431             : {
     432           0 :   if (!_vector_fe_shape_data_dual_lower[type])
     433           0 :     _vector_fe_shape_data_dual_lower[type] = std::make_unique<VectorFEShapeData>();
     434             : 
     435             :   // Build an FE object for this type for each dimension up to the dimension of
     436             :   // the current mesh minus one (because this is for lower-dimensional
     437             :   // elements!)
     438           0 :   unsigned int dim = ((type.family == LAGRANGE_VEC) || (type.family == MONOMIAL_VEC)) ? 0 : 2;
     439           0 :   const auto ending_dim = cast_int<unsigned int>(_mesh_dimension - 1);
     440           0 :   if (ending_dim < dim)
     441           0 :     return;
     442           0 :   for (; dim <= ending_dim; dim++)
     443             :   {
     444           0 :     if (!_vector_fe_lower[dim][type])
     445           0 :       _vector_fe_lower[dim][type] = FEVectorBase::build(dim, type).release();
     446             : 
     447           0 :     _vector_fe_lower[dim][type]->get_dual_phi();
     448           0 :     _vector_fe_lower[dim][type]->get_dual_dphi();
     449           0 :     if (_need_second_derivative.count(type))
     450           0 :       _vector_fe_lower[dim][type]->get_dual_d2phi();
     451             :   }
     452             : }
     453             : 
     454             : void
     455      529455 : Assembly::buildVectorFE(const FEType type) const
     456             : {
     457      529455 :   if (!_vector_fe_shape_data[type])
     458        1259 :     _vector_fe_shape_data[type] = std::make_unique<VectorFEShapeData>();
     459             : 
     460             :   // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
     461             :   unsigned int min_dim;
     462      529455 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     463        2968 :       type.family == L2_RAVIART_THOMAS)
     464      526795 :     min_dim = 2;
     465             :   else
     466        2660 :     min_dim = 0;
     467             : 
     468             :   // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
     469             :   // current mesh
     470     1520683 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     471             :   {
     472      991228 :     if (!_vector_fe[dim][type])
     473        3174 :       _vector_fe[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     474             : 
     475      991228 :     _vector_fe[dim][type]->get_phi();
     476      991228 :     _vector_fe[dim][type]->get_dphi();
     477      991228 :     if (_need_curl.count(type))
     478       63894 :       _vector_fe[dim][type]->get_curl_phi();
     479      991228 :     if (_need_div.count(type))
     480      919204 :       _vector_fe[dim][type]->get_div_phi();
     481      991228 :     _vector_fe[dim][type]->get_xyz();
     482             :   }
     483      529455 : }
     484             : 
     485             : void
     486        3663 : Assembly::buildVectorFaceFE(const FEType type) const
     487             : {
     488        3663 :   if (!_vector_fe_shape_data_face[type])
     489        1259 :     _vector_fe_shape_data_face[type] = std::make_unique<VectorFEShapeData>();
     490             : 
     491             :   // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
     492             :   unsigned int min_dim;
     493        3663 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     494        2464 :       type.family == L2_RAVIART_THOMAS)
     495        1353 :     min_dim = 2;
     496             :   else
     497        2310 :     min_dim = 0;
     498             : 
     499             :   // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
     500             :   // current mesh
     501       12492 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     502             :   {
     503        8829 :     if (!_vector_fe_face[dim][type])
     504        3174 :       _vector_fe_face[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     505             : 
     506        8829 :     _vector_fe_face[dim][type]->get_phi();
     507        8829 :     _vector_fe_face[dim][type]->get_dphi();
     508        8829 :     if (_need_curl.count(type))
     509         283 :       _vector_fe_face[dim][type]->get_curl_phi();
     510        8829 :     if (_need_face_div.count(type))
     511         416 :       _vector_fe_face[dim][type]->get_div_phi();
     512             :   }
     513        3663 : }
     514             : 
     515             : void
     516        3142 : Assembly::buildVectorNeighborFE(const FEType type) const
     517             : {
     518        3142 :   if (!_vector_fe_shape_data_neighbor[type])
     519        1259 :     _vector_fe_shape_data_neighbor[type] = std::make_unique<VectorFEShapeData>();
     520             : 
     521             :   // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
     522             :   unsigned int min_dim;
     523        3142 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     524        2464 :       type.family == L2_RAVIART_THOMAS)
     525         832 :     min_dim = 2;
     526             :   else
     527        2310 :     min_dim = 0;
     528             : 
     529             :   // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
     530             :   // current mesh
     531       11272 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     532             :   {
     533        8130 :     if (!_vector_fe_neighbor[dim][type])
     534        3174 :       _vector_fe_neighbor[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     535             : 
     536        8130 :     _vector_fe_neighbor[dim][type]->get_phi();
     537        8130 :     _vector_fe_neighbor[dim][type]->get_dphi();
     538        8130 :     if (_need_curl.count(type))
     539           0 :       _vector_fe_neighbor[dim][type]->get_curl_phi();
     540        8130 :     if (_need_neighbor_div.count(type))
     541           0 :       _vector_fe_neighbor[dim][type]->get_div_phi();
     542             :   }
     543        3142 : }
     544             : 
     545             : void
     546        3663 : Assembly::buildVectorFaceNeighborFE(const FEType type) const
     547             : {
     548        3663 :   if (!_vector_fe_shape_data_face_neighbor[type])
     549        1259 :     _vector_fe_shape_data_face_neighbor[type] = std::make_unique<VectorFEShapeData>();
     550             : 
     551             :   // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
     552             :   unsigned int min_dim;
     553        3663 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     554        2464 :       type.family == L2_RAVIART_THOMAS)
     555        1353 :     min_dim = 2;
     556             :   else
     557        2310 :     min_dim = 0;
     558             : 
     559             :   // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
     560             :   // current mesh
     561       12492 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     562             :   {
     563        8829 :     if (!_vector_fe_face_neighbor[dim][type])
     564        3174 :       _vector_fe_face_neighbor[dim][type] =
     565        6348 :           FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     566             : 
     567        8829 :     _vector_fe_face_neighbor[dim][type]->get_phi();
     568        8829 :     _vector_fe_face_neighbor[dim][type]->get_dphi();
     569        8829 :     if (_need_curl.count(type))
     570         283 :       _vector_fe_face_neighbor[dim][type]->get_curl_phi();
     571        8829 :     if (_need_face_neighbor_div.count(type))
     572           0 :       _vector_fe_face_neighbor[dim][type]->get_div_phi();
     573             :   }
     574        3663 : }
     575             : 
     576             : void
     577          90 : Assembly::bumpVolumeQRuleOrder(Order volume_order, SubdomainID block)
     578             : {
     579          90 :   auto & qdefault = _qrules[Moose::ANY_BLOCK_ID];
     580             :   mooseAssert(qdefault.size() > 0, "default quadrature must be initialized before order bumps");
     581             : 
     582          90 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     583          90 :   auto & qvec = _qrules[block];
     584          90 :   if (qvec.size() != ndims || !qvec[0].vol)
     585          52 :     createQRules(qdefault[0].vol->type(),
     586          26 :                  qdefault[0].arbitrary_vol->get_order(),
     587             :                  volume_order,
     588          26 :                  qdefault[0].face->get_order(),
     589             :                  block);
     590          64 :   else if (qvec[0].vol->get_order() < volume_order)
     591           0 :     createQRules(qvec[0].vol->type(),
     592           0 :                  qvec[0].arbitrary_vol->get_order(),
     593             :                  volume_order,
     594           0 :                  qvec[0].face->get_order(),
     595             :                  block);
     596             :   // otherwise do nothing - quadrature order is already as high as requested
     597          90 : }
     598             : 
     599             : void
     600          15 : Assembly::bumpAllQRuleOrder(Order order, SubdomainID block)
     601             : {
     602          15 :   auto & qdefault = _qrules[Moose::ANY_BLOCK_ID];
     603             :   mooseAssert(qdefault.size() > 0, "default quadrature must be initialized before order bumps");
     604             : 
     605          15 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     606          15 :   auto & qvec = _qrules[block];
     607          15 :   if (qvec.size() != ndims || !qvec[0].vol)
     608          13 :     createQRules(qdefault[0].vol->type(), order, order, order, block);
     609           2 :   else if (qvec[0].vol->get_order() < order || qvec[0].face->get_order() < order)
     610           0 :     createQRules(qvec[0].vol->type(),
     611           0 :                  std::max(order, qvec[0].arbitrary_vol->get_order()),
     612           0 :                  std::max(order, qvec[0].vol->get_order()),
     613           0 :                  std::max(order, qvec[0].face->get_order()),
     614             :                  block);
     615             :   // otherwise do nothing - quadrature order is already as high as requested
     616          15 : }
     617             : 
     618             : void
     619       66176 : Assembly::createQRules(QuadratureType type,
     620             :                        Order order,
     621             :                        Order volume_order,
     622             :                        Order face_order,
     623             :                        SubdomainID block,
     624             :                        bool allow_negative_qweights)
     625             : {
     626       66176 :   auto & qvec = _qrules[block];
     627       66176 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     628       66176 :   if (qvec.size() != ndims)
     629       66176 :     qvec.resize(ndims);
     630             : 
     631      257077 :   for (unsigned int i = 0; i < qvec.size(); i++)
     632             :   {
     633      190901 :     int dim = i;
     634      190901 :     auto & q = qvec[dim];
     635      190901 :     q.vol = QBase::build(type, dim, volume_order);
     636      190901 :     q.vol->allow_rules_with_negative_weights = allow_negative_qweights;
     637      190901 :     q.face = QBase::build(type, dim - 1, face_order);
     638      190901 :     q.face->allow_rules_with_negative_weights = allow_negative_qweights;
     639      190901 :     q.fv_face = QBase::build(QMONOMIAL, dim - 1, CONSTANT);
     640      190901 :     q.fv_face->allow_rules_with_negative_weights = allow_negative_qweights;
     641      190901 :     q.neighbor = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
     642      190901 :     q.neighbor->allow_rules_with_negative_weights = allow_negative_qweights;
     643      190901 :     q.arbitrary_vol = std::make_unique<ArbitraryQuadrature>(dim, order);
     644      190901 :     q.arbitrary_vol->allow_rules_with_negative_weights = allow_negative_qweights;
     645      190901 :     q.arbitrary_face = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
     646      190901 :     q.arbitrary_face->allow_rules_with_negative_weights = allow_negative_qweights;
     647             :   }
     648             : 
     649       66176 :   delete _qrule_msm;
     650       66176 :   _custom_mortar_qrule = false;
     651       66176 :   _qrule_msm = QBase::build(type, _mesh_dimension - 1, face_order).release();
     652       66176 :   _qrule_msm->allow_rules_with_negative_weights = allow_negative_qweights;
     653       66176 :   _fe_msm->attach_quadrature_rule(_qrule_msm);
     654       66176 : }
     655             : 
     656             : void
     657      225641 : Assembly::setVolumeQRule(QBase * qrule, unsigned int dim)
     658             : {
     659      225641 :   _current_qrule = qrule;
     660             : 
     661      225641 :   if (qrule) // Don't set a NULL qrule
     662             :   {
     663      545192 :     for (auto & it : _fe[dim])
     664      319551 :       it.second->attach_quadrature_rule(qrule);
     665      229601 :     for (auto & it : _vector_fe[dim])
     666        3960 :       it.second->attach_quadrature_rule(qrule);
     667      225641 :     if (!_unique_fe_helper.empty())
     668             :     {
     669             :       mooseAssert(dim < _unique_fe_helper.size(), "We should not be indexing out of bounds");
     670         214 :       _unique_fe_helper[dim]->attach_quadrature_rule(qrule);
     671             :     }
     672             :   }
     673      225641 : }
     674             : 
     675             : void
     676      563870 : Assembly::setFaceQRule(QBase * qrule, unsigned int dim)
     677             : {
     678      563870 :   _current_qrule_face = qrule;
     679             : 
     680     1334156 :   for (auto & it : _fe_face[dim])
     681      770286 :     it.second->attach_quadrature_rule(qrule);
     682      564494 :   for (auto & it : _vector_fe_face[dim])
     683         624 :     it.second->attach_quadrature_rule(qrule);
     684      563870 :   if (!_unique_fe_face_helper.empty())
     685             :   {
     686             :     mooseAssert(dim < _unique_fe_face_helper.size(), "We should not be indexing out of bounds");
     687         200 :     _unique_fe_face_helper[dim]->attach_quadrature_rule(qrule);
     688             :   }
     689      563870 : }
     690             : 
     691             : void
     692      263515 : Assembly::setLowerQRule(QBase * qrule, unsigned int dim)
     693             : {
     694             :   // The lower-dimensional quadrature rule matches the face quadrature rule
     695      263515 :   setFaceQRule(qrule, dim);
     696             : 
     697      263515 :   _current_qrule_lower = qrule;
     698             : 
     699      616116 :   for (auto & it : _fe_lower[dim])
     700      352601 :     it.second->attach_quadrature_rule(qrule);
     701      263515 :   for (auto & it : _vector_fe_lower[dim])
     702           0 :     it.second->attach_quadrature_rule(qrule);
     703      263515 :   if (!_unique_fe_lower_helper.empty())
     704             :   {
     705             :     mooseAssert(dim < _unique_fe_lower_helper.size(), "We should not be indexing out of bounds");
     706           0 :     _unique_fe_lower_helper[dim]->attach_quadrature_rule(qrule);
     707             :   }
     708      263515 : }
     709             : 
     710             : void
     711    27021639 : Assembly::setNeighborQRule(QBase * qrule, unsigned int dim)
     712             : {
     713    27021639 :   _current_qrule_neighbor = qrule;
     714             : 
     715    80577481 :   for (auto & it : _fe_face_neighbor[dim])
     716    53555842 :     it.second->attach_quadrature_rule(qrule);
     717    27047504 :   for (auto & it : _vector_fe_face_neighbor[dim])
     718       25865 :     it.second->attach_quadrature_rule(qrule);
     719    27021639 :   if (!_unique_fe_face_neighbor_helper.empty())
     720             :   {
     721             :     mooseAssert(dim < _unique_fe_face_neighbor_helper.size(),
     722             :                 "We should not be indexing out of bounds");
     723       62324 :     _unique_fe_face_neighbor_helper[dim]->attach_quadrature_rule(qrule);
     724             :   }
     725    27021639 : }
     726             : 
     727             : void
     728       62685 : Assembly::clearCachedQRules()
     729             : {
     730       62685 :   _current_qrule = nullptr;
     731       62685 :   _current_qrule_face = nullptr;
     732       62685 :   _current_qrule_lower = nullptr;
     733       62685 :   _current_qrule_neighbor = nullptr;
     734       62685 : }
     735             : 
     736             : void
     737           0 : Assembly::setMortarQRule(Order order)
     738             : {
     739           0 :   if (order != _qrule_msm->get_order())
     740             :   {
     741             :     // If custom mortar qrule has not yet been specified
     742           0 :     if (!_custom_mortar_qrule)
     743             :     {
     744           0 :       _custom_mortar_qrule = true;
     745           0 :       const unsigned int dim = _qrule_msm->get_dim();
     746           0 :       const QuadratureType type = _qrule_msm->type();
     747           0 :       delete _qrule_msm;
     748             : 
     749           0 :       _qrule_msm = QBase::build(type, dim, order).release();
     750           0 :       _fe_msm->attach_quadrature_rule(_qrule_msm);
     751             :     }
     752             :     else
     753           0 :       mooseError("Mortar quadrature_order: ",
     754             :                  order,
     755             :                  " does not match previously specified quadrature_order: ",
     756           0 :                  _qrule_msm->get_order(),
     757             :                  ". Quadrature_order (when specified) must match for all mortar constraints.");
     758             :   }
     759           0 : }
     760             : 
     761             : void
     762   394339425 : Assembly::reinitFE(const Elem * elem)
     763             : {
     764   394339425 :   unsigned int dim = elem->dim();
     765             : 
     766   888329751 :   for (const auto & it : _fe[dim])
     767             :   {
     768   493990354 :     FEBase & fe = *it.second;
     769   493990354 :     const FEType & fe_type = it.first;
     770             : 
     771   493990354 :     _current_fe[fe_type] = &fe;
     772             : 
     773   493990354 :     FEShapeData & fesd = *_fe_shape_data[fe_type];
     774             : 
     775   493990354 :     fe.reinit(elem);
     776             : 
     777   493990326 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_phi()));
     778   493990326 :     fesd._grad_phi.shallowCopy(
     779   493990326 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_dphi()));
     780   493990326 :     if (_need_second_derivative.count(fe_type))
     781       59941 :       fesd._second_phi.shallowCopy(
     782       59941 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe.get_d2phi()));
     783             :   }
     784   399959602 :   for (const auto & it : _vector_fe[dim])
     785             :   {
     786     5620205 :     FEVectorBase & fe = *it.second;
     787     5620205 :     const FEType & fe_type = it.first;
     788             : 
     789     5620205 :     _current_vector_fe[fe_type] = &fe;
     790             : 
     791     5620205 :     VectorFEShapeData & fesd = *_vector_fe_shape_data[fe_type];
     792             : 
     793     5620205 :     fe.reinit(elem);
     794             : 
     795     5620205 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_phi()));
     796     5620205 :     fesd._grad_phi.shallowCopy(
     797     5620205 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe.get_dphi()));
     798     5620205 :     if (_need_second_derivative.count(fe_type))
     799           0 :       fesd._second_phi.shallowCopy(
     800           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe.get_d2phi()));
     801     5620205 :     if (_need_curl.count(fe_type))
     802     2433834 :       fesd._curl_phi.shallowCopy(
     803     2433834 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_curl_phi()));
     804     5620205 :     if (_need_div.count(fe_type))
     805     1228120 :       fesd._div_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_div_phi()));
     806             :   }
     807   394339397 :   if (!_unique_fe_helper.empty())
     808             :   {
     809             :     mooseAssert(dim < _unique_fe_helper.size(), "We should be in bounds here");
     810      667582 :     _unique_fe_helper[dim]->reinit(elem);
     811             :   }
     812             : 
     813             :   // During that last loop the helper objects will have been reinitialized as well
     814             :   // We need to dig out the q_points and JxW from it.
     815   394339397 :   _current_q_points.shallowCopy(
     816   394339397 :       const_cast<std::vector<Point> &>(_holder_fe_helper[dim]->get_xyz()));
     817   394339397 :   _current_JxW.shallowCopy(const_cast<std::vector<Real> &>(_holder_fe_helper[dim]->get_JxW()));
     818             : 
     819   394339397 :   if (_subproblem.haveADObjects())
     820             :   {
     821    33195038 :     auto n_qp = _current_qrule->n_points();
     822    33195038 :     resizeADMappingObjects(n_qp, dim);
     823    33195038 :     if (_displaced)
     824             :     {
     825      575152 :       const auto & qw = _current_qrule->get_weights();
     826     3165489 :       for (unsigned int qp = 0; qp != n_qp; qp++)
     827     2590337 :         computeSinglePointMapAD(elem, qw, qp, _holder_fe_helper[dim]);
     828             :     }
     829             :     else
     830             :     {
     831   106563719 :       for (unsigned qp = 0; qp < n_qp; ++qp)
     832    73943833 :         _ad_JxW[qp] = _current_JxW[qp];
     833    32619886 :       if (_calculate_xyz)
     834    59813164 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     835    47438565 :           _ad_q_points[qp] = _current_q_points[qp];
     836             :     }
     837             : 
     838    89399961 :     for (const auto & it : _fe[dim])
     839             :     {
     840    56204923 :       FEBase & fe = *it.second;
     841    56204923 :       auto fe_type = it.first;
     842    56204923 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
     843    56204923 :       auto & grad_phi = _ad_grad_phi_data[fe_type];
     844             : 
     845    56204923 :       grad_phi.resize(num_shapes);
     846   219905495 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     847   163700572 :         grad_phi[i].resize(n_qp);
     848             : 
     849    56204923 :       if (_displaced)
     850      865825 :         computeGradPhiAD(elem, n_qp, grad_phi, &fe);
     851             :       else
     852             :       {
     853    55339098 :         const auto & regular_grad_phi = _fe_shape_data[fe_type]->_grad_phi;
     854   215959497 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     855   675698696 :           for (unsigned qp = 0; qp < n_qp; ++qp)
     856   515078297 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
     857             :       }
     858             :     }
     859    36315248 :     for (const auto & it : _vector_fe[dim])
     860             :     {
     861     3120210 :       FEVectorBase & fe = *it.second;
     862     3120210 :       auto fe_type = it.first;
     863     3120210 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
     864     3120210 :       auto & grad_phi = _ad_vector_grad_phi_data[fe_type];
     865             : 
     866     3120210 :       grad_phi.resize(num_shapes);
     867    18652890 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     868    15532680 :         grad_phi[i].resize(n_qp);
     869             : 
     870     3120210 :       if (_displaced)
     871           0 :         computeGradPhiAD(elem, n_qp, grad_phi, &fe);
     872             :       else
     873             :       {
     874     3120210 :         const auto & regular_grad_phi = _vector_fe_shape_data[fe_type]->_grad_phi;
     875    18652890 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     876    79399800 :           for (unsigned qp = 0; qp < n_qp; ++qp)
     877    63867120 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
     878             :       }
     879             :     }
     880             :   }
     881             : 
     882   394339397 :   auto n = numExtraElemIntegers();
     883   397010005 :   for (auto i : make_range(n))
     884     2670608 :     _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
     885   394339397 :   _extra_elem_ids[n] = _current_elem->subdomain_id();
     886             : 
     887   394339397 :   if (_xfem != nullptr)
     888           0 :     modifyWeightsDueToXFEM(elem);
     889   394339397 : }
     890             : 
     891             : template <typename OutputType>
     892             : void
     893      997281 : Assembly::computeGradPhiAD(const Elem * elem,
     894             :                            unsigned int n_qp,
     895             :                            ADTemplateVariablePhiGradient<OutputType> & grad_phi,
     896             :                            FEGenericBase<OutputType> * fe)
     897             : {
     898             :   // This function relies on the fact that FE::reinit has already been called. FE::reinit will
     899             :   // importantly have already called FEMap::init_shape_functions which will have computed
     900             :   // these quantities at the integration/quadrature points: dphidxi,
     901             :   // dphideta, and dphidzeta (e.g. \nabla phi w.r.t. reference coordinates). These *phi* quantities
     902             :   // are independent of mesh displacements when using a quadrature rule.
     903             :   //
     904             :   // Note that a user could have specified custom integration points (e.g. independent of a
     905             :   // quadrature rule) which could very well depend on displacements. In that case even the *phi*
     906             :   // quantities from the above paragraph would be a function of the displacements and we would be
     907             :   // missing that derivative information in the calculations below
     908             : 
     909      997281 :   auto dim = elem->dim();
     910      997281 :   const auto & dphidxi = fe->get_dphidxi();
     911      997281 :   const auto & dphideta = fe->get_dphideta();
     912      997281 :   const auto & dphidzeta = fe->get_dphidzeta();
     913      997281 :   auto num_shapes = grad_phi.size();
     914             : 
     915      997281 :   switch (dim)
     916             :   {
     917           0 :     case 0:
     918             :     {
     919           0 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     920           0 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     921           0 :           grad_phi[i][qp] = 0;
     922           0 :       break;
     923             :     }
     924             : 
     925       51957 :     case 1:
     926             :     {
     927      139340 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     928      274853 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     929             :         {
     930      187470 :           grad_phi[i][qp].slice(0) = dphidxi[i][qp] * _ad_dxidx_map[qp];
     931      187470 :           grad_phi[i][qp].slice(1) = dphidxi[i][qp] * _ad_dxidy_map[qp];
     932      187470 :           grad_phi[i][qp].slice(2) = dphidxi[i][qp] * _ad_dxidz_map[qp];
     933             :         }
     934       51957 :       break;
     935             :     }
     936             : 
     937      945324 :     case 2:
     938             :     {
     939     4624758 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     940    21534379 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     941             :         {
     942    35709890 :           grad_phi[i][qp].slice(0) =
     943    35709890 :               dphidxi[i][qp] * _ad_dxidx_map[qp] + dphideta[i][qp] * _ad_detadx_map[qp];
     944    35709890 :           grad_phi[i][qp].slice(1) =
     945    35709890 :               dphidxi[i][qp] * _ad_dxidy_map[qp] + dphideta[i][qp] * _ad_detady_map[qp];
     946    35709890 :           grad_phi[i][qp].slice(2) =
     947    35709890 :               dphidxi[i][qp] * _ad_dxidz_map[qp] + dphideta[i][qp] * _ad_detadz_map[qp];
     948             :         }
     949      945324 :       break;
     950             :     }
     951             : 
     952           0 :     case 3:
     953             :     {
     954           0 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     955           0 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     956             :         {
     957           0 :           grad_phi[i][qp].slice(0) = dphidxi[i][qp] * _ad_dxidx_map[qp] +
     958           0 :                                      dphideta[i][qp] * _ad_detadx_map[qp] +
     959           0 :                                      dphidzeta[i][qp] * _ad_dzetadx_map[qp];
     960           0 :           grad_phi[i][qp].slice(1) = dphidxi[i][qp] * _ad_dxidy_map[qp] +
     961           0 :                                      dphideta[i][qp] * _ad_detady_map[qp] +
     962           0 :                                      dphidzeta[i][qp] * _ad_dzetady_map[qp];
     963           0 :           grad_phi[i][qp].slice(2) = dphidxi[i][qp] * _ad_dxidz_map[qp] +
     964           0 :                                      dphideta[i][qp] * _ad_detadz_map[qp] +
     965           0 :                                      dphidzeta[i][qp] * _ad_dzetadz_map[qp];
     966             :         }
     967           0 :       break;
     968             :     }
     969             :   }
     970      997281 : }
     971             : 
     972             : void
     973    37284428 : Assembly::resizeADMappingObjects(unsigned int n_qp, unsigned int dim)
     974             : {
     975    37284428 :   _ad_dxyzdxi_map.resize(n_qp);
     976    37284428 :   _ad_dxidx_map.resize(n_qp);
     977    37284428 :   _ad_dxidy_map.resize(n_qp); // 1D element may live in 2D ...
     978    37284428 :   _ad_dxidz_map.resize(n_qp); // ... or 3D
     979             : 
     980    37284428 :   if (dim > 1)
     981             :   {
     982    22752064 :     _ad_dxyzdeta_map.resize(n_qp);
     983    22752064 :     _ad_detadx_map.resize(n_qp);
     984    22752064 :     _ad_detady_map.resize(n_qp);
     985    22752064 :     _ad_detadz_map.resize(n_qp);
     986             : 
     987    22752064 :     if (dim > 2)
     988             :     {
     989      468926 :       _ad_dxyzdzeta_map.resize(n_qp);
     990      468926 :       _ad_dzetadx_map.resize(n_qp);
     991      468926 :       _ad_dzetady_map.resize(n_qp);
     992      468926 :       _ad_dzetadz_map.resize(n_qp);
     993             :     }
     994             :   }
     995             : 
     996    37284428 :   _ad_jac.resize(n_qp);
     997    37284428 :   _ad_JxW.resize(n_qp);
     998    37284428 :   if (_calculate_xyz)
     999    16407608 :     _ad_q_points.resize(n_qp);
    1000    37284428 : }
    1001             : 
    1002             : void
    1003     2697665 : Assembly::computeSinglePointMapAD(const Elem * elem,
    1004             :                                   const std::vector<Real> & qw,
    1005             :                                   unsigned p,
    1006             :                                   FEBase * fe)
    1007             : {
    1008             :   // This function relies on the fact that FE::reinit has already been called. FE::reinit will
    1009             :   // importantly have already called FEMap::init_reference_to_physical_map which will have computed
    1010             :   // these quantities at the integration/quadrature points: phi_map, dphidxi_map,
    1011             :   // dphideta_map, and dphidzeta_map (e.g. phi and \nabla phi w.r.t reference coordinates). *_map is
    1012             :   // used to denote that quantities are in reference to a mapping Lagrange FE object. The FE<Dim,
    1013             :   // LAGRANGE> objects used for mapping will in general have an order matching the order of the
    1014             :   // mesh. These *phi*_map quantities are independent of mesh displacements when using a quadrature
    1015             :   // rule.
    1016             :   //
    1017             :   // Note that a user could have specified custom integration points (e.g. independent of a
    1018             :   // quadrature rule) which could very well depend on displacements. In that case even the *phi*_map
    1019             :   // quantities from the above paragraph would be a function of the displacements and we would be
    1020             :   // missing that derivative information in the calculations below
    1021             :   //
    1022             :   // Important quantities calculated by this method:
    1023             :   //   - _ad_JxW;
    1024             :   //   - _ad_q_points;
    1025             :   // And the following quantities are important because they are used in the computeGradPhiAD method
    1026             :   // to calculate the shape function gradients with respect to the physical coordinates
    1027             :   // dphi/dphys = dphi/dref * dref/dphys:
    1028             :   //   - _ad_dxidx_map;
    1029             :   //   - _ad_dxidy_map;
    1030             :   //   - _ad_dxidz_map;
    1031             :   //   - _ad_detadx_map;
    1032             :   //   - _ad_detady_map;
    1033             :   //   - _ad_detadz_map;
    1034             :   //   - _ad_dzetadx_map;
    1035             :   //   - _ad_dzetady_map;
    1036             :   //   - _ad_dzetadz_map;
    1037             :   //
    1038             :   // Some final notes. This method will be called both when we are reinit'ing in the volume and on
    1039             :   // faces. When reinit'ing on faces, computation of _ad_JxW will be garbage because we will be
    1040             :   // using dummy quadrature weights. _ad_q_points computation is also currently extraneous during
    1041             :   // face reinit because we compute _ad_q_points_face in the computeFaceMap method. However,
    1042             :   // computation of dref/dphys is absolutely necessary (and the reason we call this method for the
    1043             :   // face case) for both volume and face reinit
    1044             : 
    1045     2697665 :   auto dim = elem->dim();
    1046     2697665 :   const auto & elem_nodes = elem->get_nodes();
    1047     2697665 :   auto num_shapes = FEInterface::n_shape_functions(fe->get_fe_type(), elem);
    1048     2697665 :   const auto & phi_map = fe->get_fe_map().get_phi_map();
    1049     2697665 :   const auto & dphidxi_map = fe->get_fe_map().get_dphidxi_map();
    1050     2697665 :   const auto & dphideta_map = fe->get_fe_map().get_dphideta_map();
    1051     2697665 :   const auto & dphidzeta_map = fe->get_fe_map().get_dphidzeta_map();
    1052     2697665 :   const auto sys_num = _sys.number();
    1053             :   const bool do_derivatives =
    1054     2697665 :       ADReal::do_derivatives && _sys.number() == _subproblem.currentNlSysNum();
    1055             : 
    1056     2697665 :   switch (dim)
    1057             :   {
    1058           0 :     case 0:
    1059             :     {
    1060           0 :       _ad_jac[p] = 1.0;
    1061           0 :       _ad_JxW[p] = qw[p];
    1062           0 :       if (_calculate_xyz)
    1063           0 :         _ad_q_points[p] = *elem_nodes[0];
    1064           0 :       break;
    1065             :     }
    1066             : 
    1067       62684 :     case 1:
    1068             :     {
    1069       62684 :       if (_calculate_xyz)
    1070       12502 :         _ad_q_points[p].zero();
    1071             : 
    1072       62684 :       _ad_dxyzdxi_map[p].zero();
    1073             : 
    1074      195972 :       for (std::size_t i = 0; i < num_shapes; i++)
    1075             :       {
    1076             :         libmesh_assert(elem_nodes[i]);
    1077      133288 :         const Node & node = *elem_nodes[i];
    1078      133288 :         libMesh::VectorValue<ADReal> elem_point = node;
    1079      133288 :         if (do_derivatives)
    1080       50772 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1081        2714 :             if (node.n_dofs(sys_num, disp_num))
    1082        5428 :               Moose::derivInsert(
    1083        2714 :                   elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1084             : 
    1085      133288 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1086             : 
    1087      133288 :         if (_calculate_xyz)
    1088       32924 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1089      133288 :       }
    1090             : 
    1091       62684 :       _ad_jac[p] = _ad_dxyzdxi_map[p].norm();
    1092             : 
    1093       62684 :       if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
    1094             :       {
    1095             :         static bool failing = false;
    1096           0 :         if (!failing)
    1097             :         {
    1098           0 :           failing = true;
    1099           0 :           elem->print_info(libMesh::err);
    1100           0 :           libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
    1101             :                                                         << p << " in element " << elem->id());
    1102             :         }
    1103             :         else
    1104           0 :           return;
    1105             :       }
    1106             : 
    1107       62684 :       const auto jacm2 = 1. / _ad_jac[p] / _ad_jac[p];
    1108       62684 :       _ad_dxidx_map[p] = jacm2 * _ad_dxyzdxi_map[p](0);
    1109       62684 :       _ad_dxidy_map[p] = jacm2 * _ad_dxyzdxi_map[p](1);
    1110       62684 :       _ad_dxidz_map[p] = jacm2 * _ad_dxyzdxi_map[p](2);
    1111             : 
    1112       62684 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1113             : 
    1114       62684 :       break;
    1115       62684 :     }
    1116             : 
    1117     2634981 :     case 2:
    1118             :     {
    1119     2634981 :       if (_calculate_xyz)
    1120     1903561 :         _ad_q_points[p].zero();
    1121     2634981 :       _ad_dxyzdxi_map[p].zero();
    1122     2634981 :       _ad_dxyzdeta_map[p].zero();
    1123             : 
    1124    16203878 :       for (std::size_t i = 0; i < num_shapes; i++)
    1125             :       {
    1126             :         libmesh_assert(elem_nodes[i]);
    1127    13568897 :         const Node & node = *elem_nodes[i];
    1128    13568897 :         libMesh::VectorValue<ADReal> elem_point = node;
    1129    13568897 :         if (do_derivatives)
    1130     1505152 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1131      146496 :             if (node.n_dofs(sys_num, disp_num))
    1132      292992 :               Moose::derivInsert(
    1133      146496 :                   elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1134             : 
    1135    13568897 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1136    13568897 :         _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
    1137             : 
    1138    13568897 :         if (_calculate_xyz)
    1139    11200209 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1140    13568897 :       }
    1141             : 
    1142     2634981 :       const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dx_deta = _ad_dxyzdeta_map[p](0),
    1143     2634981 :                  &dy_dxi = _ad_dxyzdxi_map[p](1), &dy_deta = _ad_dxyzdeta_map[p](1),
    1144     2634981 :                  &dz_dxi = _ad_dxyzdxi_map[p](2), &dz_deta = _ad_dxyzdeta_map[p](2);
    1145             : 
    1146     2634981 :       const auto g11 = (dx_dxi * dx_dxi + dy_dxi * dy_dxi + dz_dxi * dz_dxi);
    1147             : 
    1148     2634981 :       const auto g12 = (dx_dxi * dx_deta + dy_dxi * dy_deta + dz_dxi * dz_deta);
    1149             : 
    1150     2634981 :       const auto & g21 = g12;
    1151             : 
    1152     2634981 :       const auto g22 = (dx_deta * dx_deta + dy_deta * dy_deta + dz_deta * dz_deta);
    1153             : 
    1154     2634981 :       auto det = (g11 * g22 - g12 * g21);
    1155             : 
    1156     2634981 :       if (det.value() <= -TOLERANCE * TOLERANCE)
    1157             :       {
    1158             :         static bool failing = false;
    1159           0 :         if (!failing)
    1160             :         {
    1161           0 :           failing = true;
    1162           0 :           elem->print_info(libMesh::err);
    1163           0 :           libmesh_error_msg("ERROR: negative Jacobian " << det << " at point index " << p
    1164             :                                                         << " in element " << elem->id());
    1165             :         }
    1166             :         else
    1167           0 :           return;
    1168             :       }
    1169     2634981 :       else if (det.value() <= 0.)
    1170           0 :         det.value() = TOLERANCE * TOLERANCE;
    1171             : 
    1172     2634981 :       const auto inv_det = 1. / det;
    1173     2634981 :       _ad_jac[p] = std::sqrt(det);
    1174             : 
    1175     2634981 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1176             : 
    1177     2634981 :       const auto g11inv = g22 * inv_det;
    1178     2634981 :       const auto g12inv = -g12 * inv_det;
    1179     2634981 :       const auto g21inv = -g21 * inv_det;
    1180     2634981 :       const auto g22inv = g11 * inv_det;
    1181             : 
    1182     2634981 :       _ad_dxidx_map[p] = g11inv * dx_dxi + g12inv * dx_deta;
    1183     2634981 :       _ad_dxidy_map[p] = g11inv * dy_dxi + g12inv * dy_deta;
    1184     2634981 :       _ad_dxidz_map[p] = g11inv * dz_dxi + g12inv * dz_deta;
    1185             : 
    1186     2634981 :       _ad_detadx_map[p] = g21inv * dx_dxi + g22inv * dx_deta;
    1187     2634981 :       _ad_detady_map[p] = g21inv * dy_dxi + g22inv * dy_deta;
    1188     2634981 :       _ad_detadz_map[p] = g21inv * dz_dxi + g22inv * dz_deta;
    1189             : 
    1190     2634981 :       break;
    1191    13174905 :     }
    1192             : 
    1193           0 :     case 3:
    1194             :     {
    1195           0 :       if (_calculate_xyz)
    1196           0 :         _ad_q_points[p].zero();
    1197           0 :       _ad_dxyzdxi_map[p].zero();
    1198           0 :       _ad_dxyzdeta_map[p].zero();
    1199           0 :       _ad_dxyzdzeta_map[p].zero();
    1200             : 
    1201           0 :       for (std::size_t i = 0; i < num_shapes; i++)
    1202             :       {
    1203             :         libmesh_assert(elem_nodes[i]);
    1204           0 :         const Node & node = *elem_nodes[i];
    1205           0 :         libMesh::VectorValue<ADReal> elem_point = node;
    1206           0 :         if (do_derivatives)
    1207           0 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1208           0 :             if (node.n_dofs(sys_num, disp_num))
    1209           0 :               Moose::derivInsert(
    1210           0 :                   elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1211             : 
    1212           0 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1213           0 :         _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
    1214           0 :         _ad_dxyzdzeta_map[p].add_scaled(elem_point, dphidzeta_map[i][p]);
    1215             : 
    1216           0 :         if (_calculate_xyz)
    1217           0 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1218           0 :       }
    1219             : 
    1220           0 :       const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dy_dxi = _ad_dxyzdxi_map[p](1),
    1221           0 :                  &dz_dxi = _ad_dxyzdxi_map[p](2), &dx_deta = _ad_dxyzdeta_map[p](0),
    1222           0 :                  &dy_deta = _ad_dxyzdeta_map[p](1), &dz_deta = _ad_dxyzdeta_map[p](2),
    1223           0 :                  &dx_dzeta = _ad_dxyzdzeta_map[p](0), &dy_dzeta = _ad_dxyzdzeta_map[p](1),
    1224           0 :                  &dz_dzeta = _ad_dxyzdzeta_map[p](2);
    1225             : 
    1226           0 :       _ad_jac[p] = (dx_dxi * (dy_deta * dz_dzeta - dz_deta * dy_dzeta) +
    1227           0 :                     dy_dxi * (dz_deta * dx_dzeta - dx_deta * dz_dzeta) +
    1228           0 :                     dz_dxi * (dx_deta * dy_dzeta - dy_deta * dx_dzeta));
    1229             : 
    1230           0 :       if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
    1231             :       {
    1232             :         static bool failing = false;
    1233           0 :         if (!failing)
    1234             :         {
    1235           0 :           failing = true;
    1236           0 :           elem->print_info(libMesh::err);
    1237           0 :           libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
    1238             :                                                         << p << " in element " << elem->id());
    1239             :         }
    1240             :         else
    1241           0 :           return;
    1242             :       }
    1243             : 
    1244           0 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1245             : 
    1246           0 :       const auto inv_jac = 1. / _ad_jac[p];
    1247             : 
    1248           0 :       _ad_dxidx_map[p] = (dy_deta * dz_dzeta - dz_deta * dy_dzeta) * inv_jac;
    1249           0 :       _ad_dxidy_map[p] = (dz_deta * dx_dzeta - dx_deta * dz_dzeta) * inv_jac;
    1250           0 :       _ad_dxidz_map[p] = (dx_deta * dy_dzeta - dy_deta * dx_dzeta) * inv_jac;
    1251             : 
    1252           0 :       _ad_detadx_map[p] = (dz_dxi * dy_dzeta - dy_dxi * dz_dzeta) * inv_jac;
    1253           0 :       _ad_detady_map[p] = (dx_dxi * dz_dzeta - dz_dxi * dx_dzeta) * inv_jac;
    1254           0 :       _ad_detadz_map[p] = (dy_dxi * dx_dzeta - dx_dxi * dy_dzeta) * inv_jac;
    1255             : 
    1256           0 :       _ad_dzetadx_map[p] = (dy_dxi * dz_deta - dz_dxi * dy_deta) * inv_jac;
    1257           0 :       _ad_dzetady_map[p] = (dz_dxi * dx_deta - dx_dxi * dz_deta) * inv_jac;
    1258           0 :       _ad_dzetadz_map[p] = (dx_dxi * dy_deta - dy_dxi * dx_deta) * inv_jac;
    1259             : 
    1260           0 :       break;
    1261           0 :     }
    1262             : 
    1263           0 :     default:
    1264           0 :       libmesh_error_msg("Invalid dim = " << dim);
    1265             :   }
    1266             : }
    1267             : 
    1268             : void
    1269    11953620 : Assembly::reinitFEFace(const Elem * elem, unsigned int side)
    1270             : {
    1271    11953620 :   unsigned int dim = elem->dim();
    1272             : 
    1273    37969179 :   for (const auto & it : _fe_face[dim])
    1274             :   {
    1275    26015559 :     FEBase & fe_face = *it.second;
    1276    26015559 :     const FEType & fe_type = it.first;
    1277    26015559 :     FEShapeData & fesd = *_fe_shape_data_face[fe_type];
    1278    26015559 :     fe_face.reinit(elem, side);
    1279    26015559 :     _current_fe_face[fe_type] = &fe_face;
    1280             : 
    1281    26015559 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
    1282    26015559 :     fesd._grad_phi.shallowCopy(
    1283    26015559 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_dphi()));
    1284    26015559 :     if (_need_second_derivative.count(fe_type))
    1285       16216 :       fesd._second_phi.shallowCopy(
    1286       16216 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
    1287             :   }
    1288    14723830 :   for (const auto & it : _vector_fe_face[dim])
    1289             :   {
    1290     2770210 :     FEVectorBase & fe_face = *it.second;
    1291     2770210 :     const FEType & fe_type = it.first;
    1292             : 
    1293     2770210 :     _current_vector_fe_face[fe_type] = &fe_face;
    1294             : 
    1295     2770210 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
    1296             : 
    1297     2770210 :     fe_face.reinit(elem, side);
    1298             : 
    1299     2770210 :     fesd._phi.shallowCopy(
    1300     2770210 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
    1301     2770210 :     fesd._grad_phi.shallowCopy(
    1302     2770210 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
    1303     2770210 :     if (_need_second_derivative.count(fe_type))
    1304           0 :       fesd._second_phi.shallowCopy(
    1305           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
    1306     2770210 :     if (_need_curl.count(fe_type))
    1307      486265 :       fesd._curl_phi.shallowCopy(
    1308      486265 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
    1309     2770210 :     if (_need_face_div.count(fe_type))
    1310       37632 :       fesd._div_phi.shallowCopy(
    1311       37632 :           const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
    1312             :   }
    1313    11953620 :   if (!_unique_fe_face_helper.empty())
    1314             :   {
    1315             :     mooseAssert(dim < _unique_fe_face_helper.size(), "We should be in bounds here");
    1316      107270 :     _unique_fe_face_helper[dim]->reinit(elem, side);
    1317             :   }
    1318             : 
    1319             :   // During that last loop the helper objects will have been reinitialized as well
    1320             :   // We need to dig out the q_points and JxW from it.
    1321    11953620 :   _current_q_points_face.shallowCopy(
    1322    11953620 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_xyz()));
    1323    11953620 :   _current_JxW_face.shallowCopy(
    1324    11953620 :       const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_JxW()));
    1325    11953620 :   _current_normals.shallowCopy(
    1326    11953620 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_normals()));
    1327             : 
    1328    11953620 :   _mapped_normals.resize(_current_normals.size(), Eigen::Map<RealDIMValue>(nullptr));
    1329    38984236 :   for (unsigned int i = 0; i < _current_normals.size(); i++)
    1330             :     // Note: this does NOT do any allocation.  It is "reconstructing" the object in place
    1331    27030616 :     new (&_mapped_normals[i]) Eigen::Map<RealDIMValue>(const_cast<Real *>(&_current_normals[i](0)));
    1332             : 
    1333    11953620 :   if (_calculate_curvatures)
    1334         416 :     _curvatures.shallowCopy(
    1335         416 :         const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_curvatures()));
    1336             : 
    1337    11953620 :   computeADFace(*elem, side);
    1338             : 
    1339    11953620 :   if (_xfem != nullptr)
    1340           0 :     modifyFaceWeightsDueToXFEM(elem, side);
    1341             : 
    1342    11953620 :   auto n = numExtraElemIntegers();
    1343    12096740 :   for (auto i : make_range(n))
    1344      143120 :     _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
    1345    11953620 :   _extra_elem_ids[n] = _current_elem->subdomain_id();
    1346    11953620 : }
    1347             : 
    1348             : void
    1349       53788 : Assembly::computeFaceMap(const Elem & elem, const unsigned int side, const std::vector<Real> & qw)
    1350             : {
    1351             :   // Important quantities calculated by this method:
    1352             :   //   - _ad_JxW_face
    1353             :   //   - _ad_q_points_face
    1354             :   //   - _ad_normals
    1355             :   //   - _ad_curvatures
    1356             : 
    1357       53788 :   const Elem & side_elem = _compute_face_map_side_elem_builder(elem, side);
    1358       53788 :   const auto dim = elem.dim();
    1359       53788 :   const auto n_qp = qw.size();
    1360       53788 :   const auto & dpsidxi_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsidxi();
    1361       53788 :   const auto & dpsideta_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsideta();
    1362       53788 :   const auto & psi_map = _holder_fe_face_helper[dim]->get_fe_map().get_psi();
    1363       53788 :   std::vector<std::vector<Real>> const * d2psidxi2_map = nullptr;
    1364       53788 :   std::vector<std::vector<Real>> const * d2psidxideta_map = nullptr;
    1365       53788 :   std::vector<std::vector<Real>> const * d2psideta2_map = nullptr;
    1366       53788 :   const auto sys_num = _sys.number();
    1367       53788 :   const bool do_derivatives = ADReal::do_derivatives && sys_num == _subproblem.currentNlSysNum();
    1368             : 
    1369       53788 :   if (_calculate_curvatures)
    1370             :   {
    1371           0 :     d2psidxi2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxi2();
    1372           0 :     d2psidxideta_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxideta();
    1373           0 :     d2psideta2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psideta2();
    1374             :   }
    1375             : 
    1376       53788 :   switch (dim)
    1377             :   {
    1378         248 :     case 1:
    1379             :     {
    1380         248 :       if (!n_qp)
    1381           0 :         break;
    1382             : 
    1383         248 :       if (side_elem.node_id(0) == elem.node_id(0))
    1384         248 :         _ad_normals[0] = Point(-1.);
    1385             :       else
    1386           0 :         _ad_normals[0] = Point(1.);
    1387             : 
    1388         248 :       VectorValue<ADReal> side_point;
    1389         248 :       if (_calculate_face_xyz)
    1390             :       {
    1391         248 :         const Node & node = side_elem.node_ref(0);
    1392         248 :         side_point = node;
    1393             : 
    1394         248 :         if (do_derivatives)
    1395         112 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1396         112 :             Moose::derivInsert(
    1397          56 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1398             :       }
    1399             : 
    1400         496 :       for (const auto p : make_range(n_qp))
    1401             :       {
    1402         248 :         if (_calculate_face_xyz)
    1403             :         {
    1404         248 :           _ad_q_points_face[p].zero();
    1405         248 :           _ad_q_points_face[p].add_scaled(side_point, psi_map[0][p]);
    1406             :         }
    1407             : 
    1408         248 :         _ad_normals[p] = _ad_normals[0];
    1409         248 :         _ad_JxW_face[p] = 1.0 * qw[p];
    1410             :       }
    1411             : 
    1412         248 :       break;
    1413         248 :     }
    1414             : 
    1415       53540 :     case 2:
    1416             :     {
    1417       53540 :       _ad_dxyzdxi_map.resize(n_qp);
    1418       53540 :       if (_calculate_curvatures)
    1419           0 :         _ad_d2xyzdxi2_map.resize(n_qp);
    1420             : 
    1421      160620 :       for (const auto p : make_range(n_qp))
    1422      107080 :         _ad_dxyzdxi_map[p].zero();
    1423       53540 :       if (_calculate_face_xyz)
    1424       99504 :         for (const auto p : make_range(n_qp))
    1425       66336 :           _ad_q_points_face[p].zero();
    1426       53540 :       if (_calculate_curvatures)
    1427           0 :         for (const auto p : make_range(n_qp))
    1428           0 :           _ad_d2xyzdxi2_map[p].zero();
    1429             : 
    1430             :       const auto n_mapping_shape_functions =
    1431       53540 :           FE<2, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
    1432             : 
    1433      189420 :       for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
    1434             :       {
    1435      135880 :         const Node & node = side_elem.node_ref(i);
    1436      135880 :         VectorValue<ADReal> side_point = node;
    1437             : 
    1438      135880 :         if (do_derivatives)
    1439       38272 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1440           0 :             Moose::derivInsert(
    1441           0 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1442             : 
    1443      407640 :         for (const auto p : make_range(n_qp))
    1444      271760 :           _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
    1445      135880 :         if (_calculate_face_xyz)
    1446      285408 :           for (const auto p : make_range(n_qp))
    1447      190272 :             _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
    1448      135880 :         if (_calculate_curvatures)
    1449           0 :           for (const auto p : make_range(n_qp))
    1450           0 :             _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
    1451      135880 :       }
    1452             : 
    1453      160620 :       for (const auto p : make_range(n_qp))
    1454             :       {
    1455      107080 :         _ad_normals[p] =
    1456      214160 :             (VectorValue<ADReal>(_ad_dxyzdxi_map[p](1), -_ad_dxyzdxi_map[p](0), 0.)).unit();
    1457      107080 :         const auto the_jac = _ad_dxyzdxi_map[p].norm();
    1458      107080 :         _ad_JxW_face[p] = the_jac * qw[p];
    1459      107080 :         if (_calculate_curvatures)
    1460             :         {
    1461           0 :           const auto numerator = _ad_d2xyzdxi2_map[p] * _ad_normals[p];
    1462           0 :           const auto denominator = _ad_dxyzdxi_map[p].norm_sq();
    1463             :           libmesh_assert_not_equal_to(denominator, 0);
    1464           0 :           _ad_curvatures[p] = numerator / denominator;
    1465           0 :         }
    1466      107080 :       }
    1467             : 
    1468       53540 :       break;
    1469             :     }
    1470             : 
    1471           0 :     case 3:
    1472             :     {
    1473           0 :       _ad_dxyzdxi_map.resize(n_qp);
    1474           0 :       _ad_dxyzdeta_map.resize(n_qp);
    1475           0 :       if (_calculate_curvatures)
    1476             :       {
    1477           0 :         _ad_d2xyzdxi2_map.resize(n_qp);
    1478           0 :         _ad_d2xyzdxideta_map.resize(n_qp);
    1479           0 :         _ad_d2xyzdeta2_map.resize(n_qp);
    1480             :       }
    1481             : 
    1482           0 :       for (const auto p : make_range(n_qp))
    1483             :       {
    1484           0 :         _ad_dxyzdxi_map[p].zero();
    1485           0 :         _ad_dxyzdeta_map[p].zero();
    1486             :       }
    1487           0 :       if (_calculate_face_xyz)
    1488           0 :         for (const auto p : make_range(n_qp))
    1489           0 :           _ad_q_points_face[p].zero();
    1490           0 :       if (_calculate_curvatures)
    1491           0 :         for (const auto p : make_range(n_qp))
    1492             :         {
    1493           0 :           _ad_d2xyzdxi2_map[p].zero();
    1494           0 :           _ad_d2xyzdxideta_map[p].zero();
    1495           0 :           _ad_d2xyzdeta2_map[p].zero();
    1496             :         }
    1497             : 
    1498             :       const unsigned int n_mapping_shape_functions =
    1499           0 :           FE<3, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
    1500             : 
    1501           0 :       for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
    1502             :       {
    1503           0 :         const Node & node = side_elem.node_ref(i);
    1504           0 :         VectorValue<ADReal> side_point = node;
    1505             : 
    1506           0 :         if (do_derivatives)
    1507           0 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1508           0 :             Moose::derivInsert(
    1509           0 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1510             : 
    1511           0 :         for (const auto p : make_range(n_qp))
    1512             :         {
    1513           0 :           _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
    1514           0 :           _ad_dxyzdeta_map[p].add_scaled(side_point, dpsideta_map[i][p]);
    1515             :         }
    1516           0 :         if (_calculate_face_xyz)
    1517           0 :           for (const auto p : make_range(n_qp))
    1518           0 :             _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
    1519           0 :         if (_calculate_curvatures)
    1520           0 :           for (const auto p : make_range(n_qp))
    1521             :           {
    1522           0 :             _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
    1523           0 :             _ad_d2xyzdxideta_map[p].add_scaled(side_point, (*d2psidxideta_map)[i][p]);
    1524           0 :             _ad_d2xyzdeta2_map[p].add_scaled(side_point, (*d2psideta2_map)[i][p]);
    1525             :           }
    1526           0 :       }
    1527             : 
    1528           0 :       for (const auto p : make_range(n_qp))
    1529             :       {
    1530           0 :         _ad_normals[p] = _ad_dxyzdxi_map[p].cross(_ad_dxyzdeta_map[p]).unit();
    1531             : 
    1532           0 :         const auto &dxdxi = _ad_dxyzdxi_map[p](0), &dxdeta = _ad_dxyzdeta_map[p](0),
    1533           0 :                    &dydxi = _ad_dxyzdxi_map[p](1), &dydeta = _ad_dxyzdeta_map[p](1),
    1534           0 :                    &dzdxi = _ad_dxyzdxi_map[p](2), &dzdeta = _ad_dxyzdeta_map[p](2);
    1535             : 
    1536           0 :         const auto g11 = (dxdxi * dxdxi + dydxi * dydxi + dzdxi * dzdxi);
    1537             : 
    1538           0 :         const auto g12 = (dxdxi * dxdeta + dydxi * dydeta + dzdxi * dzdeta);
    1539             : 
    1540           0 :         const auto & g21 = g12;
    1541             : 
    1542           0 :         const auto g22 = (dxdeta * dxdeta + dydeta * dydeta + dzdeta * dzdeta);
    1543             : 
    1544           0 :         const auto the_jac = std::sqrt(g11 * g22 - g12 * g21);
    1545             : 
    1546           0 :         _ad_JxW_face[p] = the_jac * qw[p];
    1547             : 
    1548           0 :         if (_calculate_curvatures)
    1549             :         {
    1550           0 :           const auto L = -_ad_d2xyzdxi2_map[p] * _ad_normals[p];
    1551           0 :           const auto M = -_ad_d2xyzdxideta_map[p] * _ad_normals[p];
    1552           0 :           const auto N = -_ad_d2xyzdeta2_map[p] * _ad_normals[p];
    1553           0 :           const auto E = _ad_dxyzdxi_map[p].norm_sq();
    1554           0 :           const auto F = _ad_dxyzdxi_map[p] * _ad_dxyzdeta_map[p];
    1555           0 :           const auto G = _ad_dxyzdeta_map[p].norm_sq();
    1556             : 
    1557           0 :           const auto numerator = E * N - 2. * F * M + G * L;
    1558           0 :           const auto denominator = E * G - F * F;
    1559             :           libmesh_assert_not_equal_to(denominator, 0.);
    1560           0 :           _ad_curvatures[p] = 0.5 * numerator / denominator;
    1561           0 :         }
    1562           0 :       }
    1563             : 
    1564           0 :       break;
    1565             :     }
    1566             : 
    1567           0 :     default:
    1568           0 :       mooseError("Invalid dimension dim = ", dim);
    1569             :   }
    1570       53788 : }
    1571             : 
    1572             : void
    1573     4024111 : Assembly::reinitFEFaceNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1574             : {
    1575     4024111 :   unsigned int neighbor_dim = neighbor->dim();
    1576             : 
    1577             :   // reinit neighbor face
    1578    11784063 :   for (const auto & it : _fe_face_neighbor[neighbor_dim])
    1579             :   {
    1580     7759952 :     FEBase & fe_face_neighbor = *it.second;
    1581     7759952 :     FEType fe_type = it.first;
    1582     7759952 :     FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
    1583             : 
    1584     7759952 :     fe_face_neighbor.reinit(neighbor, &reference_points);
    1585             : 
    1586     7759952 :     _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    1587             : 
    1588     7759952 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
    1589     7759952 :     fesd._grad_phi.shallowCopy(
    1590     7759952 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
    1591     7759952 :     if (_need_second_derivative_neighbor.count(fe_type))
    1592        8640 :       fesd._second_phi.shallowCopy(
    1593        8640 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
    1594             :   }
    1595     4049976 :   for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
    1596             :   {
    1597       25865 :     FEVectorBase & fe_face_neighbor = *it.second;
    1598       25865 :     const FEType & fe_type = it.first;
    1599             : 
    1600       25865 :     _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    1601             : 
    1602       25865 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
    1603             : 
    1604       25865 :     fe_face_neighbor.reinit(neighbor, &reference_points);
    1605             : 
    1606       25865 :     fesd._phi.shallowCopy(
    1607       25865 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
    1608       25865 :     fesd._grad_phi.shallowCopy(
    1609       25865 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
    1610       25865 :     if (_need_second_derivative.count(fe_type))
    1611           0 :       fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
    1612           0 :           fe_face_neighbor.get_d2phi()));
    1613       25865 :     if (_need_curl.count(fe_type))
    1614         105 :       fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
    1615         105 :           fe_face_neighbor.get_curl_phi()));
    1616       25865 :     if (_need_face_neighbor_div.count(fe_type))
    1617           0 :       fesd._div_phi.shallowCopy(
    1618           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
    1619             :   }
    1620     4024111 :   if (!_unique_fe_face_neighbor_helper.empty())
    1621             :   {
    1622             :     mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
    1623             :                 "We should be in bounds here");
    1624       62324 :     _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
    1625             :   }
    1626             : 
    1627     4024111 :   _current_q_points_face_neighbor.shallowCopy(
    1628     4024111 :       const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
    1629     4024111 : }
    1630             : 
    1631             : void
    1632       19880 : Assembly::reinitFENeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1633             : {
    1634       19880 :   unsigned int neighbor_dim = neighbor->dim();
    1635             : 
    1636             :   // reinit neighbor face
    1637       39760 :   for (const auto & it : _fe_neighbor[neighbor_dim])
    1638             :   {
    1639       19880 :     FEBase & fe_neighbor = *it.second;
    1640       19880 :     FEType fe_type = it.first;
    1641       19880 :     FEShapeData & fesd = *_fe_shape_data_neighbor[fe_type];
    1642             : 
    1643       19880 :     fe_neighbor.reinit(neighbor, &reference_points);
    1644             : 
    1645       19880 :     _current_fe_neighbor[fe_type] = &fe_neighbor;
    1646             : 
    1647       19880 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_phi()));
    1648       19880 :     fesd._grad_phi.shallowCopy(
    1649       19880 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_neighbor.get_dphi()));
    1650       19880 :     if (_need_second_derivative_neighbor.count(fe_type))
    1651           0 :       fesd._second_phi.shallowCopy(
    1652           0 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_d2phi()));
    1653             :   }
    1654       19880 :   for (const auto & it : _vector_fe_neighbor[neighbor_dim])
    1655             :   {
    1656           0 :     FEVectorBase & fe_neighbor = *it.second;
    1657           0 :     const FEType & fe_type = it.first;
    1658             : 
    1659           0 :     _current_vector_fe_neighbor[fe_type] = &fe_neighbor;
    1660             : 
    1661           0 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_neighbor[fe_type];
    1662             : 
    1663           0 :     fe_neighbor.reinit(neighbor, &reference_points);
    1664             : 
    1665           0 :     fesd._phi.shallowCopy(
    1666           0 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_phi()));
    1667           0 :     fesd._grad_phi.shallowCopy(
    1668           0 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_dphi()));
    1669           0 :     if (_need_second_derivative.count(fe_type))
    1670           0 :       fesd._second_phi.shallowCopy(
    1671           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_neighbor.get_d2phi()));
    1672           0 :     if (_need_curl.count(fe_type))
    1673           0 :       fesd._curl_phi.shallowCopy(
    1674           0 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_curl_phi()));
    1675           0 :     if (_need_neighbor_div.count(fe_type))
    1676           0 :       fesd._div_phi.shallowCopy(
    1677           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_div_phi()));
    1678             :   }
    1679       19880 :   if (!_unique_fe_neighbor_helper.empty())
    1680             :   {
    1681             :     mooseAssert(neighbor_dim < _unique_fe_neighbor_helper.size(), "We should be in bounds here");
    1682           0 :     _unique_fe_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
    1683             :   }
    1684       19880 : }
    1685             : 
    1686             : void
    1687     4043991 : Assembly::reinitNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1688             : {
    1689     4043991 :   unsigned int neighbor_dim = neighbor->dim();
    1690             :   mooseAssert(_current_neighbor_subdomain_id == neighbor->subdomain_id(),
    1691             :               "Neighbor subdomain ID has not been correctly set");
    1692             : 
    1693             :   ArbitraryQuadrature * neighbor_rule =
    1694     4043991 :       qrules(neighbor_dim, _current_neighbor_subdomain_id).neighbor.get();
    1695     4043991 :   neighbor_rule->setPoints(reference_points);
    1696     4043991 :   setNeighborQRule(neighbor_rule, neighbor_dim);
    1697             : 
    1698     4043991 :   _current_neighbor_elem = neighbor;
    1699             :   mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
    1700             :               "current neighbor subdomain has been set incorrectly");
    1701             : 
    1702             :   // Calculate the volume of the neighbor
    1703     4043991 :   if (_need_neighbor_elem_volume)
    1704             :   {
    1705     2245686 :     unsigned int dim = neighbor->dim();
    1706     2245686 :     FEBase & fe = *_holder_fe_neighbor_helper[dim];
    1707     2245686 :     QBase * qrule = qrules(dim).vol.get();
    1708             : 
    1709     2245686 :     fe.attach_quadrature_rule(qrule);
    1710     2245686 :     fe.reinit(neighbor);
    1711             : 
    1712     2245686 :     const std::vector<Real> & JxW = fe.get_JxW();
    1713     2245686 :     MooseArray<Point> q_points;
    1714     2245686 :     q_points.shallowCopy(const_cast<std::vector<Point> &>(fe.get_xyz()));
    1715             : 
    1716     2245686 :     setCoordinateTransformation(qrule, q_points, _coord_neighbor, _current_neighbor_subdomain_id);
    1717             : 
    1718     2245686 :     _current_neighbor_volume = 0.;
    1719    19551269 :     for (unsigned int qp = 0; qp < qrule->n_points(); qp++)
    1720    17305583 :       _current_neighbor_volume += JxW[qp] * _coord_neighbor[qp];
    1721     2245686 :   }
    1722             : 
    1723     4043991 :   auto n = numExtraElemIntegers();
    1724     4124271 :   for (auto i : make_range(n))
    1725       80280 :     _neighbor_extra_elem_ids[i] = _current_neighbor_elem->get_extra_integer(i);
    1726     4043991 :   _neighbor_extra_elem_ids[n] = _current_neighbor_elem->subdomain_id();
    1727     4043991 : }
    1728             : 
    1729             : template <typename Points, typename Coords>
    1730             : void
    1731   425457703 : Assembly::setCoordinateTransformation(const QBase * qrule,
    1732             :                                       const Points & q_points,
    1733             :                                       Coords & coord,
    1734             :                                       SubdomainID sub_id)
    1735             : {
    1736             : 
    1737             :   mooseAssert(qrule, "The quadrature rule is null in Assembly::setCoordinateTransformation");
    1738   425457703 :   auto n_points = qrule->n_points();
    1739             :   mooseAssert(n_points == q_points.size(),
    1740             :               "The number of points in the quadrature rule doesn't match the number of passed-in "
    1741             :               "points in Assembly::setCoordinateTransformation");
    1742             : 
    1743             :   // Make sure to honor the name of this method and set the _coord_type member because users may
    1744             :   // make use of the const Moose::CoordinateSystem & coordTransformation() { return _coord_type; }
    1745             :   // API. MaterialBase for example uses it
    1746   425457703 :   _coord_type = _subproblem.getCoordSystem(sub_id);
    1747             : 
    1748   425457703 :   coord.resize(n_points);
    1749  2248630589 :   for (unsigned int qp = 0; qp < n_points; qp++)
    1750  1823172886 :     coordTransformFactor(_subproblem, sub_id, q_points[qp], coord[qp]);
    1751   425457703 : }
    1752             : 
    1753             : void
    1754   394339397 : Assembly::computeCurrentElemVolume()
    1755             : {
    1756   394339397 :   if (_current_elem_volume_computed)
    1757           0 :     return;
    1758             : 
    1759   394339397 :   setCoordinateTransformation(
    1760   394339397 :       _current_qrule, _current_q_points, _coord, _current_elem->subdomain_id());
    1761   394339397 :   if (_calculate_ad_coord)
    1762    12751991 :     setCoordinateTransformation(
    1763    12751991 :         _current_qrule, _ad_q_points, _ad_coord, _current_elem->subdomain_id());
    1764             : 
    1765   394339397 :   _current_elem_volume = 0.;
    1766  2113796998 :   for (unsigned int qp = 0; qp < _current_qrule->n_points(); qp++)
    1767  1719457601 :     _current_elem_volume += _current_JxW[qp] * _coord[qp];
    1768             : 
    1769   394339397 :   _current_elem_volume_computed = true;
    1770             : }
    1771             : 
    1772             : void
    1773    11953620 : Assembly::computeCurrentFaceVolume()
    1774             : {
    1775    11953620 :   if (_current_side_volume_computed)
    1776           0 :     return;
    1777             : 
    1778    11953620 :   setCoordinateTransformation(
    1779    11953620 :       _current_qrule_face, _current_q_points_face, _coord, _current_elem->subdomain_id());
    1780    11953620 :   if (_calculate_ad_coord)
    1781     3637669 :     setCoordinateTransformation(
    1782     3637669 :         _current_qrule_face, _ad_q_points_face, _ad_coord, _current_elem->subdomain_id());
    1783             : 
    1784    11953620 :   _current_side_volume = 0.;
    1785    38984236 :   for (unsigned int qp = 0; qp < _current_qrule_face->n_points(); qp++)
    1786    27030616 :     _current_side_volume += _current_JxW_face[qp] * _coord[qp];
    1787             : 
    1788    11953620 :   _current_side_volume_computed = true;
    1789             : }
    1790             : 
    1791             : void
    1792      351016 : Assembly::reinitAtPhysical(const Elem * elem, const std::vector<Point> & physical_points)
    1793             : {
    1794      351016 :   _current_elem = elem;
    1795      351016 :   _current_neighbor_elem = nullptr;
    1796             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1797             :               "current subdomain has been set incorrectly");
    1798      351016 :   _current_elem_volume_computed = false;
    1799             : 
    1800      351016 :   FEMap::inverse_map(elem->dim(), elem, physical_points, _temp_reference_points);
    1801             : 
    1802      351016 :   reinit(elem, _temp_reference_points);
    1803             : 
    1804             :   // Save off the physical points
    1805      351016 :   _current_physical_points = physical_points;
    1806      351016 : }
    1807             : 
    1808             : void
    1809   394062908 : Assembly::setVolumeQRule(const Elem * const elem)
    1810             : {
    1811   394062908 :   unsigned int elem_dimension = elem->dim();
    1812   394062908 :   _current_qrule_volume = qrules(elem_dimension).vol.get();
    1813             :   // Make sure the qrule is the right one
    1814   394062908 :   if (_current_qrule != _current_qrule_volume)
    1815      194730 :     setVolumeQRule(_current_qrule_volume, elem_dimension);
    1816   394062908 : }
    1817             : 
    1818             : void
    1819   393988409 : Assembly::reinit(const Elem * elem)
    1820             : {
    1821   393988409 :   _current_elem = elem;
    1822   393988409 :   _current_neighbor_elem = nullptr;
    1823             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1824             :               "current subdomain has been set incorrectly");
    1825   393988409 :   _current_elem_volume_computed = false;
    1826   393988409 :   if (_sc)
    1827      883838 :     _sc->set_current_elem(*elem);
    1828             : 
    1829   393988409 :   setVolumeQRule(elem);
    1830   393988409 :   reinitFE(elem);
    1831             : 
    1832   393988381 :   computeCurrentElemVolume();
    1833   393988381 : }
    1834             : 
    1835             : void
    1836      351016 : Assembly::reinit(const Elem * elem, const std::vector<Point> & reference_points)
    1837             : {
    1838      351016 :   _current_elem = elem;
    1839      351016 :   _current_neighbor_elem = nullptr;
    1840             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1841             :               "current subdomain has been set incorrectly");
    1842      351016 :   _current_elem_volume_computed = false;
    1843             : 
    1844      351016 :   unsigned int elem_dimension = _current_elem->dim();
    1845             : 
    1846      351016 :   _current_qrule_arbitrary = qrules(elem_dimension).arbitrary_vol.get();
    1847             : 
    1848             :   // Make sure the qrule is the right one
    1849      351016 :   if (_current_qrule != _current_qrule_arbitrary)
    1850       30911 :     setVolumeQRule(_current_qrule_arbitrary, elem_dimension);
    1851             : 
    1852      351016 :   _current_qrule_arbitrary->setPoints(reference_points);
    1853             : 
    1854      351016 :   reinitFE(elem);
    1855             : 
    1856      351016 :   computeCurrentElemVolume();
    1857      351016 : }
    1858             : 
    1859             : void
    1860    24516206 : Assembly::reinitFVFace(const FaceInfo & fi)
    1861             : {
    1862    24516206 :   _current_elem = &fi.elem();
    1863    24516206 :   _current_neighbor_elem = fi.neighborPtr();
    1864    24516206 :   _current_side = fi.elemSideID();
    1865    24516206 :   _current_neighbor_side = fi.neighborSideID();
    1866             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1867             :               "current subdomain has been set incorrectly");
    1868             : 
    1869    24516206 :   _current_elem_volume_computed = false;
    1870    24516206 :   _current_side_volume_computed = false;
    1871             : 
    1872    24516206 :   prepareResidual();
    1873    24516206 :   prepareNeighbor();
    1874    24516206 :   prepareJacobianBlock();
    1875             : 
    1876    24516206 :   unsigned int dim = _current_elem->dim();
    1877    24516206 :   if (_current_qrule_face != qrules(dim).fv_face.get())
    1878             :   {
    1879        5104 :     setFaceQRule(qrules(dim).fv_face.get(), dim);
    1880             :     // The order of the element that is used for initing here doesn't matter since this will just
    1881             :     // be used for constant monomials (which only need a single integration point)
    1882        5104 :     if (dim == 3)
    1883          12 :       _current_qrule_face->init(QUAD4, /* p_level = */ 0, /* simple_type_only = */ true);
    1884             :     else
    1885        5092 :       _current_qrule_face->init(EDGE2, /* p_level = */ 0, /* simple_type_only = */ true);
    1886             :   }
    1887             : 
    1888    24516206 :   _current_side_elem = &_current_side_elem_builder(*_current_elem, _current_side);
    1889             : 
    1890             :   mooseAssert(_current_qrule_face->n_points() == 1,
    1891             :               "Our finite volume quadrature rule should always yield a single point");
    1892             : 
    1893             :   // We've initialized the reference points. Now we need to compute the physical location of the
    1894             :   // quadrature points. We do not do any FE initialization so we cannot simply copy over FE
    1895             :   // results like we do in reinitFEFace. Instead we handle the computation of the physical
    1896             :   // locations manually
    1897    24516206 :   _current_q_points_face.resize(1);
    1898    24516206 :   const auto & ref_points = _current_qrule_face->get_points();
    1899    24516206 :   const auto & ref_point = ref_points[0];
    1900    24516206 :   auto physical_point = FEMap::map(_current_side_elem->dim(), _current_side_elem, ref_point);
    1901    24516206 :   _current_q_points_face[0] = physical_point;
    1902             : 
    1903    24516206 :   if (_current_neighbor_elem)
    1904             :   {
    1905             :     mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
    1906             :                 "current neighbor subdomain has been set incorrectly");
    1907             :     // Now handle the neighbor qrule/qpoints
    1908             :     ArbitraryQuadrature * const neighbor_rule =
    1909    22694094 :         qrules(_current_neighbor_elem->dim(), _current_neighbor_subdomain_id).neighbor.get();
    1910             :     // Here we are setting a reference point that is correct for the neighbor *side* element. It
    1911             :     // would be wrong if this reference point is used for a volumetric FE reinit with the neighbor
    1912    22694094 :     neighbor_rule->setPoints(ref_points);
    1913    22694094 :     setNeighborQRule(neighbor_rule, _current_neighbor_elem->dim());
    1914    22694094 :     _current_q_points_face_neighbor.resize(1);
    1915    22694094 :     _current_q_points_face_neighbor[0] = std::move(physical_point);
    1916             :   }
    1917    24516206 : }
    1918             : 
    1919             : QBase *
    1920    11953620 : Assembly::qruleFace(const Elem * elem, unsigned int side)
    1921             : {
    1922    24117378 :   return qruleFaceHelper<QBase>(elem, side, [](QRules & q) { return q.face.get(); });
    1923             : }
    1924             : 
    1925             : ArbitraryQuadrature *
    1926      283554 : Assembly::qruleArbitraryFace(const Elem * elem, unsigned int side)
    1927             : {
    1928      567108 :   return qruleFaceHelper<ArbitraryQuadrature>(
    1929      850662 :       elem, side, [](QRules & q) { return q.arbitrary_face.get(); });
    1930             : }
    1931             : 
    1932             : void
    1933    11953620 : Assembly::setFaceQRule(const Elem * const elem, const unsigned int side)
    1934             : {
    1935    11953620 :   const auto elem_dimension = elem->dim();
    1936             :   //// Make sure the qrule is the right one
    1937    11953620 :   auto rule = qruleFace(elem, side);
    1938    11953620 :   if (_current_qrule_face != rule)
    1939       11697 :     setFaceQRule(rule, elem_dimension);
    1940    11953620 : }
    1941             : 
    1942             : void
    1943    11953620 : Assembly::reinit(const Elem * const elem, const unsigned int side)
    1944             : {
    1945    11953620 :   _current_elem = elem;
    1946    11953620 :   _current_neighbor_elem = nullptr;
    1947             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1948             :               "current subdomain has been set incorrectly");
    1949    11953620 :   _current_side = side;
    1950    11953620 :   _current_elem_volume_computed = false;
    1951    11953620 :   _current_side_volume_computed = false;
    1952             : 
    1953    11953620 :   _current_side_elem = &_current_side_elem_builder(*elem, side);
    1954             : 
    1955    11953620 :   setFaceQRule(elem, side);
    1956    11953620 :   reinitFEFace(elem, side);
    1957             : 
    1958    11953620 :   computeCurrentFaceVolume();
    1959    11953620 : }
    1960             : 
    1961             : void
    1962           0 : Assembly::reinit(const Elem * elem, unsigned int side, const std::vector<Point> & reference_points)
    1963             : {
    1964           0 :   _current_elem = elem;
    1965           0 :   _current_neighbor_elem = nullptr;
    1966             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1967             :               "current subdomain has been set incorrectly");
    1968           0 :   _current_side = side;
    1969           0 :   _current_elem_volume_computed = false;
    1970           0 :   _current_side_volume_computed = false;
    1971             : 
    1972           0 :   unsigned int elem_dimension = _current_elem->dim();
    1973             : 
    1974           0 :   _current_qrule_arbitrary_face = qruleArbitraryFace(elem, side);
    1975             : 
    1976             :   // Make sure the qrule is the right one
    1977           0 :   if (_current_qrule_face != _current_qrule_arbitrary_face)
    1978           0 :     setFaceQRule(_current_qrule_arbitrary_face, elem_dimension);
    1979             : 
    1980           0 :   _current_qrule_arbitrary->setPoints(reference_points);
    1981             : 
    1982           0 :   _current_side_elem = &_current_side_elem_builder(*elem, side);
    1983             : 
    1984           0 :   reinitFEFace(elem, side);
    1985             : 
    1986           0 :   computeCurrentFaceVolume();
    1987           0 : }
    1988             : 
    1989             : void
    1990   106537100 : Assembly::reinit(const Node * node)
    1991             : {
    1992   106537100 :   _current_node = node;
    1993   106537100 :   _current_neighbor_node = NULL;
    1994   106537100 : }
    1995             : 
    1996             : void
    1997     3876795 : Assembly::reinitElemAndNeighbor(const Elem * elem,
    1998             :                                 unsigned int side,
    1999             :                                 const Elem * neighbor,
    2000             :                                 unsigned int neighbor_side,
    2001             :                                 const std::vector<Point> * neighbor_reference_points)
    2002             : {
    2003     3876795 :   _current_neighbor_side = neighbor_side;
    2004             : 
    2005     3876795 :   reinit(elem, side);
    2006             : 
    2007     3876795 :   unsigned int neighbor_dim = neighbor->dim();
    2008             : 
    2009     3876795 :   if (neighbor_reference_points)
    2010       64908 :     _current_neighbor_ref_points = *neighbor_reference_points;
    2011             :   else
    2012     3811887 :     FEMap::inverse_map(
    2013     7623774 :         neighbor_dim, neighbor, _current_q_points_face.stdVector(), _current_neighbor_ref_points);
    2014             : 
    2015     3876795 :   _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
    2016             : 
    2017     3876795 :   reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
    2018     3876795 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2019     3876795 : }
    2020             : 
    2021             : void
    2022      283554 : Assembly::reinitElemFaceRef(const Elem * elem,
    2023             :                             unsigned int elem_side,
    2024             :                             Real tolerance,
    2025             :                             const std::vector<Point> * const pts,
    2026             :                             const std::vector<Real> * const weights)
    2027             : {
    2028      283554 :   _current_elem = elem;
    2029             : 
    2030      283554 :   unsigned int elem_dim = elem->dim();
    2031             : 
    2032             :   // Attach the quadrature rules
    2033      283554 :   if (pts)
    2034             :   {
    2035      283554 :     auto face_rule = qruleArbitraryFace(elem, elem_side);
    2036      283554 :     face_rule->setPoints(*pts);
    2037      283554 :     setFaceQRule(face_rule, elem_dim);
    2038             :   }
    2039             :   else
    2040             :   {
    2041           0 :     auto rule = qruleFace(elem, elem_side);
    2042           0 :     if (_current_qrule_face != rule)
    2043           0 :       setFaceQRule(rule, elem_dim);
    2044             :   }
    2045             : 
    2046             :   // reinit face
    2047      671376 :   for (const auto & it : _fe_face[elem_dim])
    2048             :   {
    2049      387822 :     FEBase & fe_face = *it.second;
    2050      387822 :     FEType fe_type = it.first;
    2051      387822 :     FEShapeData & fesd = *_fe_shape_data_face[fe_type];
    2052             : 
    2053      387822 :     fe_face.reinit(elem, elem_side, tolerance, pts, weights);
    2054             : 
    2055      387822 :     _current_fe_face[fe_type] = &fe_face;
    2056             : 
    2057      387822 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
    2058      387822 :     fesd._grad_phi.shallowCopy(
    2059      387822 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face.get_dphi()));
    2060      387822 :     if (_need_second_derivative_neighbor.count(fe_type))
    2061           0 :       fesd._second_phi.shallowCopy(
    2062           0 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
    2063             :   }
    2064      283554 :   for (const auto & it : _vector_fe_face[elem_dim])
    2065             :   {
    2066           0 :     FEVectorBase & fe_face = *it.second;
    2067           0 :     const FEType & fe_type = it.first;
    2068             : 
    2069           0 :     _current_vector_fe_face[fe_type] = &fe_face;
    2070             : 
    2071           0 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
    2072             : 
    2073           0 :     fe_face.reinit(elem, elem_side, tolerance, pts, weights);
    2074             : 
    2075           0 :     fesd._phi.shallowCopy(
    2076           0 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
    2077           0 :     fesd._grad_phi.shallowCopy(
    2078           0 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
    2079           0 :     if (_need_second_derivative.count(fe_type))
    2080           0 :       fesd._second_phi.shallowCopy(
    2081           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
    2082           0 :     if (_need_curl.count(fe_type))
    2083           0 :       fesd._curl_phi.shallowCopy(
    2084           0 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
    2085           0 :     if (_need_face_div.count(fe_type))
    2086           0 :       fesd._div_phi.shallowCopy(
    2087           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
    2088             :   }
    2089      283554 :   if (!_unique_fe_face_helper.empty())
    2090             :   {
    2091             :     mooseAssert(elem_dim < _unique_fe_face_helper.size(), "We should be in bounds here");
    2092           0 :     _unique_fe_face_helper[elem_dim]->reinit(elem, elem_side, tolerance, pts, weights);
    2093             :   }
    2094             : 
    2095             :   // During that last loop the helper objects will have been reinitialized
    2096      283554 :   _current_q_points_face.shallowCopy(
    2097      283554 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_xyz()));
    2098      283554 :   _current_normals.shallowCopy(
    2099      283554 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_normals()));
    2100      283554 :   _current_tangents.shallowCopy(const_cast<std::vector<std::vector<Point>> &>(
    2101      283554 :       _holder_fe_face_helper[elem_dim]->get_tangents()));
    2102             :   // Note that if the user did pass in points and not weights to this method, JxW will be garbage
    2103             :   // and should not be used
    2104      283554 :   _current_JxW_face.shallowCopy(
    2105      283554 :       const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_JxW()));
    2106      283554 :   if (_calculate_curvatures)
    2107           0 :     _curvatures.shallowCopy(
    2108           0 :         const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_curvatures()));
    2109             : 
    2110      283554 :   computeADFace(*elem, elem_side);
    2111      283554 : }
    2112             : 
    2113             : void
    2114    12237174 : Assembly::computeADFace(const Elem & elem, const unsigned int side)
    2115             : {
    2116    12237174 :   const auto dim = elem.dim();
    2117             : 
    2118    12237174 :   if (_subproblem.haveADObjects())
    2119             :   {
    2120     4089390 :     auto n_qp = _current_qrule_face->n_points();
    2121     4089390 :     resizeADMappingObjects(n_qp, dim);
    2122     4089390 :     _ad_normals.resize(n_qp);
    2123     4089390 :     _ad_JxW_face.resize(n_qp);
    2124     4089390 :     if (_calculate_face_xyz)
    2125     3655617 :       _ad_q_points_face.resize(n_qp);
    2126     4089390 :     if (_calculate_curvatures)
    2127         416 :       _ad_curvatures.resize(n_qp);
    2128             : 
    2129     4089390 :     if (_displaced)
    2130             :     {
    2131       53788 :       const auto & qw = _current_qrule_face->get_weights();
    2132       53788 :       computeFaceMap(elem, side, qw);
    2133       53788 :       const std::vector<Real> dummy_qw(n_qp, 1.);
    2134             : 
    2135      161116 :       for (unsigned int qp = 0; qp != n_qp; qp++)
    2136      107328 :         computeSinglePointMapAD(&elem, dummy_qw, qp, _holder_fe_face_helper[dim]);
    2137       53788 :     }
    2138             :     else
    2139             :     {
    2140    12836956 :       for (unsigned qp = 0; qp < n_qp; ++qp)
    2141             :       {
    2142     8801354 :         _ad_JxW_face[qp] = _current_JxW_face[qp];
    2143     8801354 :         _ad_normals[qp] = _current_normals[qp];
    2144             :       }
    2145     4035602 :       if (_calculate_face_xyz)
    2146    11156515 :         for (unsigned qp = 0; qp < n_qp; ++qp)
    2147     7534314 :           _ad_q_points_face[qp] = _current_q_points_face[qp];
    2148     4035602 :       if (_calculate_curvatures)
    2149         832 :         for (unsigned qp = 0; qp < n_qp; ++qp)
    2150         416 :           _ad_curvatures[qp] = _curvatures[qp];
    2151             :     }
    2152             : 
    2153    13010932 :     for (const auto & it : _fe_face[dim])
    2154             :     {
    2155     8921542 :       FEBase & fe = *it.second;
    2156     8921542 :       auto fe_type = it.first;
    2157     8921542 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
    2158     8921542 :       auto & grad_phi = _ad_grad_phi_data_face[fe_type];
    2159             : 
    2160     8921542 :       grad_phi.resize(num_shapes);
    2161    66260802 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2162    57339260 :         grad_phi[i].resize(n_qp);
    2163             : 
    2164     8921542 :       const auto & regular_grad_phi = _fe_shape_data_face[fe_type]->_grad_phi;
    2165             : 
    2166     8921542 :       if (_displaced)
    2167      131456 :         computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
    2168             :       else
    2169    65442702 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2170   187861180 :           for (unsigned qp = 0; qp < n_qp; ++qp)
    2171   131208564 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
    2172             :     }
    2173     4588203 :     for (const auto & it : _vector_fe_face[dim])
    2174             :     {
    2175      498813 :       FEVectorBase & fe = *it.second;
    2176      498813 :       auto fe_type = it.first;
    2177      498813 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
    2178      498813 :       auto & grad_phi = _ad_vector_grad_phi_data_face[fe_type];
    2179             : 
    2180      498813 :       grad_phi.resize(num_shapes);
    2181     2621137 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2182     2122324 :         grad_phi[i].resize(n_qp);
    2183             : 
    2184      498813 :       const auto & regular_grad_phi = _vector_fe_shape_data_face[fe_type]->_grad_phi;
    2185             : 
    2186      498813 :       if (_displaced)
    2187           0 :         computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
    2188             :       else
    2189     2621137 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2190     6480120 :           for (unsigned qp = 0; qp < n_qp; ++qp)
    2191     4357796 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
    2192             :     }
    2193             :   }
    2194    12237174 : }
    2195             : 
    2196             : void
    2197      283554 : Assembly::reinitNeighborFaceRef(const Elem * neighbor,
    2198             :                                 unsigned int neighbor_side,
    2199             :                                 Real tolerance,
    2200             :                                 const std::vector<Point> * const pts,
    2201             :                                 const std::vector<Real> * const weights)
    2202             : {
    2203      283554 :   _current_neighbor_elem = neighbor;
    2204             : 
    2205      283554 :   unsigned int neighbor_dim = neighbor->dim();
    2206             : 
    2207             :   ArbitraryQuadrature * neighbor_rule =
    2208      283554 :       qrules(neighbor_dim, neighbor->subdomain_id()).neighbor.get();
    2209      283554 :   neighbor_rule->setPoints(*pts);
    2210             : 
    2211             :   // Attach this quadrature rule to all the _fe_face_neighbor FE objects. This
    2212             :   // has to have garbage quadrature weights but that's ok because we never
    2213             :   // actually use the JxW coming from these FE reinit'd objects, e.g. we use the
    2214             :   // JxW coming from the element face reinit for DGKernels or we use the JxW
    2215             :   // coming from reinit of the mortar segment element in the case of mortar
    2216      283554 :   setNeighborQRule(neighbor_rule, neighbor_dim);
    2217             : 
    2218             :   // reinit neighbor face
    2219      671376 :   for (const auto & it : _fe_face_neighbor[neighbor_dim])
    2220             :   {
    2221      387822 :     FEBase & fe_face_neighbor = *it.second;
    2222      387822 :     FEType fe_type = it.first;
    2223      387822 :     FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
    2224             : 
    2225      387822 :     fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
    2226             : 
    2227      387822 :     _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    2228             : 
    2229      387822 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
    2230      387822 :     fesd._grad_phi.shallowCopy(
    2231      387822 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
    2232      387822 :     if (_need_second_derivative_neighbor.count(fe_type))
    2233           0 :       fesd._second_phi.shallowCopy(
    2234           0 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
    2235             :   }
    2236      283554 :   for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
    2237             :   {
    2238           0 :     FEVectorBase & fe_face_neighbor = *it.second;
    2239           0 :     const FEType & fe_type = it.first;
    2240             : 
    2241           0 :     _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    2242             : 
    2243           0 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
    2244             : 
    2245           0 :     fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
    2246             : 
    2247           0 :     fesd._phi.shallowCopy(
    2248           0 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
    2249           0 :     fesd._grad_phi.shallowCopy(
    2250           0 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
    2251           0 :     if (_need_second_derivative.count(fe_type))
    2252           0 :       fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
    2253           0 :           fe_face_neighbor.get_d2phi()));
    2254           0 :     if (_need_curl.count(fe_type))
    2255           0 :       fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
    2256           0 :           fe_face_neighbor.get_curl_phi()));
    2257           0 :     if (_need_face_neighbor_div.count(fe_type))
    2258           0 :       fesd._div_phi.shallowCopy(
    2259           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
    2260             :   }
    2261      283554 :   if (!_unique_fe_face_neighbor_helper.empty())
    2262             :   {
    2263             :     mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
    2264             :                 "We should be in bounds here");
    2265           0 :     _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(
    2266             :         neighbor, neighbor_side, tolerance, pts, weights);
    2267             :   }
    2268             :   // During that last loop the helper objects will have been reinitialized as well
    2269             :   // We need to dig out the q_points from it
    2270      283554 :   _current_q_points_face_neighbor.shallowCopy(
    2271      283554 :       const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
    2272      283554 : }
    2273             : 
    2274             : void
    2275        4057 : Assembly::reinitDual(const Elem * elem,
    2276             :                      const std::vector<Point> & pts,
    2277             :                      const std::vector<Real> & JxW)
    2278             : {
    2279        4057 :   const unsigned int elem_dim = elem->dim();
    2280             :   mooseAssert(elem_dim == _mesh_dimension - 1,
    2281             :               "Dual shape functions should only be computed on lower dimensional face elements");
    2282             : 
    2283        8390 :   for (const auto & it : _fe_lower[elem_dim])
    2284             :   {
    2285        4333 :     FEBase & fe_lower = *it.second;
    2286             :     // We use customized quadrature rule for integration along the mortar segment elements
    2287        4333 :     fe_lower.set_calculate_default_dual_coeff(false);
    2288        4333 :     fe_lower.reinit_dual_shape_coeffs(elem, pts, JxW);
    2289             :   }
    2290        4057 : }
    2291             : 
    2292             : void
    2293      299795 : Assembly::reinitLowerDElem(const Elem * elem,
    2294             :                            const std::vector<Point> * const pts,
    2295             :                            const std::vector<Real> * const weights)
    2296             : {
    2297      299795 :   _current_lower_d_elem = elem;
    2298             : 
    2299      299795 :   const unsigned int elem_dim = elem->dim();
    2300             :   mooseAssert(elem_dim < _mesh_dimension,
    2301             :               "The lower dimensional element should truly be a lower dimensional element");
    2302             : 
    2303      299795 :   if (pts)
    2304             :   {
    2305             :     // Lower rule matches the face rule for the higher dimensional element
    2306      263086 :     ArbitraryQuadrature * lower_rule = qrules(elem_dim + 1).arbitrary_face.get();
    2307             : 
    2308             :     // This also sets the quadrature weights to unity
    2309      263086 :     lower_rule->setPoints(*pts);
    2310             : 
    2311      263086 :     if (weights)
    2312           0 :       lower_rule->setWeights(*weights);
    2313             : 
    2314      263086 :     setLowerQRule(lower_rule, elem_dim);
    2315             :   }
    2316       36709 :   else if (_current_qrule_lower != qrules(elem_dim + 1).face.get())
    2317         429 :     setLowerQRule(qrules(elem_dim + 1).face.get(), elem_dim);
    2318             : 
    2319      740084 :   for (const auto & it : _fe_lower[elem_dim])
    2320             :   {
    2321      440289 :     FEBase & fe_lower = *it.second;
    2322      440289 :     FEType fe_type = it.first;
    2323             : 
    2324      440289 :     fe_lower.reinit(elem);
    2325             : 
    2326      440289 :     if (FEShapeData * fesd = _fe_shape_data_lower[fe_type].get())
    2327             :     {
    2328      440289 :       fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_phi()));
    2329      440289 :       fesd->_grad_phi.shallowCopy(
    2330      440289 :           const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dphi()));
    2331      440289 :       if (_need_second_derivative_neighbor.count(fe_type))
    2332           0 :         fesd->_second_phi.shallowCopy(
    2333           0 :             const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_d2phi()));
    2334             :     }
    2335             : 
    2336             :     // Dual shape functions need to be computed after primal basis being initialized
    2337      440289 :     if (FEShapeData * fesd = _fe_shape_data_dual_lower[fe_type].get())
    2338             :     {
    2339       12142 :       fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_dual_phi()));
    2340       12142 :       fesd->_grad_phi.shallowCopy(
    2341       12142 :           const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dual_dphi()));
    2342       12142 :       if (_need_second_derivative_neighbor.count(fe_type))
    2343           0 :         fesd->_second_phi.shallowCopy(
    2344           0 :             const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_dual_d2phi()));
    2345             :     }
    2346             :   }
    2347      299795 :   if (!_unique_fe_lower_helper.empty())
    2348             :   {
    2349             :     mooseAssert(elem_dim < _unique_fe_lower_helper.size(), "We should be in bounds here");
    2350           0 :     _unique_fe_lower_helper[elem_dim]->reinit(elem);
    2351             :   }
    2352             : 
    2353      299795 :   if (!_need_lower_d_elem_volume)
    2354      199345 :     return;
    2355             : 
    2356      100450 :   if (pts && !weights)
    2357             :   {
    2358             :     // We only have dummy weights so the JxWs computed during our FE reinits are meaningless and
    2359             :     // we cannot use them
    2360             : 
    2361       97282 :     if (_subproblem.getCoordSystem(elem->subdomain_id()) == Moose::CoordinateSystemType::COORD_XYZ)
    2362             :       // We are in a Cartesian coordinate system and we can just use the element volume method
    2363             :       // which has fast computation for certain element types
    2364       97282 :       _current_lower_d_elem_volume = elem->volume();
    2365             :     else
    2366             :       // We manually compute the volume taking the curvilinear coordinate transformations into
    2367             :       // account
    2368           0 :       _current_lower_d_elem_volume = elementVolume(elem);
    2369             :   }
    2370             :   else
    2371             :   {
    2372             :     // During that last loop the helper objects will have been reinitialized as well
    2373        3168 :     FEBase & helper_fe = *_holder_fe_lower_helper[elem_dim];
    2374        3168 :     const auto & physical_q_points = helper_fe.get_xyz();
    2375        3168 :     const auto & JxW = helper_fe.get_JxW();
    2376        3168 :     MooseArray<Real> coord;
    2377        3168 :     setCoordinateTransformation(
    2378        3168 :         _current_qrule_lower, physical_q_points, coord, elem->subdomain_id());
    2379        3168 :     _current_lower_d_elem_volume = 0;
    2380       46944 :     for (const auto qp : make_range(_current_qrule_lower->n_points()))
    2381       43776 :       _current_lower_d_elem_volume += JxW[qp] * coord[qp];
    2382        3168 :   }
    2383             : }
    2384             : 
    2385             : void
    2386      263086 : Assembly::reinitNeighborLowerDElem(const Elem * elem)
    2387             : {
    2388             :   mooseAssert(elem->dim() < _mesh_dimension,
    2389             :               "You should be calling reinitNeighborLowerDElem on a lower dimensional element");
    2390             : 
    2391      263086 :   _current_neighbor_lower_d_elem = elem;
    2392             : 
    2393      263086 :   if (!_need_neighbor_lower_d_elem_volume)
    2394      165804 :     return;
    2395             : 
    2396       97282 :   if (_subproblem.getCoordSystem(elem->subdomain_id()) == Moose::CoordinateSystemType::COORD_XYZ)
    2397             :     // We are in a Cartesian coordinate system and we can just use the element volume method which
    2398             :     // has fast computation for certain element types
    2399       97282 :     _current_neighbor_lower_d_elem_volume = elem->volume();
    2400             :   else
    2401             :     // We manually compute the volume taking the curvilinear coordinate transformations into
    2402             :     // account
    2403           0 :     _current_neighbor_lower_d_elem_volume = elementVolume(elem);
    2404             : }
    2405             : 
    2406             : void
    2407      526172 : Assembly::reinitMortarElem(const Elem * elem)
    2408             : {
    2409             :   mooseAssert(elem->dim() == _mesh_dimension - 1,
    2410             :               "You should be calling reinitMortarElem on a lower dimensional element");
    2411             : 
    2412      526172 :   _fe_msm->reinit(elem);
    2413      526172 :   _msm_elem = elem;
    2414             : 
    2415      526172 :   MooseArray<Point> array_q_points;
    2416      526172 :   array_q_points.shallowCopy(const_cast<std::vector<Point> &>(_fe_msm->get_xyz()));
    2417      526172 :   setCoordinateTransformation(_qrule_msm, array_q_points, _coord_msm, elem->subdomain_id());
    2418      526172 : }
    2419             : 
    2420             : void
    2421      147316 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
    2422             :                                    unsigned int neighbor_side,
    2423             :                                    const std::vector<Point> & physical_points)
    2424             : {
    2425      147316 :   unsigned int neighbor_dim = neighbor->dim();
    2426      147316 :   FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
    2427             : 
    2428      147316 :   if (_need_JxW_neighbor)
    2429             :   {
    2430             :     mooseAssert(
    2431             :         physical_points.size() == 1,
    2432             :         "If reinitializing with more than one point, then I am dubious of your use case. Perhaps "
    2433             :         "you are performing a DG type method and you are reinitializing using points from the "
    2434             :         "element face. In such a case your neighbor JxW must have its index order 'match' the "
    2435             :         "element JxW index order, e.g. imagining a vertical 1D face with two quadrature points, "
    2436             :         "if "
    2437             :         "index 0 for elem JxW corresponds to the 'top' quadrature point, then index 0 for "
    2438             :         "neighbor "
    2439             :         "JxW must also correspond to the 'top' quadrature point. And libMesh/MOOSE has no way to "
    2440             :         "guarantee that with multiple quadrature points.");
    2441             : 
    2442       96052 :     _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
    2443             : 
    2444             :     // With a single point our size-1 JxW should just be the element volume
    2445       96052 :     _current_JxW_neighbor.resize(1);
    2446       96052 :     _current_JxW_neighbor[0] = _current_neighbor_side_elem->volume();
    2447             :   }
    2448             : 
    2449      147316 :   reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
    2450      147316 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2451             : 
    2452             :   // Save off the physical points
    2453      147316 :   _current_physical_points = physical_points;
    2454      147316 : }
    2455             : 
    2456             : void
    2457       19880 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
    2458             :                                    const std::vector<Point> & physical_points)
    2459             : {
    2460       19880 :   unsigned int neighbor_dim = neighbor->dim();
    2461       19880 :   FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
    2462             : 
    2463       19880 :   reinitFENeighbor(neighbor, _current_neighbor_ref_points);
    2464       19880 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2465             :   // Save off the physical points
    2466       19880 :   _current_physical_points = physical_points;
    2467       19880 : }
    2468             : 
    2469             : void
    2470       63135 : Assembly::init(const CouplingMatrix * cm)
    2471             : {
    2472       63135 :   _cm = cm;
    2473             : 
    2474       63135 :   unsigned int n_vars = _sys.nVariables();
    2475             : 
    2476       63135 :   _cm_ss_entry.clear();
    2477       63135 :   _cm_sf_entry.clear();
    2478       63135 :   _cm_fs_entry.clear();
    2479       63135 :   _cm_ff_entry.clear();
    2480             : 
    2481       63135 :   auto & vars = _sys.getVariables(_tid);
    2482             : 
    2483       63135 :   _block_diagonal_matrix = true;
    2484      127183 :   for (auto & ivar : vars)
    2485             :   {
    2486       64048 :     auto i = ivar->number();
    2487       64048 :     if (i >= _component_block_diagonal.size())
    2488       64048 :       _component_block_diagonal.resize(i + 1, true);
    2489             : 
    2490       64048 :     auto ivar_start = _cm_ff_entry.size();
    2491      129709 :     for (unsigned int k = 0; k < ivar->count(); ++k)
    2492             :     {
    2493       65661 :       unsigned int iv = i + k;
    2494      153922 :       for (const auto & j : ConstCouplingRow(iv, *_cm))
    2495             :       {
    2496       88261 :         if (_sys.isScalarVariable(j))
    2497             :         {
    2498        1090 :           auto & jvar = _sys.getScalarVariable(_tid, j);
    2499        1090 :           _cm_fs_entry.push_back(std::make_pair(ivar, &jvar));
    2500        1090 :           _block_diagonal_matrix = false;
    2501             :         }
    2502             :         else
    2503             :         {
    2504       87171 :           auto & jvar = _sys.getVariable(_tid, j);
    2505       87171 :           auto pair = std::make_pair(ivar, &jvar);
    2506       87171 :           auto c = ivar_start;
    2507             :           // check if the pair has been pushed or not
    2508       87171 :           bool has_pair = false;
    2509      114105 :           for (; c < _cm_ff_entry.size(); ++c)
    2510       32627 :             if (_cm_ff_entry[c] == pair)
    2511             :             {
    2512        5693 :               has_pair = true;
    2513        5693 :               break;
    2514             :             }
    2515       87171 :           if (!has_pair)
    2516       81478 :             _cm_ff_entry.push_back(pair);
    2517             :           // only set having diagonal matrix to false when ivar and jvar numbers are different
    2518             :           // Note: for array variables, since we save the entire local Jacobian of all components,
    2519             :           //       even there are couplings among components of the same array variable, we still
    2520             :           //       do not set the flag to false.
    2521       87171 :           if (i != jvar.number())
    2522       19896 :             _block_diagonal_matrix = false;
    2523       67275 :           else if (iv != j)
    2524        1614 :             _component_block_diagonal[i] = false;
    2525             :         }
    2526             :       }
    2527             :     }
    2528             :   }
    2529             : 
    2530       63135 :   auto & scalar_vars = _sys.getScalarVariables(_tid);
    2531             : 
    2532       64561 :   for (auto & ivar : scalar_vars)
    2533             :   {
    2534        1426 :     auto i = ivar->number();
    2535        1426 :     if (i >= _component_block_diagonal.size())
    2536        1352 :       _component_block_diagonal.resize(i + 1, true);
    2537             : 
    2538        4078 :     for (const auto & j : ConstCouplingRow(i, *_cm))
    2539        2652 :       if (_sys.isScalarVariable(j))
    2540             :       {
    2541        1562 :         auto & jvar = _sys.getScalarVariable(_tid, j);
    2542        1562 :         _cm_ss_entry.push_back(std::make_pair(ivar, &jvar));
    2543             :       }
    2544             :       else
    2545             :       {
    2546        1090 :         auto & jvar = _sys.getVariable(_tid, j);
    2547        1090 :         _cm_sf_entry.push_back(std::make_pair(ivar, &jvar));
    2548             :       }
    2549             :   }
    2550             : 
    2551       63135 :   if (_block_diagonal_matrix && scalar_vars.size() != 0)
    2552         443 :     _block_diagonal_matrix = false;
    2553             : 
    2554       63135 :   auto num_vector_tags = _residual_vector_tags.size();
    2555             : 
    2556       63135 :   _sub_Re.resize(num_vector_tags);
    2557       63135 :   _sub_Rn.resize(num_vector_tags);
    2558       63135 :   _sub_Rl.resize(num_vector_tags);
    2559      224372 :   for (MooseIndex(_sub_Re) i = 0; i < _sub_Re.size(); i++)
    2560             :   {
    2561      161237 :     _sub_Re[i].resize(n_vars);
    2562      161237 :     _sub_Rn[i].resize(n_vars);
    2563      161237 :     _sub_Rl[i].resize(n_vars);
    2564             :   }
    2565             : 
    2566       63135 :   _cached_residual_values.resize(num_vector_tags);
    2567       63135 :   _cached_residual_rows.resize(num_vector_tags);
    2568             : 
    2569       63135 :   auto num_matrix_tags = _subproblem.numMatrixTags();
    2570             : 
    2571       63135 :   _cached_jacobian_values.resize(num_matrix_tags);
    2572       63135 :   _cached_jacobian_rows.resize(num_matrix_tags);
    2573       63135 :   _cached_jacobian_cols.resize(num_matrix_tags);
    2574             : 
    2575             :   // Element matrices
    2576       63135 :   _sub_Kee.resize(num_matrix_tags);
    2577       63135 :   _sub_Keg.resize(num_matrix_tags);
    2578       63135 :   _sub_Ken.resize(num_matrix_tags);
    2579       63135 :   _sub_Kne.resize(num_matrix_tags);
    2580       63135 :   _sub_Knn.resize(num_matrix_tags);
    2581       63135 :   _sub_Kll.resize(num_matrix_tags);
    2582       63135 :   _sub_Kle.resize(num_matrix_tags);
    2583       63135 :   _sub_Kln.resize(num_matrix_tags);
    2584       63135 :   _sub_Kel.resize(num_matrix_tags);
    2585       63135 :   _sub_Knl.resize(num_matrix_tags);
    2586             : 
    2587       63135 :   _jacobian_block_used.resize(num_matrix_tags);
    2588       63135 :   _jacobian_block_neighbor_used.resize(num_matrix_tags);
    2589       63135 :   _jacobian_block_lower_used.resize(num_matrix_tags);
    2590       63135 :   _jacobian_block_nonlocal_used.resize(num_matrix_tags);
    2591             : 
    2592      191692 :   for (MooseIndex(num_matrix_tags) tag = 0; tag < num_matrix_tags; tag++)
    2593             :   {
    2594      128557 :     _sub_Keg[tag].resize(n_vars);
    2595      128557 :     _sub_Ken[tag].resize(n_vars);
    2596      128557 :     _sub_Kne[tag].resize(n_vars);
    2597      128557 :     _sub_Knn[tag].resize(n_vars);
    2598      128557 :     _sub_Kee[tag].resize(n_vars);
    2599      128557 :     _sub_Kll[tag].resize(n_vars);
    2600      128557 :     _sub_Kle[tag].resize(n_vars);
    2601      128557 :     _sub_Kln[tag].resize(n_vars);
    2602      128557 :     _sub_Kel[tag].resize(n_vars);
    2603      128557 :     _sub_Knl[tag].resize(n_vars);
    2604             : 
    2605      128557 :     _jacobian_block_used[tag].resize(n_vars);
    2606      128557 :     _jacobian_block_neighbor_used[tag].resize(n_vars);
    2607      128557 :     _jacobian_block_lower_used[tag].resize(n_vars);
    2608      128557 :     _jacobian_block_nonlocal_used[tag].resize(n_vars);
    2609      266295 :     for (MooseIndex(n_vars) i = 0; i < n_vars; ++i)
    2610             :     {
    2611      137738 :       if (!_block_diagonal_matrix)
    2612             :       {
    2613       32056 :         _sub_Kee[tag][i].resize(n_vars);
    2614       32056 :         _sub_Keg[tag][i].resize(n_vars);
    2615       32056 :         _sub_Ken[tag][i].resize(n_vars);
    2616       32056 :         _sub_Kne[tag][i].resize(n_vars);
    2617       32056 :         _sub_Knn[tag][i].resize(n_vars);
    2618       32056 :         _sub_Kll[tag][i].resize(n_vars);
    2619       32056 :         _sub_Kle[tag][i].resize(n_vars);
    2620       32056 :         _sub_Kln[tag][i].resize(n_vars);
    2621       32056 :         _sub_Kel[tag][i].resize(n_vars);
    2622       32056 :         _sub_Knl[tag][i].resize(n_vars);
    2623             : 
    2624       32056 :         _jacobian_block_used[tag][i].resize(n_vars);
    2625       32056 :         _jacobian_block_neighbor_used[tag][i].resize(n_vars);
    2626       32056 :         _jacobian_block_lower_used[tag][i].resize(n_vars);
    2627       32056 :         _jacobian_block_nonlocal_used[tag][i].resize(n_vars);
    2628             :       }
    2629             :       else
    2630             :       {
    2631      105682 :         _sub_Kee[tag][i].resize(1);
    2632      105682 :         _sub_Keg[tag][i].resize(1);
    2633      105682 :         _sub_Ken[tag][i].resize(1);
    2634      105682 :         _sub_Kne[tag][i].resize(1);
    2635      105682 :         _sub_Knn[tag][i].resize(1);
    2636      105682 :         _sub_Kll[tag][i].resize(1);
    2637      105682 :         _sub_Kle[tag][i].resize(1);
    2638      105682 :         _sub_Kln[tag][i].resize(1);
    2639      105682 :         _sub_Kel[tag][i].resize(1);
    2640      105682 :         _sub_Knl[tag][i].resize(1);
    2641             : 
    2642      105682 :         _jacobian_block_used[tag][i].resize(1);
    2643      105682 :         _jacobian_block_neighbor_used[tag][i].resize(1);
    2644      105682 :         _jacobian_block_lower_used[tag][i].resize(1);
    2645      105682 :         _jacobian_block_nonlocal_used[tag][i].resize(1);
    2646             :       }
    2647             :     }
    2648             :   }
    2649       63135 : }
    2650             : 
    2651             : void
    2652          78 : Assembly::initNonlocalCoupling()
    2653             : {
    2654          78 :   _cm_nonlocal_entry.clear();
    2655             : 
    2656          78 :   auto & vars = _sys.getVariables(_tid);
    2657             : 
    2658         234 :   for (auto & ivar : vars)
    2659             :   {
    2660         156 :     auto i = ivar->number();
    2661         156 :     auto ivar_start = _cm_nonlocal_entry.size();
    2662         312 :     for (unsigned int k = 0; k < ivar->count(); ++k)
    2663             :     {
    2664         156 :       unsigned int iv = i + k;
    2665         268 :       for (const auto & j : ConstCouplingRow(iv, _nonlocal_cm))
    2666         112 :         if (!_sys.isScalarVariable(j))
    2667             :         {
    2668         112 :           auto & jvar = _sys.getVariable(_tid, j);
    2669         112 :           auto pair = std::make_pair(ivar, &jvar);
    2670         112 :           auto c = ivar_start;
    2671             :           // check if the pair has been pushed or not
    2672         112 :           bool has_pair = false;
    2673         146 :           for (; c < _cm_nonlocal_entry.size(); ++c)
    2674          34 :             if (_cm_nonlocal_entry[c] == pair)
    2675             :             {
    2676           0 :               has_pair = true;
    2677           0 :               break;
    2678             :             }
    2679         112 :           if (!has_pair)
    2680         112 :             _cm_nonlocal_entry.push_back(pair);
    2681             :         }
    2682             :     }
    2683             :   }
    2684          78 : }
    2685             : 
    2686             : void
    2687    82784409 : Assembly::prepareJacobianBlock()
    2688             : {
    2689   218911243 :   for (const auto & it : _cm_ff_entry)
    2690             :   {
    2691   136126834 :     MooseVariableFEBase & ivar = *(it.first);
    2692   136126834 :     MooseVariableFEBase & jvar = *(it.second);
    2693             : 
    2694   136126834 :     unsigned int vi = ivar.number();
    2695   136126834 :     unsigned int vj = jvar.number();
    2696             : 
    2697   136126834 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2698             : 
    2699   411034138 :     for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2700             :     {
    2701   274907304 :       jacobianBlock(vi, vj, LocalDataKey{}, tag)
    2702   274907304 :           .resize(ivar.dofIndices().size() * ivar.count(), jvar.dofIndices().size() * jcount);
    2703   274907304 :       jacobianBlockUsed(tag, vi, vj, false);
    2704             :     }
    2705             :   }
    2706    82784409 : }
    2707             : 
    2708             : void
    2709   418601017 : Assembly::prepareResidual()
    2710             : {
    2711   418601017 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2712   886015799 :   for (const auto & var : vars)
    2713  1748462738 :     for (auto & tag_Re : _sub_Re)
    2714  1281047956 :       tag_Re[var->number()].resize(var->dofIndices().size() * var->count());
    2715   418601017 : }
    2716             : 
    2717             : void
    2718      542568 : Assembly::prepare()
    2719             : {
    2720      542568 :   prepareJacobianBlock();
    2721      542568 :   prepareResidual();
    2722      542568 : }
    2723             : 
    2724             : void
    2725       10364 : Assembly::prepareNonlocal()
    2726             : {
    2727       20992 :   for (const auto & it : _cm_nonlocal_entry)
    2728             :   {
    2729       10628 :     MooseVariableFEBase & ivar = *(it.first);
    2730       10628 :     MooseVariableFEBase & jvar = *(it.second);
    2731             : 
    2732       10628 :     unsigned int vi = ivar.number();
    2733       10628 :     unsigned int vj = jvar.number();
    2734             : 
    2735       10628 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2736             : 
    2737       31884 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2738       31884 :          tag < _jacobian_block_nonlocal_used.size();
    2739             :          tag++)
    2740             :     {
    2741       21256 :       jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
    2742       21256 :           .resize(ivar.dofIndices().size() * ivar.count(), jvar.allDofIndices().size() * jcount);
    2743       21256 :       jacobianBlockNonlocalUsed(tag, vi, vj, false);
    2744             :     }
    2745             :   }
    2746       10364 : }
    2747             : 
    2748             : void
    2749        1488 : Assembly::prepareVariable(MooseVariableFEBase * var)
    2750             : {
    2751        5624 :   for (const auto & it : _cm_ff_entry)
    2752             :   {
    2753        4136 :     MooseVariableFEBase & ivar = *(it.first);
    2754        4136 :     MooseVariableFEBase & jvar = *(it.second);
    2755             : 
    2756        4136 :     unsigned int vi = ivar.number();
    2757        4136 :     unsigned int vj = jvar.number();
    2758             : 
    2759        4136 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2760             : 
    2761        4136 :     if (vi == var->number() || vj == var->number())
    2762             :     {
    2763        8640 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2764             :       {
    2765        5760 :         jacobianBlock(vi, vj, LocalDataKey{}, tag)
    2766        5760 :             .resize(ivar.dofIndices().size() * ivar.count(), jvar.dofIndices().size() * jcount);
    2767        5760 :         jacobianBlockUsed(tag, vi, vj, false);
    2768             :       }
    2769             :     }
    2770             :   }
    2771             : 
    2772        5160 :   for (auto & tag_Re : _sub_Re)
    2773        3672 :     tag_Re[var->number()].resize(var->dofIndices().size() * var->count());
    2774        1488 : }
    2775             : 
    2776             : void
    2777           0 : Assembly::prepareVariableNonlocal(MooseVariableFEBase * var)
    2778             : {
    2779           0 :   for (const auto & it : _cm_nonlocal_entry)
    2780             :   {
    2781           0 :     MooseVariableFEBase & ivar = *(it.first);
    2782           0 :     MooseVariableFEBase & jvar = *(it.second);
    2783             : 
    2784           0 :     unsigned int vi = ivar.number();
    2785           0 :     unsigned int vj = jvar.number();
    2786             : 
    2787           0 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2788             : 
    2789           0 :     if (vi == var->number() || vj == var->number())
    2790             :     {
    2791           0 :       for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2792           0 :            tag < _jacobian_block_nonlocal_used.size();
    2793             :            tag++)
    2794             :       {
    2795           0 :         jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
    2796           0 :             .resize(ivar.dofIndices().size() * ivar.count(), jvar.allDofIndices().size() * jcount);
    2797           0 :         jacobianBlockNonlocalUsed(tag, vi, vj);
    2798             :       }
    2799             :     }
    2800             :   }
    2801           0 : }
    2802             : 
    2803             : void
    2804    28843751 : Assembly::prepareNeighbor()
    2805             : {
    2806    88480614 :   for (const auto & it : _cm_ff_entry)
    2807             :   {
    2808    59636863 :     MooseVariableFEBase & ivar = *(it.first);
    2809    59636863 :     MooseVariableFEBase & jvar = *(it.second);
    2810             : 
    2811    59636863 :     unsigned int vi = ivar.number();
    2812    59636863 :     unsigned int vj = jvar.number();
    2813             : 
    2814    59636863 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2815             : 
    2816   178918077 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    2817   178918077 :          tag < _jacobian_block_neighbor_used.size();
    2818             :          tag++)
    2819             :     {
    2820   119281214 :       jacobianBlockNeighbor(Moose::ElementNeighbor, vi, vj, LocalDataKey{}, tag)
    2821   119281214 :           .resize(ivar.dofIndices().size() * ivar.count(),
    2822   119281214 :                   jvar.dofIndicesNeighbor().size() * jcount);
    2823             : 
    2824   119281214 :       jacobianBlockNeighbor(Moose::NeighborElement, vi, vj, LocalDataKey{}, tag)
    2825   119281214 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2826   119281214 :                   jvar.dofIndices().size() * jcount);
    2827             : 
    2828   119281214 :       jacobianBlockNeighbor(Moose::NeighborNeighbor, vi, vj, LocalDataKey{}, tag)
    2829   119281214 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2830   119281214 :                   jvar.dofIndicesNeighbor().size() * jcount);
    2831             : 
    2832   119281214 :       jacobianBlockNeighborUsed(tag, vi, vj, false);
    2833             :     }
    2834             :   }
    2835             : 
    2836    28843751 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2837    67261704 :   for (const auto & var : vars)
    2838   136723390 :     for (auto & tag_Rn : _sub_Rn)
    2839    98305437 :       tag_Rn[var->number()].resize(var->dofIndicesNeighbor().size() * var->count());
    2840    28843751 : }
    2841             : 
    2842             : void
    2843      299795 : Assembly::prepareLowerD()
    2844             : {
    2845     1285175 :   for (const auto & it : _cm_ff_entry)
    2846             :   {
    2847      985380 :     MooseVariableFEBase & ivar = *(it.first);
    2848      985380 :     MooseVariableFEBase & jvar = *(it.second);
    2849             : 
    2850      985380 :     unsigned int vi = ivar.number();
    2851      985380 :     unsigned int vj = jvar.number();
    2852             : 
    2853      985380 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2854             : 
    2855     2956140 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    2856             :          tag++)
    2857             :     {
    2858             :       // To cover all possible cases we should have 9 combinations below for every 2-permutation
    2859             :       // of Lower,Secondary,Primary. However, 4 cases will in general be covered by calls to
    2860             :       // prepare() and prepareNeighbor(). These calls will cover SecondarySecondary
    2861             :       // (ElementElement), SecondaryPrimary (ElementNeighbor), PrimarySecondary (NeighborElement),
    2862             :       // and PrimaryPrimary (NeighborNeighbor). With these covered we only need to prepare the 5
    2863             :       // remaining below
    2864             : 
    2865             :       // derivatives w.r.t. lower dimensional residuals
    2866     1970760 :       jacobianBlockMortar(Moose::LowerLower, vi, vj, LocalDataKey{}, tag)
    2867     1970760 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2868     1970760 :                   jvar.dofIndicesLower().size() * jcount);
    2869             : 
    2870     1970760 :       jacobianBlockMortar(Moose::LowerSecondary, vi, vj, LocalDataKey{}, tag)
    2871     1970760 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2872     1970760 :                   jvar.dofIndices().size() * jvar.count());
    2873             : 
    2874     1970760 :       jacobianBlockMortar(Moose::LowerPrimary, vi, vj, LocalDataKey{}, tag)
    2875     1970760 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2876     1970760 :                   jvar.dofIndicesNeighbor().size() * jvar.count());
    2877             : 
    2878             :       // derivatives w.r.t. interior secondary residuals
    2879     1970760 :       jacobianBlockMortar(Moose::SecondaryLower, vi, vj, LocalDataKey{}, tag)
    2880     1970760 :           .resize(ivar.dofIndices().size() * ivar.count(),
    2881     1970760 :                   jvar.dofIndicesLower().size() * jvar.count());
    2882             : 
    2883             :       // derivatives w.r.t. interior primary residuals
    2884     1970760 :       jacobianBlockMortar(Moose::PrimaryLower, vi, vj, LocalDataKey{}, tag)
    2885     1970760 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2886     1970760 :                   jvar.dofIndicesLower().size() * jvar.count());
    2887             : 
    2888     1970760 :       jacobianBlockLowerUsed(tag, vi, vj, false);
    2889             :     }
    2890             :   }
    2891             : 
    2892      299795 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2893      805435 :   for (const auto & var : vars)
    2894     1590640 :     for (auto & tag_Rl : _sub_Rl)
    2895     1085000 :       tag_Rl[var->number()].resize(var->dofIndicesLower().size() * var->count());
    2896      299795 : }
    2897             : 
    2898             : void
    2899           0 : Assembly::prepareBlock(unsigned int ivar,
    2900             :                        unsigned int jvar,
    2901             :                        const std::vector<dof_id_type> & dof_indices)
    2902             : {
    2903           0 :   const auto & iv = _sys.getVariable(_tid, ivar);
    2904           0 :   const auto & jv = _sys.getVariable(_tid, jvar);
    2905           0 :   const unsigned int ivn = iv.number();
    2906           0 :   const unsigned int jvn = jv.number();
    2907           0 :   const unsigned int icount = iv.count();
    2908           0 :   unsigned int jcount = jv.count();
    2909           0 :   if (ivn == jvn && _component_block_diagonal[ivn])
    2910           0 :     jcount = 1;
    2911             : 
    2912           0 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2913             :   {
    2914           0 :     jacobianBlock(ivn, jvn, LocalDataKey{}, tag)
    2915           0 :         .resize(dof_indices.size() * icount, dof_indices.size() * jcount);
    2916           0 :     jacobianBlockUsed(tag, ivn, jvn, false);
    2917             :   }
    2918             : 
    2919           0 :   for (auto & tag_Re : _sub_Re)
    2920           0 :     tag_Re[ivn].resize(dof_indices.size() * icount);
    2921           0 : }
    2922             : 
    2923             : void
    2924           0 : Assembly::prepareBlockNonlocal(unsigned int ivar,
    2925             :                                unsigned int jvar,
    2926             :                                const std::vector<dof_id_type> & idof_indices,
    2927             :                                const std::vector<dof_id_type> & jdof_indices)
    2928             : {
    2929           0 :   const auto & iv = _sys.getVariable(_tid, ivar);
    2930           0 :   const auto & jv = _sys.getVariable(_tid, jvar);
    2931           0 :   const unsigned int ivn = iv.number();
    2932           0 :   const unsigned int jvn = jv.number();
    2933           0 :   const unsigned int icount = iv.count();
    2934           0 :   unsigned int jcount = jv.count();
    2935           0 :   if (ivn == jvn && _component_block_diagonal[ivn])
    2936           0 :     jcount = 1;
    2937             : 
    2938           0 :   for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2939           0 :        tag < _jacobian_block_nonlocal_used.size();
    2940             :        tag++)
    2941             :   {
    2942           0 :     jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag)
    2943           0 :         .resize(idof_indices.size() * icount, jdof_indices.size() * jcount);
    2944             : 
    2945           0 :     jacobianBlockNonlocalUsed(tag, ivn, jvn, false);
    2946             :   }
    2947           0 : }
    2948             : 
    2949             : void
    2950     8600239 : Assembly::prepareScalar()
    2951             : {
    2952     8600239 :   const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
    2953     8890286 :   for (const auto & ivar : vars)
    2954             :   {
    2955      290047 :     auto idofs = ivar->dofIndices().size();
    2956             : 
    2957     1149856 :     for (auto & tag_Re : _sub_Re)
    2958      859809 :       tag_Re[ivar->number()].resize(idofs);
    2959             : 
    2960      727700 :     for (const auto & jvar : vars)
    2961             :     {
    2962      437653 :       auto jdofs = jvar->dofIndices().size();
    2963             : 
    2964     1316869 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2965             :       {
    2966      879216 :         jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
    2967      879216 :         jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
    2968             :       }
    2969             :     }
    2970             :   }
    2971     8600239 : }
    2972             : 
    2973             : void
    2974      186723 : Assembly::prepareOffDiagScalar()
    2975             : {
    2976      186723 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2977      186723 :   const std::vector<MooseVariableScalar *> & scalar_vars = _sys.getScalarVariables(_tid);
    2978             : 
    2979      378761 :   for (const auto & ivar : scalar_vars)
    2980             :   {
    2981      192038 :     auto idofs = ivar->dofIndices().size();
    2982             : 
    2983      473087 :     for (const auto & jvar : vars)
    2984             :     {
    2985      281049 :       auto jdofs = jvar->dofIndices().size() * jvar->count();
    2986      843147 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2987             :       {
    2988      562098 :         jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
    2989      562098 :         jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
    2990             : 
    2991      562098 :         jacobianBlock(jvar->number(), ivar->number(), LocalDataKey{}, tag).resize(jdofs, idofs);
    2992      562098 :         jacobianBlockUsed(tag, jvar->number(), ivar->number(), false);
    2993             :       }
    2994             :     }
    2995             :   }
    2996      186723 : }
    2997             : 
    2998             : template <typename T>
    2999             : void
    3000   130886798 : Assembly::copyShapes(MooseVariableField<T> & v)
    3001             : {
    3002   130886798 :   phi(v).shallowCopy(v.phi());
    3003   130886798 :   gradPhi(v).shallowCopy(v.gradPhi());
    3004   130886798 :   if (v.computingSecond())
    3005       26616 :     secondPhi(v).shallowCopy(v.secondPhi());
    3006   130886798 : }
    3007             : 
    3008             : void
    3009   130886798 : Assembly::copyShapes(unsigned int var)
    3010             : {
    3011   130886798 :   auto & v = _sys.getVariable(_tid, var);
    3012   130886798 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3013             :   {
    3014   127890134 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3015   127890134 :     copyShapes(v);
    3016             :   }
    3017     2996664 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3018             :   {
    3019     1107654 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3020     1107654 :     copyShapes(v);
    3021             :   }
    3022     1889010 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3023             :   {
    3024     1889010 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3025     1889010 :     copyShapes(v);
    3026     1889010 :     if (v.computingCurl())
    3027       50512 :       curlPhi(v).shallowCopy(v.curlPhi());
    3028     1889010 :     if (v.computingDiv())
    3029      449280 :       divPhi(v).shallowCopy(v.divPhi());
    3030             :   }
    3031             :   else
    3032           0 :     mooseError("Unsupported variable field type!");
    3033   130886798 : }
    3034             : 
    3035             : template <typename T>
    3036             : void
    3037      659288 : Assembly::copyFaceShapes(MooseVariableField<T> & v)
    3038             : {
    3039      659288 :   phiFace(v).shallowCopy(v.phiFace());
    3040      659288 :   gradPhiFace(v).shallowCopy(v.gradPhiFace());
    3041      659288 :   if (v.computingSecond())
    3042        5208 :     secondPhiFace(v).shallowCopy(v.secondPhiFace());
    3043      659288 : }
    3044             : 
    3045             : void
    3046      659288 : Assembly::copyFaceShapes(unsigned int var)
    3047             : {
    3048      659288 :   auto & v = _sys.getVariable(_tid, var);
    3049      659288 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3050             :   {
    3051      585047 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3052      585047 :     copyFaceShapes(v);
    3053             :   }
    3054       74241 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3055             :   {
    3056       12832 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3057       12832 :     copyFaceShapes(v);
    3058             :   }
    3059       61409 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3060             :   {
    3061       61409 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3062       61409 :     copyFaceShapes(v);
    3063       61409 :     if (v.computingCurl())
    3064        6380 :       _vector_curl_phi_face.shallowCopy(v.curlPhi());
    3065       61409 :     if (v.computingDiv())
    3066       18816 :       _vector_div_phi_face.shallowCopy(v.divPhi());
    3067             :   }
    3068             :   else
    3069           0 :     mooseError("Unsupported variable field type!");
    3070      659288 : }
    3071             : 
    3072             : template <typename T>
    3073             : void
    3074      194810 : Assembly::copyNeighborShapes(MooseVariableField<T> & v)
    3075             : {
    3076      194810 :   if (v.usesPhiNeighbor())
    3077             :   {
    3078      194810 :     phiFaceNeighbor(v).shallowCopy(v.phiFaceNeighbor());
    3079      194810 :     phiNeighbor(v).shallowCopy(v.phiNeighbor());
    3080             :   }
    3081      194810 :   if (v.usesGradPhiNeighbor())
    3082             :   {
    3083      194810 :     gradPhiFaceNeighbor(v).shallowCopy(v.gradPhiFaceNeighbor());
    3084      194810 :     gradPhiNeighbor(v).shallowCopy(v.gradPhiNeighbor());
    3085             :   }
    3086      194810 :   if (v.usesSecondPhiNeighbor())
    3087             :   {
    3088           0 :     secondPhiFaceNeighbor(v).shallowCopy(v.secondPhiFaceNeighbor());
    3089           0 :     secondPhiNeighbor(v).shallowCopy(v.secondPhiNeighbor());
    3090             :   }
    3091      194810 : }
    3092             : 
    3093             : void
    3094      194810 : Assembly::copyNeighborShapes(unsigned int var)
    3095             : {
    3096      194810 :   auto & v = _sys.getVariable(_tid, var);
    3097      194810 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3098             :   {
    3099      190935 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3100      190935 :     copyNeighborShapes(v);
    3101             :   }
    3102        3875 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3103             :   {
    3104        3600 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3105        3600 :     copyNeighborShapes(v);
    3106             :   }
    3107         275 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3108             :   {
    3109         275 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3110         275 :     copyNeighborShapes(v);
    3111             :   }
    3112             :   else
    3113           0 :     mooseError("Unsupported variable field type!");
    3114      194810 : }
    3115             : 
    3116             : DenseMatrix<Number> &
    3117   358632242 : Assembly::jacobianBlockNeighbor(
    3118             :     Moose::DGJacobianType type, unsigned int ivar, unsigned int jvar, LocalDataKey, TagID tag)
    3119             : {
    3120   358632242 :   if (type == Moose::ElementElement)
    3121           0 :     jacobianBlockUsed(tag, ivar, jvar, true);
    3122             :   else
    3123   358632242 :     jacobianBlockNeighborUsed(tag, ivar, jvar, true);
    3124             : 
    3125   358632242 :   if (_block_diagonal_matrix)
    3126             :   {
    3127   132101427 :     switch (type)
    3128             :     {
    3129           0 :       default:
    3130             :       case Moose::ElementElement:
    3131           0 :         return _sub_Kee[tag][ivar][0];
    3132    44034903 :       case Moose::ElementNeighbor:
    3133    44034903 :         return _sub_Ken[tag][ivar][0];
    3134    44028681 :       case Moose::NeighborElement:
    3135    44028681 :         return _sub_Kne[tag][ivar][0];
    3136    44037843 :       case Moose::NeighborNeighbor:
    3137    44037843 :         return _sub_Knn[tag][ivar][0];
    3138             :     }
    3139             :   }
    3140             :   else
    3141             :   {
    3142   226530815 :     switch (type)
    3143             :     {
    3144           0 :       default:
    3145             :       case Moose::ElementElement:
    3146           0 :         return _sub_Kee[tag][ivar][jvar];
    3147    75510501 :       case Moose::ElementNeighbor:
    3148    75510501 :         return _sub_Ken[tag][ivar][jvar];
    3149    75509813 :       case Moose::NeighborElement:
    3150    75509813 :         return _sub_Kne[tag][ivar][jvar];
    3151    75510501 :       case Moose::NeighborNeighbor:
    3152    75510501 :         return _sub_Knn[tag][ivar][jvar];
    3153             :     }
    3154             :   }
    3155             : }
    3156             : 
    3157             : DenseMatrix<Number> &
    3158    10591604 : Assembly::jacobianBlockMortar(Moose::ConstraintJacobianType type,
    3159             :                               unsigned int ivar,
    3160             :                               unsigned int jvar,
    3161             :                               LocalDataKey,
    3162             :                               TagID tag)
    3163             : {
    3164    10591604 :   jacobianBlockLowerUsed(tag, ivar, jvar, true);
    3165    10591604 :   if (_block_diagonal_matrix)
    3166             :   {
    3167     1926080 :     switch (type)
    3168             :     {
    3169      329552 :       default:
    3170             :       case Moose::LowerLower:
    3171      329552 :         return _sub_Kll[tag][ivar][0];
    3172      329168 :       case Moose::LowerSecondary:
    3173      329168 :         return _sub_Kle[tag][ivar][0];
    3174      328976 :       case Moose::LowerPrimary:
    3175      328976 :         return _sub_Kln[tag][ivar][0];
    3176      357192 :       case Moose::SecondaryLower:
    3177      357192 :         return _sub_Kel[tag][ivar][0];
    3178       56048 :       case Moose::SecondarySecondary:
    3179       56048 :         return _sub_Kee[tag][ivar][0];
    3180       56048 :       case Moose::SecondaryPrimary:
    3181       56048 :         return _sub_Ken[tag][ivar][0];
    3182      357000 :       case Moose::PrimaryLower:
    3183      357000 :         return _sub_Knl[tag][ivar][0];
    3184       56048 :       case Moose::PrimarySecondary:
    3185       56048 :         return _sub_Kne[tag][ivar][0];
    3186       56048 :       case Moose::PrimaryPrimary:
    3187       56048 :         return _sub_Knn[tag][ivar][0];
    3188             :     }
    3189             :   }
    3190             :   else
    3191             :   {
    3192     8665524 :     switch (type)
    3193             :     {
    3194     1714644 :       default:
    3195             :       case Moose::LowerLower:
    3196     1714644 :         return _sub_Kll[tag][ivar][jvar];
    3197     1713764 :       case Moose::LowerSecondary:
    3198     1713764 :         return _sub_Kle[tag][ivar][jvar];
    3199     1706196 :       case Moose::LowerPrimary:
    3200     1706196 :         return _sub_Kln[tag][ivar][jvar];
    3201     1715924 :       case Moose::SecondaryLower:
    3202     1715924 :         return _sub_Kel[tag][ivar][jvar];
    3203       26660 :       case Moose::SecondarySecondary:
    3204       26660 :         return _sub_Kee[tag][ivar][jvar];
    3205       26660 :       case Moose::SecondaryPrimary:
    3206       26660 :         return _sub_Ken[tag][ivar][jvar];
    3207     1708356 :       case Moose::PrimaryLower:
    3208     1708356 :         return _sub_Knl[tag][ivar][jvar];
    3209       26660 :       case Moose::PrimarySecondary:
    3210       26660 :         return _sub_Kne[tag][ivar][jvar];
    3211       26660 :       case Moose::PrimaryPrimary:
    3212       26660 :         return _sub_Knn[tag][ivar][jvar];
    3213             :     }
    3214             :   }
    3215             : }
    3216             : 
    3217             : void
    3218  1098238072 : Assembly::processLocalResidual(DenseVector<Number> & res_block,
    3219             :                                std::vector<dof_id_type> & dof_indices,
    3220             :                                const std::vector<Real> & scaling_factor,
    3221             :                                bool is_nodal)
    3222             : {
    3223             :   // For an array variable, ndof is the number of dofs of the zero-th component and
    3224             :   // ntdof is the number of dofs of all components.
    3225             :   // For standard or vector variables, ndof will be the same as ntdof.
    3226  1098238072 :   auto ndof = dof_indices.size();
    3227  1098238072 :   auto ntdof = res_block.size();
    3228  1098238072 :   auto count = ntdof / ndof;
    3229             :   mooseAssert(count == scaling_factor.size(), "Inconsistent of number of components");
    3230             :   mooseAssert(count * ndof == ntdof, "Inconsistent of number of components");
    3231  1098238072 :   if (count > 1)
    3232             :   {
    3233             :     // expanding dof indices
    3234     4940709 :     dof_indices.resize(ntdof);
    3235     4940709 :     unsigned int p = 0;
    3236    17148087 :     for (MooseIndex(count) j = 0; j < count; ++j)
    3237    67883010 :       for (MooseIndex(ndof) i = 0; i < ndof; ++i)
    3238             :       {
    3239    55675632 :         dof_indices[p] = dof_indices[i] + (is_nodal ? j : j * ndof);
    3240    55675632 :         res_block(p) *= scaling_factor[j];
    3241    55675632 :         ++p;
    3242             :       }
    3243             :   }
    3244             :   else
    3245             :   {
    3246  1093297363 :     if (scaling_factor[0] != 1.0)
    3247     4901982 :       res_block *= scaling_factor[0];
    3248             :   }
    3249             : 
    3250  1098238072 :   _dof_map.constrain_element_vector(res_block, dof_indices, false);
    3251  1098238072 : }
    3252             : 
    3253             : void
    3254    14563758 : Assembly::addResidualBlock(NumericVector<Number> & residual,
    3255             :                            DenseVector<Number> & res_block,
    3256             :                            const std::vector<dof_id_type> & dof_indices,
    3257             :                            const std::vector<Real> & scaling_factor,
    3258             :                            bool is_nodal)
    3259             : {
    3260    14563758 :   if (dof_indices.size() > 0 && res_block.size())
    3261             :   {
    3262     7468928 :     _temp_dof_indices = dof_indices;
    3263     7468928 :     _tmp_Re = res_block;
    3264     7468928 :     processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor, is_nodal);
    3265     7468928 :     residual.add_vector(_tmp_Re, _temp_dof_indices);
    3266             :   }
    3267    14563758 : }
    3268             : 
    3269             : void
    3270  1165837821 : Assembly::cacheResidualBlock(std::vector<Real> & cached_residual_values,
    3271             :                              std::vector<dof_id_type> & cached_residual_rows,
    3272             :                              DenseVector<Number> & res_block,
    3273             :                              const std::vector<dof_id_type> & dof_indices,
    3274             :                              const std::vector<Real> & scaling_factor,
    3275             :                              bool is_nodal)
    3276             : {
    3277  1165837821 :   if (dof_indices.size() > 0 && res_block.size())
    3278             :   {
    3279  1090769144 :     _temp_dof_indices = dof_indices;
    3280  1090769144 :     _tmp_Re = res_block;
    3281  1090769144 :     processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor, is_nodal);
    3282             : 
    3283  5181152016 :     for (MooseIndex(_tmp_Re) i = 0; i < _tmp_Re.size(); i++)
    3284             :     {
    3285  4090382872 :       cached_residual_values.push_back(_tmp_Re(i));
    3286  4090382872 :       cached_residual_rows.push_back(_temp_dof_indices[i]);
    3287             :     }
    3288             :   }
    3289             : 
    3290  1165837821 :   res_block.zero();
    3291  1165837821 : }
    3292             : 
    3293             : void
    3294           0 : Assembly::setResidualBlock(NumericVector<Number> & residual,
    3295             :                            DenseVector<Number> & res_block,
    3296             :                            const std::vector<dof_id_type> & dof_indices,
    3297             :                            const std::vector<Real> & scaling_factor,
    3298             :                            bool is_nodal)
    3299             : {
    3300           0 :   if (dof_indices.size() > 0)
    3301             :   {
    3302           0 :     std::vector<dof_id_type> di(dof_indices);
    3303           0 :     _tmp_Re = res_block;
    3304           0 :     processLocalResidual(_tmp_Re, di, scaling_factor, is_nodal);
    3305           0 :     residual.insert(_tmp_Re, di);
    3306           0 :   }
    3307           0 : }
    3308             : 
    3309             : void
    3310      782880 : Assembly::addResidual(const VectorTag & vector_tag)
    3311             : {
    3312             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3313             :               "Non-residual tag in Assembly::addResidual");
    3314             : 
    3315      782880 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3316      782880 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3317      782880 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3318     2255232 :   for (const auto & var : vars)
    3319     1472352 :     addResidualBlock(residual,
    3320     1472352 :                      tag_Re[var->number()],
    3321     1472352 :                      var->dofIndices(),
    3322     1472352 :                      var->arrayScalingFactor(),
    3323     1472352 :                      var->isNodal());
    3324      782880 : }
    3325             : 
    3326             : void
    3327      270736 : Assembly::addResidual(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3328             : {
    3329     1053616 :   for (const auto & vector_tag : vector_tags)
    3330      782880 :     if (_sys.hasVector(vector_tag._id))
    3331      782880 :       addResidual(vector_tag);
    3332      270736 : }
    3333             : 
    3334             : void
    3335     5172304 : Assembly::addResidualNeighbor(const VectorTag & vector_tag)
    3336             : {
    3337             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3338             :               "Non-residual tag in Assembly::addResidualNeighbor");
    3339             : 
    3340     5172304 :   auto & tag_Rn = _sub_Rn[vector_tag._type_id];
    3341     5172304 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3342     5172304 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3343    11638556 :   for (const auto & var : vars)
    3344     6466252 :     addResidualBlock(residual,
    3345     6466252 :                      tag_Rn[var->number()],
    3346     6466252 :                      var->dofIndicesNeighbor(),
    3347     6466252 :                      var->arrayScalingFactor(),
    3348     6466252 :                      var->isNodal());
    3349     5172304 : }
    3350             : 
    3351             : void
    3352     2080743 : Assembly::addResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3353             : {
    3354     7253047 :   for (const auto & vector_tag : vector_tags)
    3355     5172304 :     if (_sys.hasVector(vector_tag._id))
    3356     5172304 :       addResidualNeighbor(vector_tag);
    3357     2080743 : }
    3358             : 
    3359             : void
    3360     5130576 : Assembly::addResidualLower(const VectorTag & vector_tag)
    3361             : {
    3362             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3363             :               "Non-residual tag in Assembly::addResidualLower");
    3364             : 
    3365     5130576 :   auto & tag_Rl = _sub_Rl[vector_tag._type_id];
    3366     5130576 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3367     5130576 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3368    11531280 :   for (const auto & var : vars)
    3369     6400704 :     addResidualBlock(residual,
    3370     6400704 :                      tag_Rl[var->number()],
    3371     6400704 :                      var->dofIndicesLower(),
    3372     6400704 :                      var->arrayScalingFactor(),
    3373     6400704 :                      var->isNodal());
    3374     5130576 : }
    3375             : 
    3376             : void
    3377     2055577 : Assembly::addResidualLower(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3378             : {
    3379     7186153 :   for (const auto & vector_tag : vector_tags)
    3380     5130576 :     if (_sys.hasVector(vector_tag._id))
    3381     5130576 :       addResidualLower(vector_tag);
    3382     2055577 : }
    3383             : 
    3384             : // private method, so no key required
    3385             : void
    3386      171809 : Assembly::addResidualScalar(const VectorTag & vector_tag)
    3387             : {
    3388             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3389             :               "Non-residual tag in Assembly::addResidualScalar");
    3390             : 
    3391             :   // add the scalar variables residuals
    3392      171809 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3393      171809 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3394      171809 :   const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
    3395      396259 :   for (const auto & var : vars)
    3396      224450 :     addResidualBlock(
    3397      224450 :         residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor(), false);
    3398      171809 : }
    3399             : 
    3400             : void
    3401       57299 : Assembly::addResidualScalar(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3402             : {
    3403      229108 :   for (const auto & vector_tag : vector_tags)
    3404      171809 :     if (_sys.hasVector(vector_tag._id))
    3405      171809 :       addResidualScalar(vector_tag);
    3406       57299 : }
    3407             : 
    3408             : void
    3409   338499112 : Assembly::cacheResidual(GlobalDataKey, const std::vector<VectorTag> & tags)
    3410             : {
    3411   338499112 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3412   721895973 :   for (const auto & var : vars)
    3413  1425962564 :     for (const auto & vector_tag : tags)
    3414  1042565703 :       if (_sys.hasVector(vector_tag._id))
    3415  1042565703 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3416  1042565703 :                            _cached_residual_rows[vector_tag._type_id],
    3417  1042565703 :                            _sub_Re[vector_tag._type_id][var->number()],
    3418  1042565703 :                            var->dofIndices(),
    3419  1042565703 :                            var->arrayScalingFactor(),
    3420  1042565703 :                            var->isNodal());
    3421   338499112 : }
    3422             : 
    3423             : // private method, so no key required
    3424             : void
    3425   117727606 : Assembly::cacheResidual(dof_id_type dof, Real value, TagID tag_id)
    3426             : {
    3427   117727606 :   const VectorTag & tag = _subproblem.getVectorTag(tag_id);
    3428             : 
    3429   117727606 :   _cached_residual_values[tag._type_id].push_back(value);
    3430   117727606 :   _cached_residual_rows[tag._type_id].push_back(dof);
    3431   117727606 : }
    3432             : 
    3433             : // private method, so no key required
    3434             : void
    3435   117296362 : Assembly::cacheResidual(dof_id_type dof, Real value, const std::set<TagID> & tags)
    3436             : {
    3437   235023968 :   for (auto & tag : tags)
    3438   117727606 :     cacheResidual(dof, value, tag);
    3439   117296362 : }
    3440             : 
    3441             : void
    3442           0 : Assembly::cacheResidualNodes(const DenseVector<Number> & res,
    3443             :                              const std::vector<dof_id_type> & dof_index,
    3444             :                              LocalDataKey,
    3445             :                              TagID tag)
    3446             : {
    3447             :   // Add the residual value and dof_index to cached_residual_values and cached_residual_rows
    3448             :   // respectively.
    3449             :   // This is used by NodalConstraint.C to cache the residual calculated for primary and secondary
    3450             :   // node.
    3451           0 :   const VectorTag & vector_tag = _subproblem.getVectorTag(tag);
    3452           0 :   for (MooseIndex(dof_index) i = 0; i < dof_index.size(); ++i)
    3453             :   {
    3454           0 :     _cached_residual_values[vector_tag._type_id].push_back(res(i));
    3455           0 :     _cached_residual_rows[vector_tag._type_id].push_back(dof_index[i]);
    3456             :   }
    3457           0 : }
    3458             : 
    3459             : void
    3460    35796406 : Assembly::cacheResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & tags)
    3461             : {
    3462    35796406 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3463    83907714 :   for (const auto & var : vars)
    3464   170794490 :     for (const auto & vector_tag : tags)
    3465   122683182 :       if (_sys.hasVector(vector_tag._id))
    3466   122683182 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3467   122683182 :                            _cached_residual_rows[vector_tag._type_id],
    3468   122683182 :                            _sub_Rn[vector_tag._type_id][var->number()],
    3469   122683182 :                            var->dofIndicesNeighbor(),
    3470   122683182 :                            var->arrayScalingFactor(),
    3471   122683182 :                            var->isNodal());
    3472    35796406 : }
    3473             : 
    3474             : void
    3475      181094 : Assembly::cacheResidualLower(GlobalDataKey, const std::vector<VectorTag> & tags)
    3476             : {
    3477      181094 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3478      459598 :   for (const auto & var : vars)
    3479      867440 :     for (const auto & vector_tag : tags)
    3480      588936 :       if (_sys.hasVector(vector_tag._id))
    3481      588936 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3482      588936 :                            _cached_residual_rows[vector_tag._type_id],
    3483      588936 :                            _sub_Rl[vector_tag._type_id][var->number()],
    3484      588936 :                            var->dofIndicesLower(),
    3485      588936 :                            var->arrayScalingFactor(),
    3486      588936 :                            var->isNodal());
    3487      181094 : }
    3488             : 
    3489             : void
    3490    53017553 : Assembly::addCachedResiduals(GlobalDataKey, const std::vector<VectorTag> & tags)
    3491             : {
    3492   191638945 :   for (const auto & vector_tag : tags)
    3493             :   {
    3494   138621392 :     if (!_sys.hasVector(vector_tag._id))
    3495             :     {
    3496           0 :       _cached_residual_values[vector_tag._type_id].clear();
    3497           0 :       _cached_residual_rows[vector_tag._type_id].clear();
    3498           0 :       continue;
    3499             :     }
    3500   138621392 :     addCachedResidualDirectly(_sys.getVector(vector_tag._id), GlobalDataKey{}, vector_tag);
    3501             :   }
    3502    53017553 : }
    3503             : 
    3504             : void
    3505       10870 : Assembly::clearCachedResiduals(GlobalDataKey)
    3506             : {
    3507       42552 :   for (const auto & vector_tag : _residual_vector_tags)
    3508       31682 :     clearCachedResiduals(vector_tag);
    3509       10870 : }
    3510             : 
    3511             : // private method, so no key required
    3512             : void
    3513   131065695 : Assembly::clearCachedResiduals(const VectorTag & vector_tag)
    3514             : {
    3515   131065695 :   auto & values = _cached_residual_values[vector_tag._type_id];
    3516   131065695 :   auto & rows = _cached_residual_rows[vector_tag._type_id];
    3517             : 
    3518             :   mooseAssert(values.size() == rows.size(),
    3519             :               "Number of cached residuals and number of rows must match!");
    3520             : 
    3521             :   // Keep track of the largest size so we can use it to reserve and avoid
    3522             :   // as much dynamic allocation as possible
    3523   131065695 :   if (_max_cached_residuals < values.size())
    3524       45082 :     _max_cached_residuals = values.size();
    3525             : 
    3526             :   // Clear both vectors (keeps the capacity the same)
    3527   131065695 :   values.clear();
    3528   131065695 :   rows.clear();
    3529             :   // And then reserve: use 2 as a fudge factor to *really* avoid dynamic allocation!
    3530   131065695 :   values.reserve(_max_cached_residuals * 2);
    3531   131065695 :   rows.reserve(_max_cached_residuals * 2);
    3532   131065695 : }
    3533             : 
    3534             : void
    3535   138642204 : Assembly::addCachedResidualDirectly(NumericVector<Number> & residual,
    3536             :                                     GlobalDataKey,
    3537             :                                     const VectorTag & vector_tag)
    3538             : {
    3539   138642204 :   const auto & values = _cached_residual_values[vector_tag._type_id];
    3540   138642204 :   const auto & rows = _cached_residual_rows[vector_tag._type_id];
    3541             : 
    3542             :   mooseAssert(values.size() == rows.size(),
    3543             :               "Number of cached residuals and number of rows must match!");
    3544             : 
    3545   138642204 :   if (!values.empty())
    3546             :   {
    3547   131034013 :     residual.add_vector(values, rows);
    3548   131034013 :     clearCachedResiduals(vector_tag);
    3549             :   }
    3550   138642204 : }
    3551             : 
    3552             : void
    3553           0 : Assembly::setResidual(NumericVector<Number> & residual, GlobalDataKey, const VectorTag & vector_tag)
    3554             : {
    3555           0 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3556           0 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3557           0 :   for (const auto & var : vars)
    3558           0 :     setResidualBlock(residual,
    3559           0 :                      tag_Re[var->number()],
    3560           0 :                      var->dofIndices(),
    3561           0 :                      var->arrayScalingFactor(),
    3562           0 :                      var->isNodal());
    3563           0 : }
    3564             : 
    3565             : void
    3566           0 : Assembly::setResidualNeighbor(NumericVector<Number> & residual,
    3567             :                               GlobalDataKey,
    3568             :                               const VectorTag & vector_tag)
    3569             : {
    3570           0 :   auto & tag_Rn = _sub_Rn[vector_tag._type_id];
    3571           0 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3572           0 :   for (const auto & var : vars)
    3573           0 :     setResidualBlock(residual,
    3574           0 :                      tag_Rn[var->number()],
    3575           0 :                      var->dofIndicesNeighbor(),
    3576           0 :                      var->arrayScalingFactor(),
    3577           0 :                      var->isNodal());
    3578           0 : }
    3579             : 
    3580             : // private method, so no key required
    3581             : void
    3582      459818 : Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
    3583             :                            DenseMatrix<Number> & jac_block,
    3584             :                            const MooseVariableBase & ivar,
    3585             :                            const MooseVariableBase & jvar,
    3586             :                            const std::vector<dof_id_type> & idof_indices,
    3587             :                            const std::vector<dof_id_type> & jdof_indices)
    3588             : {
    3589      459818 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3590       86636 :     return;
    3591      373182 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3592           0 :     return;
    3593             : 
    3594      373182 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3595             : 
    3596      760092 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3597             :   {
    3598      386910 :     unsigned int iv = ivar.number();
    3599      931704 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3600             :     {
    3601      544794 :       unsigned int jv = jvar.number();
    3602      544794 :       if (jt < jv || jt >= jv + jvar.count())
    3603      132348 :         continue;
    3604      412446 :       unsigned int j = jt - jv;
    3605             : 
    3606      412446 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3607      412446 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3608      412446 :       auto indof = di.size();
    3609      412446 :       auto jndof = dj.size();
    3610             : 
    3611      412446 :       unsigned int jj = j;
    3612      412446 :       if (iv == jv && _component_block_diagonal[iv])
    3613             :         // here i must be equal to j
    3614      335208 :         jj = 0;
    3615             : 
    3616      412446 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3617      412446 :       if (scaling_factor[i] != 1.0)
    3618        6108 :         sub *= scaling_factor[i];
    3619             : 
    3620             :       // If we're computing the jacobian for automatically scaling variables we do not want
    3621             :       // to constrain the element matrix because it introduces 1s on the diagonal for the
    3622             :       // constrained dofs
    3623      412446 :       if (!_sys.computingScalingJacobian())
    3624      412376 :         _dof_map.constrain_element_matrix(sub, di, dj, false);
    3625             : 
    3626      412446 :       jacobian.add_matrix(sub, di, dj);
    3627      412446 :     }
    3628             :   }
    3629             : }
    3630             : 
    3631             : // private method, so no key required
    3632             : void
    3633    60452113 : Assembly::cacheJacobianBlock(DenseMatrix<Number> & jac_block,
    3634             :                              const MooseVariableBase & ivar,
    3635             :                              const MooseVariableBase & jvar,
    3636             :                              const std::vector<dof_id_type> & idof_indices,
    3637             :                              const std::vector<dof_id_type> & jdof_indices,
    3638             :                              TagID tag)
    3639             : {
    3640    60452113 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3641      394052 :     return;
    3642    60058061 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3643           0 :     return;
    3644    60058061 :   if (!_sys.hasMatrix(tag))
    3645           0 :     return;
    3646             : 
    3647    60058061 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3648             : 
    3649   120943150 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3650             :   {
    3651    60885089 :     unsigned int iv = ivar.number();
    3652   153175077 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3653             :     {
    3654    92289988 :       unsigned int jv = jvar.number();
    3655    92289988 :       if (jt < jv || jt >= jv + jvar.count())
    3656    28939755 :         continue;
    3657    63350233 :       unsigned int j = jt - jv;
    3658             : 
    3659    63350233 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3660    63350233 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3661    63350233 :       auto indof = di.size();
    3662    63350233 :       auto jndof = dj.size();
    3663             : 
    3664    63350233 :       unsigned int jj = j;
    3665    63350233 :       if (iv == jv && _component_block_diagonal[iv])
    3666             :         // here i must be equal to j
    3667    50135997 :         jj = 0;
    3668             : 
    3669    63350233 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3670    63350233 :       if (scaling_factor[i] != 1.0)
    3671     1794194 :         sub *= scaling_factor[i];
    3672             : 
    3673             :       // If we're computing the jacobian for automatically scaling variables we do not want
    3674             :       // to constrain the element matrix because it introduces 1s on the diagonal for the
    3675             :       // constrained dofs
    3676    63350233 :       if (!_sys.computingScalingJacobian())
    3677    63127198 :         _dof_map.constrain_element_matrix(sub, di, dj, false);
    3678             : 
    3679   342621978 :       for (MooseIndex(di) i = 0; i < di.size(); i++)
    3680  1684008149 :         for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3681             :         {
    3682  1404736404 :           _cached_jacobian_values[tag].push_back(sub(i, j));
    3683  1404736404 :           _cached_jacobian_rows[tag].push_back(di[i]);
    3684  1404736404 :           _cached_jacobian_cols[tag].push_back(dj[j]);
    3685             :         }
    3686    63350233 :     }
    3687             :   }
    3688             : 
    3689    60058061 :   jac_block.zero();
    3690             : }
    3691             : 
    3692             : // private method, so no key required
    3693             : void
    3694         770 : Assembly::cacheJacobianBlockNonzero(DenseMatrix<Number> & jac_block,
    3695             :                                     const MooseVariableBase & ivar,
    3696             :                                     const MooseVariableBase & jvar,
    3697             :                                     const std::vector<dof_id_type> & idof_indices,
    3698             :                                     const std::vector<dof_id_type> & jdof_indices,
    3699             :                                     TagID tag)
    3700             : {
    3701         770 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3702           0 :     return;
    3703         770 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3704           0 :     return;
    3705         770 :   if (!_sys.hasMatrix(tag))
    3706           0 :     return;
    3707             : 
    3708         770 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3709             : 
    3710        1540 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3711             :   {
    3712         770 :     unsigned int iv = ivar.number();
    3713        2254 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3714             :     {
    3715        1484 :       unsigned int jv = jvar.number();
    3716        1484 :       if (jt < jv || jt >= jv + jvar.count())
    3717         714 :         continue;
    3718         770 :       unsigned int j = jt - jv;
    3719             : 
    3720         770 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3721         770 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3722         770 :       auto indof = di.size();
    3723         770 :       auto jndof = dj.size();
    3724             : 
    3725         770 :       unsigned int jj = j;
    3726         770 :       if (iv == jv && _component_block_diagonal[iv])
    3727             :         // here i must be equal to j
    3728         196 :         jj = 0;
    3729             : 
    3730         770 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3731         770 :       if (scaling_factor[i] != 1.0)
    3732         322 :         sub *= scaling_factor[i];
    3733             : 
    3734         770 :       _dof_map.constrain_element_matrix(sub, di, dj, false);
    3735             : 
    3736        3850 :       for (MooseIndex(di) i = 0; i < di.size(); i++)
    3737      232400 :         for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3738      229320 :           if (sub(i, j) != 0.0) // no storage allocated for unimplemented jacobian terms,
    3739             :                                 // maintaining maximum sparsity possible
    3740             :           {
    3741       32648 :             _cached_jacobian_values[tag].push_back(sub(i, j));
    3742       32648 :             _cached_jacobian_rows[tag].push_back(di[i]);
    3743       32648 :             _cached_jacobian_cols[tag].push_back(dj[j]);
    3744             :           }
    3745         770 :     }
    3746             :   }
    3747             : 
    3748         770 :   jac_block.zero();
    3749             : }
    3750             : 
    3751             : void
    3752     6706460 : Assembly::cacheJacobianBlock(DenseMatrix<Number> & jac_block,
    3753             :                              const std::vector<dof_id_type> & idof_indices,
    3754             :                              const std::vector<dof_id_type> & jdof_indices,
    3755             :                              Real scaling_factor,
    3756             :                              LocalDataKey,
    3757             :                              TagID tag)
    3758             : {
    3759             :   // Only cache data when the matrix exists
    3760    13392220 :   if ((idof_indices.size() > 0) && (jdof_indices.size() > 0) && jac_block.n() && jac_block.m() &&
    3761     6685760 :       _sys.hasMatrix(tag))
    3762             :   {
    3763     6685760 :     std::vector<dof_id_type> di(idof_indices);
    3764     6685760 :     std::vector<dof_id_type> dj(jdof_indices);
    3765             : 
    3766             :     // If we're computing the jacobian for automatically scaling variables we do not want to
    3767             :     // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    3768             :     // dofs
    3769     6685760 :     if (!_sys.computingScalingJacobian())
    3770     6685760 :       _dof_map.constrain_element_matrix(jac_block, di, dj, false);
    3771             : 
    3772     6685760 :     if (scaling_factor != 1.0)
    3773        7521 :       jac_block *= scaling_factor;
    3774             : 
    3775    39563256 :     for (MooseIndex(di) i = 0; i < di.size(); i++)
    3776   217463582 :       for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3777             :       {
    3778   184586086 :         _cached_jacobian_values[tag].push_back(jac_block(i, j));
    3779   184586086 :         _cached_jacobian_rows[tag].push_back(di[i]);
    3780   184586086 :         _cached_jacobian_cols[tag].push_back(dj[j]);
    3781             :       }
    3782     6685760 :   }
    3783     6706460 :   jac_block.zero();
    3784     6706460 : }
    3785             : 
    3786             : Real
    3787           0 : Assembly::elementVolume(const Elem * elem) const
    3788             : {
    3789           0 :   FEType fe_type(elem->default_order(), LAGRANGE);
    3790           0 :   std::unique_ptr<FEBase> fe(FEBase::build(elem->dim(), fe_type));
    3791             : 
    3792             :   // references to the quadrature points and weights
    3793           0 :   const std::vector<Real> & JxW = fe->get_JxW();
    3794           0 :   const std::vector<Point> & q_points = fe->get_xyz();
    3795             : 
    3796             :   // The default quadrature rule should integrate the mass matrix,
    3797             :   // thus it should be plenty to compute the volume
    3798           0 :   QGauss qrule(elem->dim(), fe_type.default_quadrature_order());
    3799           0 :   fe->attach_quadrature_rule(&qrule);
    3800           0 :   fe->reinit(elem);
    3801             : 
    3802             :   // perform a sanity check to ensure that size of quad rule and size of q_points is
    3803             :   // identical
    3804             :   mooseAssert(qrule.n_points() == q_points.size(),
    3805             :               "The number of points in the quadrature rule doesn't match the number of passed-in "
    3806             :               "points in Assembly::setCoordinateTransformation");
    3807             : 
    3808             :   // compute the coordinate transformation
    3809           0 :   Real vol = 0;
    3810           0 :   for (unsigned int qp = 0; qp < qrule.n_points(); ++qp)
    3811             :   {
    3812             :     Real coord;
    3813           0 :     coordTransformFactor(_subproblem, elem->subdomain_id(), q_points[qp], coord);
    3814           0 :     vol += JxW[qp] * coord;
    3815             :   }
    3816           0 :   return vol;
    3817           0 : }
    3818             : 
    3819             : void
    3820     3831499 : Assembly::addCachedJacobian(GlobalDataKey)
    3821             : {
    3822             : #ifndef NDEBUG
    3823             :   if (!_subproblem.checkNonlocalCouplingRequirement())
    3824             :   {
    3825             :     mooseAssert(_cached_jacobian_rows.size() == _cached_jacobian_cols.size(),
    3826             :                 "Error: Cached data sizes MUST be the same!");
    3827             :     for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3828             :       mooseAssert(_cached_jacobian_rows[i].size() == _cached_jacobian_cols[i].size(),
    3829             :                   "Error: Cached data sizes MUST be the same for a given tag!");
    3830             :   }
    3831             : #endif
    3832             : 
    3833    11563925 :   for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3834     7732430 :     if (_sys.hasMatrix(i))
    3835  1823566469 :       for (MooseIndex(_cached_jacobian_rows[i]) j = 0; j < _cached_jacobian_rows[i].size(); j++)
    3836  3639439762 :         _sys.getMatrix(i).add(_cached_jacobian_rows[i][j],
    3837  1819719881 :                               _cached_jacobian_cols[i][j],
    3838  1819719881 :                               _cached_jacobian_values[i][j]);
    3839             : 
    3840    11563921 :   for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3841             :   {
    3842     7732426 :     if (!_sys.hasMatrix(i))
    3843     3885838 :       continue;
    3844             : 
    3845     3846588 :     if (_max_cached_jacobians < _cached_jacobian_values[i].size())
    3846       46876 :       _max_cached_jacobians = _cached_jacobian_values[i].size();
    3847             : 
    3848             :     // Try to be more efficient from now on
    3849             :     // The 2 is just a fudge factor to keep us from having to grow the vector during assembly
    3850     3846588 :     _cached_jacobian_values[i].clear();
    3851     3846588 :     _cached_jacobian_values[i].reserve(_max_cached_jacobians * 2);
    3852             : 
    3853     3846588 :     _cached_jacobian_rows[i].clear();
    3854     3846588 :     _cached_jacobian_rows[i].reserve(_max_cached_jacobians * 2);
    3855             : 
    3856     3846588 :     _cached_jacobian_cols[i].clear();
    3857     3846588 :     _cached_jacobian_cols[i].reserve(_max_cached_jacobians * 2);
    3858             :   }
    3859     3831495 : }
    3860             : 
    3861             : inline void
    3862      103486 : Assembly::addJacobianCoupledVarPair(const MooseVariableBase & ivar, const MooseVariableBase & jvar)
    3863             : {
    3864      103486 :   auto i = ivar.number();
    3865      103486 :   auto j = jvar.number();
    3866      311494 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    3867      208008 :     if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
    3868       55316 :       addJacobianBlock(_sys.getMatrix(tag),
    3869      110632 :                        jacobianBlock(i, j, LocalDataKey{}, tag),
    3870             :                        ivar,
    3871             :                        jvar,
    3872       55316 :                        ivar.dofIndices(),
    3873       55316 :                        jvar.dofIndices());
    3874      103486 : }
    3875             : 
    3876             : void
    3877       37388 : Assembly::addJacobian(GlobalDataKey)
    3878             : {
    3879      110174 :   for (const auto & it : _cm_ff_entry)
    3880       72786 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3881             : 
    3882       37388 :   for (const auto & it : _cm_sf_entry)
    3883           0 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3884             : 
    3885       37388 :   for (const auto & it : _cm_fs_entry)
    3886           0 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3887       37388 : }
    3888             : 
    3889             : void
    3890           0 : Assembly::addJacobianNonlocal(GlobalDataKey)
    3891             : {
    3892           0 :   for (const auto & it : _cm_nonlocal_entry)
    3893             :   {
    3894           0 :     auto ivar = it.first;
    3895           0 :     auto jvar = it.second;
    3896           0 :     auto i = ivar->number();
    3897           0 :     auto j = jvar->number();
    3898           0 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    3899           0 :          tag < _jacobian_block_nonlocal_used.size();
    3900             :          tag++)
    3901           0 :       if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
    3902           0 :         addJacobianBlock(_sys.getMatrix(tag),
    3903           0 :                          jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
    3904             :                          *ivar,
    3905             :                          *jvar,
    3906           0 :                          ivar->dofIndices(),
    3907             :                          jvar->allDofIndices());
    3908             :   }
    3909           0 : }
    3910             : 
    3911             : void
    3912        8244 : Assembly::addJacobianNeighbor(GlobalDataKey)
    3913             : {
    3914       38364 :   for (const auto & it : _cm_ff_entry)
    3915             :   {
    3916       30120 :     auto ivar = it.first;
    3917       30120 :     auto jvar = it.second;
    3918       30120 :     auto i = ivar->number();
    3919       30120 :     auto j = jvar->number();
    3920       90744 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    3921       90744 :          tag < _jacobian_block_neighbor_used.size();
    3922             :          tag++)
    3923       60624 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    3924             :       {
    3925       22711 :         addJacobianBlock(_sys.getMatrix(tag),
    3926       22711 :                          jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    3927             :                          *ivar,
    3928             :                          *jvar,
    3929       22711 :                          ivar->dofIndices(),
    3930       22711 :                          jvar->dofIndicesNeighbor());
    3931             : 
    3932       22711 :         addJacobianBlock(_sys.getMatrix(tag),
    3933       22711 :                          jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    3934             :                          *ivar,
    3935             :                          *jvar,
    3936       22711 :                          ivar->dofIndicesNeighbor(),
    3937       22711 :                          jvar->dofIndices());
    3938             : 
    3939       22711 :         addJacobianBlock(_sys.getMatrix(tag),
    3940       45422 :                          jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    3941             :                          *ivar,
    3942             :                          *jvar,
    3943       22711 :                          ivar->dofIndicesNeighbor(),
    3944       22711 :                          jvar->dofIndicesNeighbor());
    3945             :       }
    3946             :   }
    3947        8244 : }
    3948             : 
    3949             : void
    3950      115562 : Assembly::addJacobianNeighborLowerD(GlobalDataKey)
    3951             : {
    3952      300559 :   for (const auto & it : _cm_ff_entry)
    3953             :   {
    3954      184997 :     auto ivar = it.first;
    3955      184997 :     auto jvar = it.second;
    3956      184997 :     auto i = ivar->number();
    3957      184997 :     auto j = jvar->number();
    3958      560079 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    3959             :          tag++)
    3960      375082 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    3961             :       {
    3962        7824 :         addJacobianBlock(_sys.getMatrix(tag),
    3963        7824 :                          jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    3964             :                          *ivar,
    3965             :                          *jvar,
    3966        7824 :                          ivar->dofIndicesLower(),
    3967        7824 :                          jvar->dofIndicesLower());
    3968             : 
    3969        7824 :         addJacobianBlock(_sys.getMatrix(tag),
    3970        7824 :                          jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    3971             :                          *ivar,
    3972             :                          *jvar,
    3973        7824 :                          ivar->dofIndicesLower(),
    3974        7824 :                          jvar->dofIndicesNeighbor());
    3975             : 
    3976        7824 :         addJacobianBlock(_sys.getMatrix(tag),
    3977        7824 :                          jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
    3978             :                          *ivar,
    3979             :                          *jvar,
    3980        7824 :                          ivar->dofIndicesLower(),
    3981        7824 :                          jvar->dofIndices());
    3982             : 
    3983        7824 :         addJacobianBlock(_sys.getMatrix(tag),
    3984        7824 :                          jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    3985             :                          *ivar,
    3986             :                          *jvar,
    3987        7824 :                          ivar->dofIndicesNeighbor(),
    3988        7824 :                          jvar->dofIndicesLower());
    3989             : 
    3990        7824 :         addJacobianBlock(_sys.getMatrix(tag),
    3991       15648 :                          jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
    3992             :                          *ivar,
    3993             :                          *jvar,
    3994        7824 :                          ivar->dofIndices(),
    3995        7824 :                          jvar->dofIndicesLower());
    3996             :       }
    3997             : 
    3998      560079 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    3999      560079 :          tag < _jacobian_block_neighbor_used.size();
    4000             :          tag++)
    4001      375082 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    4002             :       {
    4003       92379 :         addJacobianBlock(_sys.getMatrix(tag),
    4004       92379 :                          jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    4005             :                          *ivar,
    4006             :                          *jvar,
    4007       92379 :                          ivar->dofIndices(),
    4008       92379 :                          jvar->dofIndicesNeighbor());
    4009             : 
    4010       92379 :         addJacobianBlock(_sys.getMatrix(tag),
    4011       92379 :                          jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    4012             :                          *ivar,
    4013             :                          *jvar,
    4014       92379 :                          ivar->dofIndicesNeighbor(),
    4015       92379 :                          jvar->dofIndices());
    4016             : 
    4017       92379 :         addJacobianBlock(_sys.getMatrix(tag),
    4018      184758 :                          jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    4019             :                          *ivar,
    4020             :                          *jvar,
    4021       92379 :                          ivar->dofIndicesNeighbor(),
    4022       92379 :                          jvar->dofIndicesNeighbor());
    4023             :       }
    4024             :   }
    4025      115562 : }
    4026             : 
    4027             : void
    4028        4816 : Assembly::addJacobianLowerD(GlobalDataKey)
    4029             : {
    4030       41840 :   for (const auto & it : _cm_ff_entry)
    4031             :   {
    4032       37024 :     auto ivar = it.first;
    4033       37024 :     auto jvar = it.second;
    4034       37024 :     auto i = ivar->number();
    4035       37024 :     auto j = jvar->number();
    4036      111072 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    4037             :          tag++)
    4038       74048 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    4039             :       {
    4040        6704 :         addJacobianBlock(_sys.getMatrix(tag),
    4041        6704 :                          jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    4042             :                          *ivar,
    4043             :                          *jvar,
    4044        6704 :                          ivar->dofIndicesLower(),
    4045        6704 :                          jvar->dofIndicesLower());
    4046             : 
    4047        6704 :         addJacobianBlock(_sys.getMatrix(tag),
    4048        6704 :                          jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    4049             :                          *ivar,
    4050             :                          *jvar,
    4051        6704 :                          ivar->dofIndicesLower(),
    4052        6704 :                          jvar->dofIndices());
    4053             : 
    4054        6704 :         addJacobianBlock(_sys.getMatrix(tag),
    4055       13408 :                          jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    4056             :                          *ivar,
    4057             :                          *jvar,
    4058        6704 :                          ivar->dofIndices(),
    4059        6704 :                          jvar->dofIndicesLower());
    4060             :       }
    4061             :   }
    4062        4816 : }
    4063             : 
    4064             : void
    4065    51041992 : Assembly::cacheJacobian(GlobalDataKey)
    4066             : {
    4067   129043144 :   for (const auto & it : _cm_ff_entry)
    4068    78001152 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4069             : 
    4070    51293406 :   for (const auto & it : _cm_fs_entry)
    4071      251414 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4072             : 
    4073    51293406 :   for (const auto & it : _cm_sf_entry)
    4074      251414 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4075    51041992 : }
    4076             : 
    4077             : // private method, so no key required
    4078             : void
    4079    78503980 : Assembly::cacheJacobianCoupledVarPair(const MooseVariableBase & ivar,
    4080             :                                       const MooseVariableBase & jvar)
    4081             : {
    4082    78503980 :   auto i = ivar.number();
    4083    78503980 :   auto j = jvar.number();
    4084   237498600 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    4085   158994620 :     if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
    4086    60026527 :       cacheJacobianBlock(jacobianBlock(i, j, LocalDataKey{}, tag),
    4087             :                          ivar,
    4088             :                          jvar,
    4089    60026527 :                          ivar.dofIndices(),
    4090    60026527 :                          jvar.dofIndices(),
    4091             :                          tag);
    4092    78503980 : }
    4093             : 
    4094             : void
    4095        5166 : Assembly::cacheJacobianNonlocal(GlobalDataKey)
    4096             : {
    4097       10458 :   for (const auto & it : _cm_nonlocal_entry)
    4098             :   {
    4099        5292 :     auto ivar = it.first;
    4100        5292 :     auto jvar = it.second;
    4101        5292 :     auto i = ivar->number();
    4102        5292 :     auto j = jvar->number();
    4103       15876 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    4104       15876 :          tag < _jacobian_block_nonlocal_used.size();
    4105             :          tag++)
    4106       10584 :       if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
    4107        1540 :         cacheJacobianBlockNonzero(jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
    4108             :                                   *ivar,
    4109             :                                   *jvar,
    4110         770 :                                   ivar->dofIndices(),
    4111             :                                   jvar->allDofIndices(),
    4112             :                                   tag);
    4113             :   }
    4114        5166 : }
    4115             : 
    4116             : void
    4117        9290 : Assembly::cacheJacobianNeighbor(GlobalDataKey)
    4118             : {
    4119       32404 :   for (const auto & it : _cm_ff_entry)
    4120             :   {
    4121       23114 :     auto ivar = it.first;
    4122       23114 :     auto jvar = it.second;
    4123       23114 :     auto i = ivar->number();
    4124       23114 :     auto j = jvar->number();
    4125             : 
    4126       69342 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    4127       69342 :          tag < _jacobian_block_neighbor_used.size();
    4128             :          tag++)
    4129       46228 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    4130             :       {
    4131        7726 :         cacheJacobianBlock(jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    4132             :                            *ivar,
    4133             :                            *jvar,
    4134        7726 :                            ivar->dofIndices(),
    4135        7726 :                            jvar->dofIndicesNeighbor(),
    4136             :                            tag);
    4137        7726 :         cacheJacobianBlock(jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    4138             :                            *ivar,
    4139             :                            *jvar,
    4140        7726 :                            ivar->dofIndicesNeighbor(),
    4141        7726 :                            jvar->dofIndices(),
    4142             :                            tag);
    4143        7726 :         cacheJacobianBlock(
    4144       15452 :             jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    4145             :             *ivar,
    4146             :             *jvar,
    4147        7726 :             ivar->dofIndicesNeighbor(),
    4148        7726 :             jvar->dofIndicesNeighbor(),
    4149             :             tag);
    4150             :       }
    4151             :   }
    4152        9290 : }
    4153             : 
    4154             : void
    4155       84056 : Assembly::cacheJacobianMortar(GlobalDataKey)
    4156             : {
    4157      344172 :   for (const auto & it : _cm_ff_entry)
    4158             :   {
    4159      260116 :     auto ivar = it.first;
    4160      260116 :     auto jvar = it.second;
    4161      260116 :     auto i = ivar->number();
    4162      260116 :     auto j = jvar->number();
    4163      780348 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    4164             :          tag++)
    4165      520232 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    4166             :       {
    4167       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    4168             :                            *ivar,
    4169             :                            *jvar,
    4170       44712 :                            ivar->dofIndicesLower(),
    4171       44712 :                            jvar->dofIndicesLower(),
    4172             :                            tag);
    4173             : 
    4174       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    4175             :                            *ivar,
    4176             :                            *jvar,
    4177       44712 :                            ivar->dofIndicesLower(),
    4178       44712 :                            jvar->dofIndices(),
    4179             :                            tag);
    4180             : 
    4181       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
    4182             :                            *ivar,
    4183             :                            *jvar,
    4184       44712 :                            ivar->dofIndicesLower(),
    4185       44712 :                            jvar->dofIndicesNeighbor(),
    4186             :                            tag);
    4187             : 
    4188       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    4189             :                            *ivar,
    4190             :                            *jvar,
    4191       44712 :                            ivar->dofIndices(),
    4192       44712 :                            jvar->dofIndicesLower(),
    4193             :                            tag);
    4194             : 
    4195       44712 :         cacheJacobianBlock(
    4196       44712 :             jacobianBlockMortar(Moose::SecondarySecondary, i, j, LocalDataKey{}, tag),
    4197             :             *ivar,
    4198             :             *jvar,
    4199       44712 :             ivar->dofIndices(),
    4200       44712 :             jvar->dofIndices(),
    4201             :             tag);
    4202             : 
    4203       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryPrimary, i, j, LocalDataKey{}, tag),
    4204             :                            *ivar,
    4205             :                            *jvar,
    4206       44712 :                            ivar->dofIndices(),
    4207       44712 :                            jvar->dofIndicesNeighbor(),
    4208             :                            tag);
    4209             : 
    4210       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
    4211             :                            *ivar,
    4212             :                            *jvar,
    4213       44712 :                            ivar->dofIndicesNeighbor(),
    4214       44712 :                            jvar->dofIndicesLower(),
    4215             :                            tag);
    4216             : 
    4217       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimarySecondary, i, j, LocalDataKey{}, tag),
    4218             :                            *ivar,
    4219             :                            *jvar,
    4220       44712 :                            ivar->dofIndicesNeighbor(),
    4221       44712 :                            jvar->dofIndices(),
    4222             :                            tag);
    4223             : 
    4224       44712 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryPrimary, i, j, LocalDataKey{}, tag),
    4225             :                            *ivar,
    4226             :                            *jvar,
    4227       44712 :                            ivar->dofIndicesNeighbor(),
    4228       44712 :                            jvar->dofIndicesNeighbor(),
    4229             :                            tag);
    4230             :       }
    4231             :   }
    4232       84056 : }
    4233             : 
    4234             : void
    4235       65544 : Assembly::addJacobianBlockTags(SparseMatrix<Number> & jacobian,
    4236             :                                unsigned int ivar,
    4237             :                                unsigned int jvar,
    4238             :                                const DofMap & dof_map,
    4239             :                                std::vector<dof_id_type> & dof_indices,
    4240             :                                GlobalDataKey,
    4241             :                                const std::set<TagID> & tags)
    4242             : {
    4243      164376 :   for (auto tag : tags)
    4244       98832 :     addJacobianBlock(jacobian, ivar, jvar, dof_map, dof_indices, GlobalDataKey{}, tag);
    4245       65544 : }
    4246             : 
    4247             : void
    4248       98832 : Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
    4249             :                            unsigned int ivar,
    4250             :                            unsigned int jvar,
    4251             :                            const DofMap & dof_map,
    4252             :                            std::vector<dof_id_type> & dof_indices,
    4253             :                            GlobalDataKey,
    4254             :                            TagID tag)
    4255             : {
    4256       98832 :   if (dof_indices.size() == 0)
    4257           0 :     return;
    4258       98832 :   if (!(*_cm)(ivar, jvar))
    4259           0 :     return;
    4260             : 
    4261       98832 :   auto & iv = _sys.getVariable(_tid, ivar);
    4262       98832 :   auto & jv = _sys.getVariable(_tid, jvar);
    4263       98832 :   auto & scaling_factor = iv.arrayScalingFactor();
    4264             : 
    4265       98832 :   const unsigned int ivn = iv.number();
    4266       98832 :   const unsigned int jvn = jv.number();
    4267       98832 :   auto & ke = jacobianBlock(ivn, jvn, LocalDataKey{}, tag);
    4268             : 
    4269             :   // It is guaranteed by design iv.number <= ivar since iv is obtained
    4270             :   // through SystemBase::getVariable with ivar.
    4271             :   // Most of times ivar will just be equal to iv.number except for array variables,
    4272             :   // where ivar could be a number for a component of an array variable but calling
    4273             :   // getVariable will return the array variable that has the number of the 0th component.
    4274             :   // It is the same for jvar.
    4275       98832 :   const unsigned int i = ivar - ivn;
    4276       98832 :   const unsigned int j = jvar - jvn;
    4277             : 
    4278             :   // DoF indices are independently given
    4279       98832 :   auto di = dof_indices;
    4280       98832 :   auto dj = dof_indices;
    4281             : 
    4282       98832 :   auto indof = di.size();
    4283       98832 :   auto jndof = dj.size();
    4284             : 
    4285       98832 :   unsigned int jj = j;
    4286       98832 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4287       94304 :     jj = 0;
    4288             : 
    4289       98832 :   auto sub = ke.sub_matrix(i * indof, indof, jj * jndof, jndof);
    4290             :   // If we're computing the jacobian for automatically scaling variables we do not want to
    4291             :   // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    4292             :   // dofs
    4293       98832 :   if (!_sys.computingScalingJacobian())
    4294       98832 :     dof_map.constrain_element_matrix(sub, di, dj, false);
    4295             : 
    4296       98832 :   if (scaling_factor[i] != 1.0)
    4297           0 :     sub *= scaling_factor[i];
    4298             : 
    4299       98832 :   jacobian.add_matrix(sub, di, dj);
    4300       98832 : }
    4301             : 
    4302             : void
    4303           0 : Assembly::addJacobianBlockNonlocal(SparseMatrix<Number> & jacobian,
    4304             :                                    const unsigned int ivar,
    4305             :                                    const unsigned int jvar,
    4306             :                                    const DofMap & dof_map,
    4307             :                                    const std::vector<dof_id_type> & idof_indices,
    4308             :                                    const std::vector<dof_id_type> & jdof_indices,
    4309             :                                    GlobalDataKey,
    4310             :                                    const TagID tag)
    4311             : {
    4312           0 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    4313           0 :     return;
    4314           0 :   if (jacobian.n() == 0 || jacobian.m() == 0)
    4315           0 :     return;
    4316           0 :   if (!(*_cm)(ivar, jvar))
    4317           0 :     return;
    4318             : 
    4319           0 :   auto & iv = _sys.getVariable(_tid, ivar);
    4320           0 :   auto & jv = _sys.getVariable(_tid, jvar);
    4321           0 :   auto & scaling_factor = iv.arrayScalingFactor();
    4322             : 
    4323           0 :   const unsigned int ivn = iv.number();
    4324           0 :   const unsigned int jvn = jv.number();
    4325           0 :   auto & keg = jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag);
    4326             : 
    4327             :   // It is guaranteed by design iv.number <= ivar since iv is obtained
    4328             :   // through SystemBase::getVariable with ivar.
    4329             :   // Most of times ivar will just be equal to iv.number except for array variables,
    4330             :   // where ivar could be a number for a component of an array variable but calling
    4331             :   // getVariable will return the array variable that has the number of the 0th component.
    4332             :   // It is the same for jvar.
    4333           0 :   const unsigned int i = ivar - ivn;
    4334           0 :   const unsigned int j = jvar - jvn;
    4335             : 
    4336             :   // DoF indices are independently given
    4337           0 :   auto di = idof_indices;
    4338           0 :   auto dj = jdof_indices;
    4339             : 
    4340           0 :   auto indof = di.size();
    4341           0 :   auto jndof = dj.size();
    4342             : 
    4343           0 :   unsigned int jj = j;
    4344           0 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4345           0 :     jj = 0;
    4346             : 
    4347           0 :   auto sub = keg.sub_matrix(i * indof, indof, jj * jndof, jndof);
    4348             :   // If we're computing the jacobian for automatically scaling variables we do not want to
    4349             :   // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    4350             :   // dofs
    4351           0 :   if (!_sys.computingScalingJacobian())
    4352           0 :     dof_map.constrain_element_matrix(sub, di, dj, false);
    4353             : 
    4354           0 :   if (scaling_factor[i] != 1.0)
    4355           0 :     sub *= scaling_factor[i];
    4356             : 
    4357           0 :   jacobian.add_matrix(sub, di, dj);
    4358           0 : }
    4359             : 
    4360             : void
    4361           0 : Assembly::addJacobianBlockNonlocalTags(SparseMatrix<Number> & jacobian,
    4362             :                                        const unsigned int ivar,
    4363             :                                        const unsigned int jvar,
    4364             :                                        const DofMap & dof_map,
    4365             :                                        const std::vector<dof_id_type> & idof_indices,
    4366             :                                        const std::vector<dof_id_type> & jdof_indices,
    4367             :                                        GlobalDataKey,
    4368             :                                        const std::set<TagID> & tags)
    4369             : {
    4370           0 :   for (auto tag : tags)
    4371           0 :     addJacobianBlockNonlocal(
    4372           0 :         jacobian, ivar, jvar, dof_map, idof_indices, jdof_indices, GlobalDataKey{}, tag);
    4373           0 : }
    4374             : 
    4375             : void
    4376        2688 : Assembly::addJacobianNeighbor(SparseMatrix<Number> & jacobian,
    4377             :                               const unsigned int ivar,
    4378             :                               const unsigned int jvar,
    4379             :                               const DofMap & dof_map,
    4380             :                               std::vector<dof_id_type> & dof_indices,
    4381             :                               std::vector<dof_id_type> & neighbor_dof_indices,
    4382             :                               GlobalDataKey,
    4383             :                               const TagID tag)
    4384             : {
    4385        2688 :   if (dof_indices.size() == 0 && neighbor_dof_indices.size() == 0)
    4386           0 :     return;
    4387        2688 :   if (!(*_cm)(ivar, jvar))
    4388           0 :     return;
    4389             : 
    4390        2688 :   auto & iv = _sys.getVariable(_tid, ivar);
    4391        2688 :   auto & jv = _sys.getVariable(_tid, jvar);
    4392        2688 :   auto & scaling_factor = iv.arrayScalingFactor();
    4393             : 
    4394        2688 :   const unsigned int ivn = iv.number();
    4395        2688 :   const unsigned int jvn = jv.number();
    4396        2688 :   auto & ken = jacobianBlockNeighbor(Moose::ElementNeighbor, ivn, jvn, LocalDataKey{}, tag);
    4397        2688 :   auto & kne = jacobianBlockNeighbor(Moose::NeighborElement, ivn, jvn, LocalDataKey{}, tag);
    4398        2688 :   auto & knn = jacobianBlockNeighbor(Moose::NeighborNeighbor, ivn, jvn, LocalDataKey{}, tag);
    4399             : 
    4400             :   // It is guaranteed by design iv.number <= ivar since iv is obtained
    4401             :   // through SystemBase::getVariable with ivar.
    4402             :   // Most of times ivar will just be equal to iv.number except for array variables,
    4403             :   // where ivar could be a number for a component of an array variable but calling
    4404             :   // getVariable will return the array variable that has the number of the 0th component.
    4405             :   // It is the same for jvar.
    4406        2688 :   const unsigned int i = ivar - ivn;
    4407        2688 :   const unsigned int j = jvar - jvn;
    4408             :   // DoF indices are independently given
    4409        2688 :   auto dc = dof_indices;
    4410        2688 :   auto dn = neighbor_dof_indices;
    4411        2688 :   auto cndof = dc.size();
    4412        2688 :   auto nndof = dn.size();
    4413             : 
    4414        2688 :   unsigned int jj = j;
    4415        2688 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4416        2688 :     jj = 0;
    4417             : 
    4418        2688 :   auto suben = ken.sub_matrix(i * cndof, cndof, jj * nndof, nndof);
    4419        2688 :   auto subne = kne.sub_matrix(i * nndof, nndof, jj * cndof, cndof);
    4420        2688 :   auto subnn = knn.sub_matrix(i * nndof, nndof, jj * nndof, nndof);
    4421             : 
    4422             :   // If we're computing the jacobian for automatically scaling variables we do not want to
    4423             :   // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    4424             :   // dofs
    4425        2688 :   if (!_sys.computingScalingJacobian())
    4426             :   {
    4427        2688 :     dof_map.constrain_element_matrix(suben, dc, dn, false);
    4428        2688 :     dof_map.constrain_element_matrix(subne, dn, dc, false);
    4429        2688 :     dof_map.constrain_element_matrix(subnn, dn, dn, false);
    4430             :   }
    4431             : 
    4432        2688 :   if (scaling_factor[i] != 1.0)
    4433             :   {
    4434           0 :     suben *= scaling_factor[i];
    4435           0 :     subne *= scaling_factor[i];
    4436           0 :     subnn *= scaling_factor[i];
    4437             :   }
    4438             : 
    4439        2688 :   jacobian.add_matrix(suben, dc, dn);
    4440        2688 :   jacobian.add_matrix(subne, dn, dc);
    4441        2688 :   jacobian.add_matrix(subnn, dn, dn);
    4442        2688 : }
    4443             : 
    4444             : void
    4445        1344 : Assembly::addJacobianNeighborTags(SparseMatrix<Number> & jacobian,
    4446             :                                   const unsigned int ivar,
    4447             :                                   const unsigned int jvar,
    4448             :                                   const DofMap & dof_map,
    4449             :                                   std::vector<dof_id_type> & dof_indices,
    4450             :                                   std::vector<dof_id_type> & neighbor_dof_indices,
    4451             :                                   GlobalDataKey,
    4452             :                                   const std::set<TagID> & tags)
    4453             : {
    4454        4032 :   for (const auto tag : tags)
    4455        2688 :     addJacobianNeighbor(
    4456        5376 :         jacobian, ivar, jvar, dof_map, dof_indices, neighbor_dof_indices, GlobalDataKey{}, tag);
    4457        1344 : }
    4458             : 
    4459             : void
    4460       13840 : Assembly::addJacobianScalar(GlobalDataKey)
    4461             : {
    4462       31574 :   for (const auto & it : _cm_ss_entry)
    4463       17734 :     addJacobianCoupledVarPair(*it.first, *it.second);
    4464       13840 : }
    4465             : 
    4466             : void
    4467       34764 : Assembly::addJacobianOffDiagScalar(unsigned int ivar, GlobalDataKey)
    4468             : {
    4469       34764 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    4470       34764 :   MooseVariableScalar & var_i = _sys.getScalarVariable(_tid, ivar);
    4471       47730 :   for (const auto & var_j : vars)
    4472       12966 :     addJacobianCoupledVarPair(var_i, *var_j);
    4473       34764 : }
    4474             : 
    4475             : void
    4476   238614908 : Assembly::cacheJacobian(
    4477             :     numeric_index_type i, numeric_index_type j, Real value, LocalDataKey, TagID tag)
    4478             : {
    4479   238614908 :   _cached_jacobian_rows[tag].push_back(i);
    4480   238614908 :   _cached_jacobian_cols[tag].push_back(j);
    4481   238614908 :   _cached_jacobian_values[tag].push_back(value);
    4482   238614908 : }
    4483             : 
    4484             : void
    4485   238562004 : Assembly::cacheJacobian(numeric_index_type i,
    4486             :                         numeric_index_type j,
    4487             :                         Real value,
    4488             :                         LocalDataKey,
    4489             :                         const std::set<TagID> & tags)
    4490             : {
    4491   492102516 :   for (auto tag : tags)
    4492   253540512 :     if (_sys.hasMatrix(tag))
    4493   238614908 :       cacheJacobian(i, j, value, LocalDataKey{}, tag);
    4494   238562004 : }
    4495             : 
    4496             : void
    4497      394261 : Assembly::setCachedJacobian(GlobalDataKey)
    4498             : {
    4499     1194593 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4500      800332 :     if (_sys.hasMatrix(tag))
    4501             :     {
    4502             :       // First zero the rows (including the diagonals) to prepare for
    4503             :       // setting the cached values.
    4504      395648 :       _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
    4505             : 
    4506             :       // TODO: Use SparseMatrix::set_values() for efficiency
    4507     8635269 :       for (MooseIndex(_cached_jacobian_values) i = 0; i < _cached_jacobian_values[tag].size(); ++i)
    4508    16479242 :         _sys.getMatrix(tag).set(_cached_jacobian_rows[tag][i],
    4509     8239621 :                                 _cached_jacobian_cols[tag][i],
    4510     8239621 :                                 _cached_jacobian_values[tag][i]);
    4511             :     }
    4512             : 
    4513      394261 :   clearCachedJacobian();
    4514      394261 : }
    4515             : 
    4516             : void
    4517           0 : Assembly::zeroCachedJacobian(GlobalDataKey)
    4518             : {
    4519           0 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4520           0 :     if (_sys.hasMatrix(tag))
    4521           0 :       _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
    4522             : 
    4523           0 :   clearCachedJacobian();
    4524           0 : }
    4525             : 
    4526             : void
    4527      394261 : Assembly::clearCachedJacobian()
    4528             : {
    4529     1194593 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4530             :   {
    4531      800332 :     _cached_jacobian_rows[tag].clear();
    4532      800332 :     _cached_jacobian_cols[tag].clear();
    4533      800332 :     _cached_jacobian_values[tag].clear();
    4534             :   }
    4535      394261 : }
    4536             : 
    4537             : void
    4538           0 : Assembly::modifyWeightsDueToXFEM(const Elem * elem)
    4539             : {
    4540             :   mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
    4541             : 
    4542           0 :   if (_current_qrule == _current_qrule_arbitrary)
    4543           0 :     return;
    4544             : 
    4545           0 :   MooseArray<Real> xfem_weight_multipliers;
    4546           0 :   if (_xfem->getXFEMWeights(xfem_weight_multipliers, elem, _current_qrule, _current_q_points))
    4547             :   {
    4548             :     mooseAssert(xfem_weight_multipliers.size() == _current_JxW.size(),
    4549             :                 "Size of weight multipliers in xfem doesn't match number of quadrature points");
    4550           0 :     for (unsigned i = 0; i < xfem_weight_multipliers.size(); i++)
    4551           0 :       _current_JxW[i] = _current_JxW[i] * xfem_weight_multipliers[i];
    4552             : 
    4553           0 :     xfem_weight_multipliers.release();
    4554             :   }
    4555           0 : }
    4556             : 
    4557             : void
    4558           0 : Assembly::modifyFaceWeightsDueToXFEM(const Elem * elem, unsigned int side)
    4559             : {
    4560             :   mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
    4561             : 
    4562           0 :   if (_current_qrule_face == _current_qrule_arbitrary)
    4563           0 :     return;
    4564             : 
    4565           0 :   MooseArray<Real> xfem_face_weight_multipliers;
    4566           0 :   if (_xfem->getXFEMFaceWeights(
    4567           0 :           xfem_face_weight_multipliers, elem, _current_qrule_face, _current_q_points_face, side))
    4568             :   {
    4569             :     mooseAssert(xfem_face_weight_multipliers.size() == _current_JxW_face.size(),
    4570             :                 "Size of weight multipliers in xfem doesn't match number of quadrature points");
    4571           0 :     for (unsigned i = 0; i < xfem_face_weight_multipliers.size(); i++)
    4572           0 :       _current_JxW_face[i] = _current_JxW_face[i] * xfem_face_weight_multipliers[i];
    4573             : 
    4574           0 :     xfem_face_weight_multipliers.release();
    4575             :   }
    4576           0 : }
    4577             : 
    4578             : void
    4579         412 : Assembly::hasScalingVector()
    4580             : {
    4581         412 :   _scaling_vector = &_sys.getVector("scaling_factors");
    4582         412 : }
    4583             : 
    4584             : void
    4585           0 : Assembly::modifyArbitraryWeights(const std::vector<Real> & weights)
    4586             : {
    4587             :   mooseAssert(_current_qrule == _current_qrule_arbitrary, "Rule should be arbitrary");
    4588             :   mooseAssert(weights.size() == _current_physical_points.size(), "Size mismatch");
    4589             : 
    4590           0 :   for (MooseIndex(weights.size()) i = 0; i < weights.size(); ++i)
    4591           0 :     _current_JxW[i] = weights[i];
    4592           0 : }
    4593             : 
    4594             : template <>
    4595             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4596        1571 : Assembly::fePhi<VectorValue<Real>>(FEType type) const
    4597             : {
    4598        1571 :   buildVectorFE(type);
    4599        1571 :   return _vector_fe_shape_data[type]->_phi;
    4600             : }
    4601             : 
    4602             : template <>
    4603             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4604        1571 : Assembly::feGradPhi<VectorValue<Real>>(FEType type) const
    4605             : {
    4606        1571 :   buildVectorFE(type);
    4607        1571 :   return _vector_fe_shape_data[type]->_grad_phi;
    4608             : }
    4609             : 
    4610             : template <>
    4611             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4612           0 : Assembly::feSecondPhi<VectorValue<Real>>(FEType type) const
    4613             : {
    4614           0 :   _need_second_derivative.insert(type);
    4615           0 :   buildVectorFE(type);
    4616           0 :   return _vector_fe_shape_data[type]->_second_phi;
    4617             : }
    4618             : 
    4619             : template <>
    4620             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4621        3142 : Assembly::fePhiLower<VectorValue<Real>>(FEType type) const
    4622             : {
    4623        3142 :   buildVectorLowerDFE(type);
    4624        3142 :   return _vector_fe_shape_data_lower[type]->_phi;
    4625             : }
    4626             : 
    4627             : template <>
    4628             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4629           0 : Assembly::feDualPhiLower<VectorValue<Real>>(FEType type) const
    4630             : {
    4631           0 :   buildVectorDualLowerDFE(type);
    4632           0 :   return _vector_fe_shape_data_dual_lower[type]->_phi;
    4633             : }
    4634             : 
    4635             : template <>
    4636             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4637        3142 : Assembly::feGradPhiLower<VectorValue<Real>>(FEType type) const
    4638             : {
    4639        3142 :   buildVectorLowerDFE(type);
    4640        3142 :   return _vector_fe_shape_data_lower[type]->_grad_phi;
    4641             : }
    4642             : 
    4643             : template <>
    4644             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4645           0 : Assembly::feGradDualPhiLower<VectorValue<Real>>(FEType type) const
    4646             : {
    4647           0 :   buildVectorDualLowerDFE(type);
    4648           0 :   return _vector_fe_shape_data_dual_lower[type]->_grad_phi;
    4649             : }
    4650             : 
    4651             : template <>
    4652             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4653        1571 : Assembly::fePhiFace<VectorValue<Real>>(FEType type) const
    4654             : {
    4655        1571 :   buildVectorFaceFE(type);
    4656        1571 :   return _vector_fe_shape_data_face[type]->_phi;
    4657             : }
    4658             : 
    4659             : template <>
    4660             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4661        1571 : Assembly::feGradPhiFace<VectorValue<Real>>(FEType type) const
    4662             : {
    4663        1571 :   buildVectorFaceFE(type);
    4664        1571 :   return _vector_fe_shape_data_face[type]->_grad_phi;
    4665             : }
    4666             : 
    4667             : template <>
    4668             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4669           0 : Assembly::feSecondPhiFace<VectorValue<Real>>(FEType type) const
    4670             : {
    4671           0 :   _need_second_derivative.insert(type);
    4672           0 :   buildVectorFaceFE(type);
    4673             : 
    4674             :   // If we're building for a face we probably need to build for a
    4675             :   // neighbor while _need_second_derivative is set;
    4676             :   // onInterface/reinitNeighbor/etc don't distinguish
    4677           0 :   buildVectorFaceNeighborFE(type);
    4678             : 
    4679           0 :   return _vector_fe_shape_data_face[type]->_second_phi;
    4680             : }
    4681             : 
    4682             : template <>
    4683             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4684        1571 : Assembly::fePhiNeighbor<VectorValue<Real>>(FEType type) const
    4685             : {
    4686        1571 :   buildVectorNeighborFE(type);
    4687        1571 :   return _vector_fe_shape_data_neighbor[type]->_phi;
    4688             : }
    4689             : 
    4690             : template <>
    4691             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4692        1571 : Assembly::feGradPhiNeighbor<VectorValue<Real>>(FEType type) const
    4693             : {
    4694        1571 :   buildVectorNeighborFE(type);
    4695        1571 :   return _vector_fe_shape_data_neighbor[type]->_grad_phi;
    4696             : }
    4697             : 
    4698             : template <>
    4699             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4700           0 : Assembly::feSecondPhiNeighbor<VectorValue<Real>>(FEType type) const
    4701             : {
    4702           0 :   _need_second_derivative_neighbor.insert(type);
    4703           0 :   buildVectorNeighborFE(type);
    4704           0 :   return _vector_fe_shape_data_neighbor[type]->_second_phi;
    4705             : }
    4706             : 
    4707             : template <>
    4708             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4709        1571 : Assembly::fePhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4710             : {
    4711        1571 :   buildVectorFaceNeighborFE(type);
    4712        1571 :   return _vector_fe_shape_data_face_neighbor[type]->_phi;
    4713             : }
    4714             : 
    4715             : template <>
    4716             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4717        1571 : Assembly::feGradPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4718             : {
    4719        1571 :   buildVectorFaceNeighborFE(type);
    4720        1571 :   return _vector_fe_shape_data_face_neighbor[type]->_grad_phi;
    4721             : }
    4722             : 
    4723             : template <>
    4724             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4725           0 : Assembly::feSecondPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4726             : {
    4727           0 :   _need_second_derivative_neighbor.insert(type);
    4728           0 :   buildVectorFaceNeighborFE(type);
    4729           0 :   return _vector_fe_shape_data_face_neighbor[type]->_second_phi;
    4730             : }
    4731             : 
    4732             : template <>
    4733             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4734       57245 : Assembly::feCurlPhi<VectorValue<Real>>(FEType type) const
    4735             : {
    4736       57245 :   _need_curl.insert(type);
    4737       57245 :   buildVectorFE(type);
    4738       57245 :   return _vector_fe_shape_data[type]->_curl_phi;
    4739             : }
    4740             : 
    4741             : template <>
    4742             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4743         209 : Assembly::feCurlPhiFace<VectorValue<Real>>(FEType type) const
    4744             : {
    4745         209 :   _need_curl.insert(type);
    4746         209 :   buildVectorFaceFE(type);
    4747             : 
    4748             :   // If we're building for a face we probably need to build for a
    4749             :   // neighbor while _need_curl is set;
    4750             :   // onInterface/reinitNeighbor/etc don't distinguish
    4751         209 :   buildVectorFaceNeighborFE(type);
    4752             : 
    4753         209 :   return _vector_fe_shape_data_face[type]->_curl_phi;
    4754             : }
    4755             : 
    4756             : template <>
    4757             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4758           0 : Assembly::feCurlPhiNeighbor<VectorValue<Real>>(FEType type) const
    4759             : {
    4760           0 :   _need_curl.insert(type);
    4761           0 :   buildVectorNeighborFE(type);
    4762           0 :   return _vector_fe_shape_data_neighbor[type]->_curl_phi;
    4763             : }
    4764             : 
    4765             : template <>
    4766             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4767           0 : Assembly::feCurlPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4768             : {
    4769           0 :   _need_curl.insert(type);
    4770           0 :   buildVectorFaceNeighborFE(type);
    4771             : 
    4772           0 :   return _vector_fe_shape_data_face_neighbor[type]->_curl_phi;
    4773             : }
    4774             : 
    4775             : template <>
    4776             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4777      469068 : Assembly::feDivPhi<VectorValue<Real>>(FEType type) const
    4778             : {
    4779      469068 :   _need_div.insert(type);
    4780      469068 :   buildVectorFE(type);
    4781      469068 :   return _vector_fe_shape_data[type]->_div_phi;
    4782             : }
    4783             : 
    4784             : template <>
    4785             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4786         312 : Assembly::feDivPhiFace<VectorValue<Real>>(FEType type) const
    4787             : {
    4788         312 :   _need_face_div.insert(type);
    4789         312 :   buildVectorFaceFE(type);
    4790             : 
    4791             :   // If we're building for a face we probably need to build for a
    4792             :   // neighbor while _need_face_div is set;
    4793             :   // onInterface/reinitNeighbor/etc don't distinguish
    4794         312 :   buildVectorFaceNeighborFE(type);
    4795             : 
    4796         312 :   return _vector_fe_shape_data_face[type]->_div_phi;
    4797             : }
    4798             : 
    4799             : template <>
    4800             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4801           0 : Assembly::feDivPhiNeighbor<VectorValue<Real>>(FEType type) const
    4802             : {
    4803           0 :   _need_neighbor_div.insert(type);
    4804           0 :   buildVectorNeighborFE(type);
    4805           0 :   return _vector_fe_shape_data_neighbor[type]->_div_phi;
    4806             : }
    4807             : 
    4808             : template <>
    4809             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4810           0 : Assembly::feDivPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4811             : {
    4812           0 :   _need_face_neighbor_div.insert(type);
    4813           0 :   buildVectorFaceNeighborFE(type);
    4814           0 :   return _vector_fe_shape_data_face_neighbor[type]->_div_phi;
    4815             : }
    4816             : 
    4817             : const MooseArray<ADReal> &
    4818          26 : Assembly::adCurvatures() const
    4819             : {
    4820          26 :   _calculate_curvatures = true;
    4821          26 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
    4822          26 :   const FEType helper_type(helper_order, LAGRANGE);
    4823             :   // Must prerequest the second derivatives. Sadly because there is only one
    4824             :   // _need_second_derivative map for both volumetric and face FE objects we must request both here
    4825          26 :   feSecondPhi<Real>(helper_type);
    4826          26 :   feSecondPhiFace<Real>(helper_type);
    4827          26 :   return _ad_curvatures;
    4828             : }
    4829             : 
    4830             : void
    4831       66805 : Assembly::helpersRequestData()
    4832             : {
    4833      259602 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
    4834             :   {
    4835      192797 :     _holder_fe_helper[dim]->get_phi();
    4836      192797 :     _holder_fe_helper[dim]->get_dphi();
    4837      192797 :     _holder_fe_helper[dim]->get_xyz();
    4838      192797 :     _holder_fe_helper[dim]->get_JxW();
    4839             : 
    4840      192797 :     _holder_fe_face_helper[dim]->get_phi();
    4841      192797 :     _holder_fe_face_helper[dim]->get_dphi();
    4842      192797 :     _holder_fe_face_helper[dim]->get_xyz();
    4843      192797 :     _holder_fe_face_helper[dim]->get_JxW();
    4844      192797 :     _holder_fe_face_helper[dim]->get_normals();
    4845             : 
    4846      192797 :     _holder_fe_face_neighbor_helper[dim]->get_xyz();
    4847      192797 :     _holder_fe_face_neighbor_helper[dim]->get_JxW();
    4848      192797 :     _holder_fe_face_neighbor_helper[dim]->get_normals();
    4849             : 
    4850      192797 :     _holder_fe_neighbor_helper[dim]->get_xyz();
    4851      192797 :     _holder_fe_neighbor_helper[dim]->get_JxW();
    4852             :   }
    4853             : 
    4854      192797 :   for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
    4855             :   {
    4856             :     // We need these computations in order to compute correct lower-d element volumes in
    4857             :     // curvilinear coordinates
    4858      125992 :     _holder_fe_lower_helper[dim]->get_xyz();
    4859      125992 :     _holder_fe_lower_helper[dim]->get_JxW();
    4860             :   }
    4861       66805 : }
    4862             : 
    4863             : void
    4864         234 : Assembly::havePRefinement(const std::unordered_set<FEFamily> & disable_families)
    4865             : {
    4866         234 :   if (_have_p_refinement)
    4867             :     // Already performed tasks for p-refinement
    4868           0 :     return;
    4869             : 
    4870         234 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
    4871         234 :   const FEType helper_type(helper_order, LAGRANGE);
    4872             :   auto process_fe =
    4873        9984 :       [&disable_families](const unsigned int num_dimensionalities, auto & fe_container)
    4874             :   {
    4875        2340 :     if (!disable_families.empty())
    4876        7540 :       for (const auto dim : make_range(num_dimensionalities))
    4877             :       {
    4878        5590 :         auto fe_container_it = fe_container.find(dim);
    4879        5590 :         if (fe_container_it != fe_container.end())
    4880       11349 :           for (auto & [fe_type, fe_ptr] : fe_container_it->second)
    4881        7644 :             if (disable_families.count(fe_type.family))
    4882        2665 :               fe_ptr->add_p_level_in_reinit(false);
    4883             :       }
    4884        2574 :   };
    4885        1170 :   auto process_fe_and_helpers = [process_fe, &helper_type](auto & unique_helper_container,
    4886             :                                                            auto & helper_container,
    4887             :                                                            const unsigned int num_dimensionalities,
    4888             :                                                            const bool user_added_helper_type,
    4889        5707 :                                                            auto & fe_container)
    4890             :   {
    4891        1170 :     unique_helper_container.resize(num_dimensionalities);
    4892        4511 :     for (const auto dim : make_range(num_dimensionalities))
    4893             :     {
    4894        3341 :       auto & unique_helper = unique_helper_container[dim];
    4895        3341 :       unique_helper = FEGenericBase<Real>::build(dim, helper_type);
    4896             :       // don't participate in p-refinement
    4897        3341 :       unique_helper->add_p_level_in_reinit(false);
    4898        3341 :       helper_container[dim] = unique_helper.get();
    4899             : 
    4900             :       // If the user did not request the helper type then we should erase it from our FE container
    4901             :       // so that they're not penalized (in the "we should be able to do p-refinement sense") for
    4902             :       // our perhaps silly helpers
    4903        3341 :       if (!user_added_helper_type)
    4904             :       {
    4905        2366 :         auto & fe_container_dim = libmesh_map_find(fe_container, dim);
    4906        2366 :         auto fe_it = fe_container_dim.find(helper_type);
    4907             :         mooseAssert(fe_it != fe_container_dim.end(), "We should have the helper type");
    4908        2366 :         delete fe_it->second;
    4909        2366 :         fe_container_dim.erase(fe_it);
    4910             :       }
    4911             :     }
    4912             : 
    4913        1170 :     process_fe(num_dimensionalities, fe_container);
    4914        1170 :   };
    4915             : 
    4916             :   // Handle scalar field families
    4917         234 :   process_fe_and_helpers(_unique_fe_helper,
    4918         234 :                          _holder_fe_helper,
    4919         234 :                          _mesh_dimension + 1,
    4920         234 :                          _user_added_fe_of_helper_type,
    4921         234 :                          _fe);
    4922         234 :   process_fe_and_helpers(_unique_fe_face_helper,
    4923         234 :                          _holder_fe_face_helper,
    4924         234 :                          _mesh_dimension + 1,
    4925         234 :                          _user_added_fe_face_of_helper_type,
    4926         234 :                          _fe_face);
    4927         234 :   process_fe_and_helpers(_unique_fe_face_neighbor_helper,
    4928         234 :                          _holder_fe_face_neighbor_helper,
    4929         234 :                          _mesh_dimension + 1,
    4930         234 :                          _user_added_fe_face_neighbor_of_helper_type,
    4931         234 :                          _fe_face_neighbor);
    4932         234 :   process_fe_and_helpers(_unique_fe_neighbor_helper,
    4933         234 :                          _holder_fe_neighbor_helper,
    4934         234 :                          _mesh_dimension + 1,
    4935         234 :                          _user_added_fe_neighbor_of_helper_type,
    4936         234 :                          _fe_neighbor);
    4937         234 :   process_fe_and_helpers(_unique_fe_lower_helper,
    4938         234 :                          _holder_fe_lower_helper,
    4939             :                          _mesh_dimension,
    4940         234 :                          _user_added_fe_lower_of_helper_type,
    4941         234 :                          _fe_lower);
    4942             :   // Handle vector field families
    4943         234 :   process_fe(_mesh_dimension + 1, _vector_fe);
    4944         234 :   process_fe(_mesh_dimension + 1, _vector_fe_face);
    4945         234 :   process_fe(_mesh_dimension + 1, _vector_fe_neighbor);
    4946         234 :   process_fe(_mesh_dimension + 1, _vector_fe_face_neighbor);
    4947         234 :   process_fe(_mesh_dimension, _vector_fe_lower);
    4948             : 
    4949         234 :   helpersRequestData();
    4950             : 
    4951         234 :   _have_p_refinement = true;
    4952             : }
    4953             : 
    4954             : template void coordTransformFactor<Point, Real>(const SubProblem & s,
    4955             :                                                 SubdomainID sub_id,
    4956             :                                                 const Point & point,
    4957             :                                                 Real & factor,
    4958             :                                                 SubdomainID neighbor_sub_id);
    4959             : template void coordTransformFactor<ADPoint, ADReal>(const SubProblem & s,
    4960             :                                                     SubdomainID sub_id,
    4961             :                                                     const ADPoint & point,
    4962             :                                                     ADReal & factor,
    4963             :                                                     SubdomainID neighbor_sub_id);
    4964             : template void coordTransformFactor<Point, Real>(const MooseMesh & mesh,
    4965             :                                                 SubdomainID sub_id,
    4966             :                                                 const Point & point,
    4967             :                                                 Real & factor,
    4968             :                                                 SubdomainID neighbor_sub_id);
    4969             : template void coordTransformFactor<ADPoint, ADReal>(const MooseMesh & mesh,
    4970             :                                                     SubdomainID sub_id,
    4971             :                                                     const ADPoint & point,
    4972             :                                                     ADReal & factor,
    4973             :                                                     SubdomainID neighbor_sub_id);
    4974             : 
    4975             : template <>
    4976             : const MooseArray<Moose::GenericType<Point, false>> &
    4977          23 : Assembly::genericQPoints<false>() const
    4978             : {
    4979          23 :   return qPoints();
    4980             : }
    4981             : 
    4982             : template <>
    4983             : const MooseArray<Moose::GenericType<Point, true>> &
    4984          11 : Assembly::genericQPoints<true>() const
    4985             : {
    4986          11 :   return adQPoints();
    4987             : }

Generated by: LCOV version 1.14