LCOV - code coverage report
Current view: top level - src/base - Assembly.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 2218 2769 80.1 %
Date: 2025-08-08 20:01:16 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  2038105197 : coordTransformFactor(const SubProblem & s,
      43             :                      const SubdomainID sub_id,
      44             :                      const P & point,
      45             :                      C & factor,
      46             :                      const SubdomainID neighbor_sub_id)
      47             : {
      48  2038105197 :   coordTransformFactor(s.mesh(), sub_id, point, factor, neighbor_sub_id);
      49  2038105197 : }
      50             : 
      51             : template <typename P, typename C>
      52             : void
      53  2041549239 : 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  2041549239 :   const auto coord_type = mesh.getCoordSystem(sub_id);
      64             : 
      65  2041549239 :   if (coord_type == Moose::COORD_RZ)
      66             :   {
      67     4123964 :     if (mesh.usingGeneralAxisymmetricCoordAxes())
      68             :     {
      69     1212256 :       const auto & axis = mesh.getGeneralAxisymmetricCoordAxis(sub_id);
      70     1212256 :       MooseMeshUtils::coordTransformFactorRZGeneral(point, axis, factor);
      71             :     }
      72             :     else
      73     2911708 :       MooseMeshUtils::coordTransformFactor(
      74             :           point, factor, coord_type, mesh.getAxisymmetricRadialCoord());
      75             :   }
      76             :   else
      77  2037425275 :     MooseMeshUtils::coordTransformFactor(point, factor, coord_type, libMesh::invalid_uint);
      78  2041549239 : }
      79             : 
      80       71343 : Assembly::Assembly(SystemBase & sys, THREAD_ID tid)
      81       71343 :   : _sys(sys),
      82      142686 :     _subproblem(_sys.subproblem()),
      83       71343 :     _displaced(dynamic_cast<DisplacedSystem *>(&sys) ? true : false),
      84       71343 :     _nonlocal_cm(_subproblem.nonlocalCouplingMatrix(_sys.number())),
      85       71343 :     _computing_residual(_subproblem.currentlyComputingResidual()),
      86       71343 :     _computing_jacobian(_subproblem.currentlyComputingJacobian()),
      87       71343 :     _computing_residual_and_jacobian(_subproblem.currentlyComputingResidualAndJacobian()),
      88       71343 :     _dof_map(_sys.dofMap()),
      89       71343 :     _tid(tid),
      90       71343 :     _mesh(sys.mesh()),
      91       71343 :     _mesh_dimension(_mesh.dimension()),
      92       71343 :     _helper_type(_mesh.hasSecondOrderElements() ? SECOND : FIRST, LAGRANGE),
      93       71343 :     _user_added_fe_of_helper_type(false),
      94       71343 :     _user_added_fe_face_of_helper_type(false),
      95       71343 :     _user_added_fe_face_neighbor_of_helper_type(false),
      96       71343 :     _user_added_fe_neighbor_of_helper_type(false),
      97       71343 :     _user_added_fe_lower_of_helper_type(false),
      98       71343 :     _building_helpers(false),
      99       71343 :     _current_qrule(nullptr),
     100       71343 :     _current_qrule_volume(nullptr),
     101       71343 :     _current_qrule_arbitrary(nullptr),
     102       71343 :     _coord_type(Moose::COORD_XYZ),
     103       71343 :     _current_qrule_face(nullptr),
     104       71343 :     _current_qface_arbitrary(nullptr),
     105       71343 :     _current_qrule_neighbor(nullptr),
     106       71343 :     _need_JxW_neighbor(false),
     107       71343 :     _qrule_msm(nullptr),
     108       71343 :     _custom_mortar_qrule(false),
     109       71343 :     _current_qrule_lower(nullptr),
     110             : 
     111       71343 :     _current_elem(nullptr),
     112       71343 :     _current_elem_volume(0),
     113       71343 :     _current_side(0),
     114       71343 :     _current_side_elem(nullptr),
     115       71343 :     _current_side_volume(0),
     116       71343 :     _current_neighbor_elem(nullptr),
     117       71343 :     _current_neighbor_side(0),
     118       71343 :     _current_neighbor_side_elem(nullptr),
     119       71343 :     _need_neighbor_elem_volume(false),
     120       71343 :     _current_neighbor_volume(0),
     121       71343 :     _current_node(nullptr),
     122       71343 :     _current_neighbor_node(nullptr),
     123       71343 :     _current_elem_volume_computed(false),
     124       71343 :     _current_side_volume_computed(false),
     125             : 
     126       71343 :     _current_lower_d_elem(nullptr),
     127       71343 :     _current_neighbor_lower_d_elem(nullptr),
     128       71343 :     _need_lower_d_elem_volume(false),
     129       71343 :     _need_neighbor_lower_d_elem_volume(false),
     130       71343 :     _need_dual(false),
     131             : 
     132       71343 :     _residual_vector_tags(_subproblem.getVectorTags(Moose::VECTOR_TAG_RESIDUAL)),
     133       71343 :     _cached_residual_values(2), // The 2 is for TIME and NONTIME
     134       71343 :     _cached_residual_rows(2),   // The 2 is for TIME and NONTIME
     135       71343 :     _max_cached_residuals(0),
     136       71343 :     _max_cached_jacobians(0),
     137             : 
     138       71343 :     _block_diagonal_matrix(false),
     139       71343 :     _calculate_xyz(false),
     140       71343 :     _calculate_face_xyz(false),
     141       71343 :     _calculate_curvatures(false),
     142       71343 :     _calculate_ad_coord(false),
     143       71343 :     _have_p_refinement(false),
     144      285372 :     _sc(nullptr)
     145             : {
     146       71343 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
     147       71343 :   _building_helpers = true;
     148             :   // Build fe's for the helpers
     149       71343 :   buildFE(FEType(helper_order, LAGRANGE));
     150       71343 :   buildFaceFE(FEType(helper_order, LAGRANGE));
     151       71343 :   buildNeighborFE(FEType(helper_order, LAGRANGE));
     152       71343 :   buildFaceNeighborFE(FEType(helper_order, LAGRANGE));
     153       71343 :   buildLowerDFE(FEType(helper_order, LAGRANGE));
     154       71343 :   _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      277330 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     159             :   {
     160      205987 :     _holder_fe_helper[dim] = _fe[dim][FEType(helper_order, LAGRANGE)];
     161      205987 :     _holder_fe_face_helper[dim] = _fe_face[dim][FEType(helper_order, LAGRANGE)];
     162      205987 :     _holder_fe_face_neighbor_helper[dim] = _fe_face_neighbor[dim][FEType(helper_order, LAGRANGE)];
     163      205987 :     _holder_fe_neighbor_helper[dim] = _fe_neighbor[dim][FEType(helper_order, LAGRANGE)];
     164             :   }
     165             : 
     166      205987 :   for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
     167      134644 :     _holder_fe_lower_helper[dim] = _fe_lower[dim][FEType(helper_order, LAGRANGE)];
     168             : 
     169             :   // request phi, dphi, xyz, JxW, etc. data
     170       71343 :   helpersRequestData();
     171             : 
     172             :   // For 3D mortar, mortar segments are always TRI3 elements so we want FIRST LAGRANGE regardless
     173             :   // of discretization
     174       71343 :   _fe_msm = (_mesh_dimension == 2)
     175      142686 :                 ? FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(helper_order, LAGRANGE))
     176       71343 :                 : FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(FIRST, LAGRANGE));
     177             :   // This FE object should not take part in p-refinement
     178       71343 :   _fe_msm->add_p_level_in_reinit(false);
     179       71343 :   _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       71343 :   _fe_msm->get_xyz();
     183             : 
     184       71343 :   _extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
     185       71343 :   _neighbor_extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
     186       71343 : }
     187             : 
     188      131844 : Assembly::~Assembly()
     189             : {
     190      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     191      469625 :     for (auto & it : _fe[dim])
     192      278638 :       delete it.second;
     193             : 
     194      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     195      469625 :     for (auto & it : _fe_face[dim])
     196      278638 :       delete it.second;
     197             : 
     198      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     199      469625 :     for (auto & it : _fe_neighbor[dim])
     200      278638 :       delete it.second;
     201             : 
     202      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     203      469625 :     for (auto & it : _fe_face_neighbor[dim])
     204      278638 :       delete it.second;
     205             : 
     206      190987 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     207      300496 :     for (auto & it : _fe_lower[dim])
     208      175431 :       delete it.second;
     209             : 
     210      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     211      194209 :     for (auto & it : _vector_fe[dim])
     212        3222 :       delete it.second;
     213             : 
     214      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     215      194209 :     for (auto & it : _vector_fe_face[dim])
     216        3222 :       delete it.second;
     217             : 
     218      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     219      194209 :     for (auto & it : _vector_fe_neighbor[dim])
     220        3222 :       delete it.second;
     221             : 
     222      256909 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     223      194209 :     for (auto & it : _vector_fe_face_neighbor[dim])
     224        3222 :       delete it.second;
     225             : 
     226      190987 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     227      126739 :     for (auto & it : _vector_fe_lower[dim])
     228        1674 :       delete it.second;
     229             : 
     230      148271 :   for (auto & it : _ad_grad_phi_data)
     231       82349 :     it.second.release();
     232             : 
     233       67210 :   for (auto & it : _ad_vector_grad_phi_data)
     234        1288 :     it.second.release();
     235             : 
     236      142031 :   for (auto & it : _ad_grad_phi_data_face)
     237       76109 :     it.second.release();
     238             : 
     239       67210 :   for (auto & it : _ad_vector_grad_phi_data_face)
     240        1288 :     it.second.release();
     241             : 
     242       65922 :   _current_physical_points.release();
     243             : 
     244       65922 :   _coord.release();
     245       65922 :   _coord_neighbor.release();
     246       65922 :   _coord_msm.release();
     247             : 
     248       65922 :   _ad_JxW.release();
     249       65922 :   _ad_q_points.release();
     250       65922 :   _ad_JxW_face.release();
     251       65922 :   _ad_normals.release();
     252       65922 :   _ad_q_points_face.release();
     253       65922 :   _curvatures.release();
     254       65922 :   _ad_curvatures.release();
     255       65922 :   _ad_coord.release();
     256             : 
     257       65922 :   delete _qrule_msm;
     258      131844 : }
     259             : 
     260             : const MooseArray<Real> &
     261         101 : Assembly::JxWNeighbor() const
     262             : {
     263         101 :   _need_JxW_neighbor = true;
     264         101 :   return _current_JxW_neighbor;
     265             : }
     266             : 
     267             : void
     268      472701 : Assembly::buildFE(FEType type) const
     269             : {
     270      472701 :   if (!_building_helpers && type == _helper_type)
     271      209749 :     _user_added_fe_of_helper_type = true;
     272             : 
     273      472701 :   if (!_fe_shape_data[type])
     274      102617 :     _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     1888602 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     278             :   {
     279     1415901 :     if (!_fe[dim][type])
     280      298691 :       _fe[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     281             : 
     282     1415901 :     _fe[dim][type]->get_phi();
     283     1415901 :     _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     1415901 :     _fe[dim][type]->get_xyz();
     288     1415901 :     if (_need_second_derivative.count(type))
     289       87752 :       _fe[dim][type]->get_d2phi();
     290             :   }
     291      472701 : }
     292             : 
     293             : void
     294      444745 : Assembly::buildFaceFE(FEType type) const
     295             : {
     296      444745 :   if (!_building_helpers && type == _helper_type)
     297      204081 :     _user_added_fe_face_of_helper_type = true;
     298             : 
     299      444745 :   if (!_fe_shape_data_face[type])
     300      102617 :     _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     1776714 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     304             :   {
     305     1331969 :     if (!_fe_face[dim][type])
     306      298691 :       _fe_face[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     307             : 
     308     1331969 :     _fe_face[dim][type]->get_phi();
     309     1331969 :     _fe_face[dim][type]->get_dphi();
     310     1331969 :     if (_need_second_derivative.count(type))
     311       18884 :       _fe_face[dim][type]->get_d2phi();
     312             :   }
     313      444745 : }
     314             : 
     315             : void
     316      438497 : Assembly::buildNeighborFE(FEType type) const
     317             : {
     318      438497 :   if (!_building_helpers && type == _helper_type)
     319      203960 :     _user_added_fe_neighbor_of_helper_type = true;
     320             : 
     321      438497 :   if (!_fe_shape_data_neighbor[type])
     322      102617 :     _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     1751708 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     326             :   {
     327     1313211 :     if (!_fe_neighbor[dim][type])
     328      298691 :       _fe_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     329             : 
     330     1313211 :     _fe_neighbor[dim][type]->get_phi();
     331     1313211 :     _fe_neighbor[dim][type]->get_dphi();
     332     1313211 :     if (_need_second_derivative_neighbor.count(type))
     333         126 :       _fe_neighbor[dim][type]->get_d2phi();
     334             :   }
     335      438497 : }
     336             : 
     337             : void
     338      438497 : Assembly::buildFaceNeighborFE(FEType type) const
     339             : {
     340      438497 :   if (!_building_helpers && type == _helper_type)
     341      203960 :     _user_added_fe_face_neighbor_of_helper_type = true;
     342             : 
     343      438497 :   if (!_fe_shape_data_face_neighbor[type])
     344      102617 :     _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     1751708 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     348             :   {
     349     1313211 :     if (!_fe_face_neighbor[dim][type])
     350      298691 :       _fe_face_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     351             : 
     352     1313211 :     _fe_face_neighbor[dim][type]->get_phi();
     353     1313211 :     _fe_face_neighbor[dim][type]->get_dphi();
     354     1313211 :     if (_need_second_derivative_neighbor.count(type))
     355         126 :       _fe_face_neighbor[dim][type]->get_d2phi();
     356             :   }
     357      438497 : }
     358             : 
     359             : void
     360      772031 : Assembly::buildLowerDFE(FEType type) const
     361             : {
     362      772031 :   if (!_building_helpers && type == _helper_type)
     363      407336 :     _user_added_fe_lower_of_helper_type = true;
     364             : 
     365      772031 :   if (!_fe_shape_data_lower[type])
     366       97405 :     _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     2335067 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     372             :   {
     373     1563036 :     if (!_fe_lower[dim][type])
     374      188121 :       _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     375             : 
     376     1563036 :     _fe_lower[dim][type]->get_phi();
     377     1563036 :     _fe_lower[dim][type]->get_dphi();
     378     1563036 :     if (_need_second_derivative.count(type))
     379           0 :       _fe_lower[dim][type]->get_d2phi();
     380             :   }
     381      772031 : }
     382             : 
     383             : void
     384         584 : Assembly::buildLowerDDualFE(FEType type) const
     385             : {
     386         584 :   if (!_fe_shape_data_dual_lower[type])
     387         146 :     _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        1808 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     393             :   {
     394        1224 :     if (!_fe_lower[dim][type])
     395           0 :       _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     396             : 
     397        1224 :     _fe_lower[dim][type]->get_dual_phi();
     398        1224 :     _fe_lower[dim][type]->get_dual_dphi();
     399        1224 :     if (_need_second_derivative.count(type))
     400           0 :       _fe_lower[dim][type]->get_dual_d2phi();
     401             :   }
     402         584 : }
     403             : 
     404             : void
     405        6716 : Assembly::buildVectorLowerDFE(FEType type) const
     406             : {
     407        6716 :   if (!_vector_fe_shape_data_lower[type])
     408        1338 :     _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        6716 :   unsigned int dim = ((type.family == LAGRANGE_VEC) || (type.family == MONOMIAL_VEC)) ? 0 : 2;
     414        6716 :   const auto ending_dim = cast_int<unsigned int>(_mesh_dimension - 1);
     415        6716 :   if (ending_dim < dim)
     416        1796 :     return;
     417       14644 :   for (; dim <= ending_dim; dim++)
     418             :   {
     419        9724 :     if (!_vector_fe_lower[dim][type])
     420        1789 :       _vector_fe_lower[dim][type] = FEVectorBase::build(dim, type).release();
     421             : 
     422        9724 :     _vector_fe_lower[dim][type]->get_phi();
     423        9724 :     _vector_fe_lower[dim][type]->get_dphi();
     424        9724 :     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      595372 : Assembly::buildVectorFE(const FEType type) const
     456             : {
     457      595372 :   if (!_vector_fe_shape_data[type])
     458        1338 :     _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      595372 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     463        3150 :       type.family == L2_RAVIART_THOMAS)
     464      592530 :     min_dim = 2;
     465             :   else
     466        2842 :     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     1709944 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     471             :   {
     472     1114572 :     if (!_vector_fe[dim][type])
     473        3387 :       _vector_fe[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     474             : 
     475     1114572 :     _vector_fe[dim][type]->get_phi();
     476     1114572 :     _vector_fe[dim][type]->get_dphi();
     477     1114572 :     if (_need_curl.count(type))
     478       71860 :       _vector_fe[dim][type]->get_curl_phi();
     479     1114572 :     if (_need_div.count(type))
     480     1033972 :       _vector_fe[dim][type]->get_div_phi();
     481     1114572 :     _vector_fe[dim][type]->get_xyz();
     482             :   }
     483      595372 : }
     484             : 
     485             : void
     486        3918 : Assembly::buildVectorFaceFE(const FEType type) const
     487             : {
     488        3918 :   if (!_vector_fe_shape_data_face[type])
     489        1338 :     _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        3918 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     494        2630 :       type.family == L2_RAVIART_THOMAS)
     495        1442 :     min_dim = 2;
     496             :   else
     497        2476 :     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       13410 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     502             :   {
     503        9492 :     if (!_vector_fe_face[dim][type])
     504        3387 :       _vector_fe_face[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     505             : 
     506        9492 :     _vector_fe_face[dim][type]->get_phi();
     507        9492 :     _vector_fe_face[dim][type]->get_dphi();
     508        9492 :     if (_need_curl.count(type))
     509         304 :       _vector_fe_face[dim][type]->get_curl_phi();
     510        9492 :     if (_need_face_div.count(type))
     511         448 :       _vector_fe_face[dim][type]->get_div_phi();
     512             :   }
     513        3918 : }
     514             : 
     515             : void
     516        3358 : Assembly::buildVectorNeighborFE(const FEType type) const
     517             : {
     518        3358 :   if (!_vector_fe_shape_data_neighbor[type])
     519        1338 :     _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        3358 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     524        2630 :       type.family == L2_RAVIART_THOMAS)
     525         882 :     min_dim = 2;
     526             :   else
     527        2476 :     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       12098 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     532             :   {
     533        8740 :     if (!_vector_fe_neighbor[dim][type])
     534        3387 :       _vector_fe_neighbor[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     535             : 
     536        8740 :     _vector_fe_neighbor[dim][type]->get_phi();
     537        8740 :     _vector_fe_neighbor[dim][type]->get_dphi();
     538        8740 :     if (_need_curl.count(type))
     539           0 :       _vector_fe_neighbor[dim][type]->get_curl_phi();
     540        8740 :     if (_need_neighbor_div.count(type))
     541           0 :       _vector_fe_neighbor[dim][type]->get_div_phi();
     542             :   }
     543        3358 : }
     544             : 
     545             : void
     546        3918 : Assembly::buildVectorFaceNeighborFE(const FEType type) const
     547             : {
     548        3918 :   if (!_vector_fe_shape_data_face_neighbor[type])
     549        1338 :     _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        3918 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     554        2630 :       type.family == L2_RAVIART_THOMAS)
     555        1442 :     min_dim = 2;
     556             :   else
     557        2476 :     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       13410 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     562             :   {
     563        9492 :     if (!_vector_fe_face_neighbor[dim][type])
     564        3387 :       _vector_fe_face_neighbor[dim][type] =
     565        6774 :           FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     566             : 
     567        9492 :     _vector_fe_face_neighbor[dim][type]->get_phi();
     568        9492 :     _vector_fe_face_neighbor[dim][type]->get_dphi();
     569        9492 :     if (_need_curl.count(type))
     570         304 :       _vector_fe_face_neighbor[dim][type]->get_curl_phi();
     571        9492 :     if (_need_face_neighbor_div.count(type))
     572           0 :       _vector_fe_face_neighbor[dim][type]->get_div_phi();
     573             :   }
     574        3918 : }
     575             : 
     576             : void
     577          96 : Assembly::bumpVolumeQRuleOrder(Order volume_order, SubdomainID block)
     578             : {
     579          96 :   auto & qdefault = _qrules[Moose::ANY_BLOCK_ID];
     580             :   mooseAssert(qdefault.size() > 0, "default quadrature must be initialized before order bumps");
     581             : 
     582          96 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     583          96 :   auto & qvec = _qrules[block];
     584          96 :   if (qvec.size() != ndims || !qvec[0].vol)
     585          56 :     createQRules(qdefault[0].vol->type(),
     586          28 :                  qdefault[0].arbitrary_vol->get_order(),
     587             :                  volume_order,
     588          28 :                  qdefault[0].face->get_order(),
     589             :                  block);
     590          68 :   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          96 : }
     598             : 
     599             : void
     600          16 : Assembly::bumpAllQRuleOrder(Order order, SubdomainID block)
     601             : {
     602          16 :   auto & qdefault = _qrules[Moose::ANY_BLOCK_ID];
     603             :   mooseAssert(qdefault.size() > 0, "default quadrature must be initialized before order bumps");
     604             : 
     605          16 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     606          16 :   auto & qvec = _qrules[block];
     607          16 :   if (qvec.size() != ndims || !qvec[0].vol)
     608          14 :     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          16 : }
     617             : 
     618             : void
     619       70953 : 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       70953 :   auto & qvec = _qrules[block];
     627       70953 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     628       70953 :   if (qvec.size() != ndims)
     629       70953 :     qvec.resize(ndims);
     630             : 
     631      275774 :   for (unsigned int i = 0; i < qvec.size(); i++)
     632             :   {
     633      204821 :     int dim = i;
     634      204821 :     auto & q = qvec[dim];
     635      204821 :     q.vol = QBase::build(type, dim, volume_order);
     636      204821 :     q.vol->allow_rules_with_negative_weights = allow_negative_qweights;
     637      204821 :     q.face = QBase::build(type, dim - 1, face_order);
     638      204821 :     q.face->allow_rules_with_negative_weights = allow_negative_qweights;
     639      204821 :     q.fv_face = QBase::build(QMONOMIAL, dim - 1, CONSTANT);
     640      204821 :     q.fv_face->allow_rules_with_negative_weights = allow_negative_qweights;
     641      204821 :     q.neighbor = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
     642      204821 :     q.neighbor->allow_rules_with_negative_weights = allow_negative_qweights;
     643      204821 :     q.arbitrary_vol = std::make_unique<ArbitraryQuadrature>(dim, order);
     644      204821 :     q.arbitrary_vol->allow_rules_with_negative_weights = allow_negative_qweights;
     645      204821 :     q.arbitrary_face = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
     646      204821 :     q.arbitrary_face->allow_rules_with_negative_weights = allow_negative_qweights;
     647             :   }
     648             : 
     649       70953 :   delete _qrule_msm;
     650       70953 :   _custom_mortar_qrule = false;
     651       70953 :   _qrule_msm = QBase::build(type, _mesh_dimension - 1, face_order).release();
     652       70953 :   _qrule_msm->allow_rules_with_negative_weights = allow_negative_qweights;
     653       70953 :   _fe_msm->attach_quadrature_rule(_qrule_msm);
     654       70953 : }
     655             : 
     656             : void
     657      243172 : Assembly::setVolumeQRule(QBase * qrule, unsigned int dim)
     658             : {
     659      243172 :   _current_qrule = qrule;
     660             : 
     661      243172 :   if (qrule) // Don't set a NULL qrule
     662             :   {
     663      586398 :     for (auto & it : _fe[dim])
     664      343226 :       it.second->attach_quadrature_rule(qrule);
     665      247441 :     for (auto & it : _vector_fe[dim])
     666        4269 :       it.second->attach_quadrature_rule(qrule);
     667      243172 :     if (!_unique_fe_helper.empty())
     668             :     {
     669             :       mooseAssert(dim < _unique_fe_helper.size(), "We should not be indexing out of bounds");
     670         232 :       _unique_fe_helper[dim]->attach_quadrature_rule(qrule);
     671             :     }
     672             :   }
     673      243172 : }
     674             : 
     675             : void
     676      609319 : Assembly::setFaceQRule(QBase * qrule, unsigned int dim)
     677             : {
     678      609319 :   _current_qrule_face = qrule;
     679             : 
     680     1432904 :   for (auto & it : _fe_face[dim])
     681      823585 :     it.second->attach_quadrature_rule(qrule);
     682      609980 :   for (auto & it : _vector_fe_face[dim])
     683         661 :     it.second->attach_quadrature_rule(qrule);
     684      609319 :   if (!_unique_fe_face_helper.empty())
     685             :   {
     686             :     mooseAssert(dim < _unique_fe_face_helper.size(), "We should not be indexing out of bounds");
     687         217 :     _unique_fe_face_helper[dim]->attach_quadrature_rule(qrule);
     688             :   }
     689      609319 : }
     690             : 
     691             : void
     692      284549 : Assembly::setLowerQRule(QBase * qrule, unsigned int dim)
     693             : {
     694             :   // The lower-dimensional quadrature rule matches the face quadrature rule
     695      284549 :   setFaceQRule(qrule, dim);
     696             : 
     697      284549 :   _current_qrule_lower = qrule;
     698             : 
     699      660957 :   for (auto & it : _fe_lower[dim])
     700      376408 :     it.second->attach_quadrature_rule(qrule);
     701      284549 :   for (auto & it : _vector_fe_lower[dim])
     702           0 :     it.second->attach_quadrature_rule(qrule);
     703      284549 :   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      284549 : }
     709             : 
     710             : void
     711    29115844 : Assembly::setNeighborQRule(QBase * qrule, unsigned int dim)
     712             : {
     713    29115844 :   _current_qrule_neighbor = qrule;
     714             : 
     715    86871373 :   for (auto & it : _fe_face_neighbor[dim])
     716    57755529 :     it.second->attach_quadrature_rule(qrule);
     717    29144407 :   for (auto & it : _vector_fe_face_neighbor[dim])
     718       28563 :     it.second->attach_quadrature_rule(qrule);
     719    29115844 :   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       68880 :     _unique_fe_face_neighbor_helper[dim]->attach_quadrature_rule(qrule);
     724             :   }
     725    29115844 : }
     726             : 
     727             : void
     728       67251 : Assembly::clearCachedQRules()
     729             : {
     730       67251 :   _current_qrule = nullptr;
     731       67251 :   _current_qrule_face = nullptr;
     732       67251 :   _current_qrule_lower = nullptr;
     733       67251 :   _current_qrule_neighbor = nullptr;
     734       67251 : }
     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   440075306 : Assembly::reinitFE(const Elem * elem)
     763             : {
     764   440075306 :   unsigned int dim = elem->dim();
     765             : 
     766   991661836 :   for (const auto & it : _fe[dim])
     767             :   {
     768   551586558 :     FEBase & fe = *it.second;
     769   551586558 :     const FEType & fe_type = it.first;
     770             : 
     771   551586558 :     _current_fe[fe_type] = &fe;
     772             : 
     773   551586558 :     FEShapeData & fesd = *_fe_shape_data[fe_type];
     774             : 
     775   551586558 :     fe.reinit(elem);
     776             : 
     777   551586530 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_phi()));
     778   551586530 :     fesd._grad_phi.shallowCopy(
     779   551586530 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_dphi()));
     780   551586530 :     if (_need_second_derivative.count(fe_type))
     781       66221 :       fesd._second_phi.shallowCopy(
     782       66221 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe.get_d2phi()));
     783             :   }
     784   445963199 :   for (const auto & it : _vector_fe[dim])
     785             :   {
     786     5887921 :     FEVectorBase & fe = *it.second;
     787     5887921 :     const FEType & fe_type = it.first;
     788             : 
     789     5887921 :     _current_vector_fe[fe_type] = &fe;
     790             : 
     791     5887921 :     VectorFEShapeData & fesd = *_vector_fe_shape_data[fe_type];
     792             : 
     793     5887921 :     fe.reinit(elem);
     794             : 
     795     5887921 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_phi()));
     796     5887921 :     fesd._grad_phi.shallowCopy(
     797     5887921 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe.get_dphi()));
     798     5887921 :     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     5887921 :     if (_need_curl.count(fe_type))
     802     2442307 :       fesd._curl_phi.shallowCopy(
     803     2442307 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_curl_phi()));
     804     5887921 :     if (_need_div.count(fe_type))
     805     1280464 :       fesd._div_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_div_phi()));
     806             :   }
     807   440075278 :   if (!_unique_fe_helper.empty())
     808             :   {
     809             :     mooseAssert(dim < _unique_fe_helper.size(), "We should be in bounds here");
     810      766348 :     _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   440075278 :   _current_q_points.shallowCopy(
     816   440075278 :       const_cast<std::vector<Point> &>(_holder_fe_helper[dim]->get_xyz()));
     817   440075278 :   _current_JxW.shallowCopy(const_cast<std::vector<Real> &>(_holder_fe_helper[dim]->get_JxW()));
     818             : 
     819   440075278 :   if (_subproblem.haveADObjects())
     820             :   {
     821    35266901 :     auto n_qp = _current_qrule->n_points();
     822    35266901 :     resizeADMappingObjects(n_qp, dim);
     823    35266901 :     if (_displaced)
     824             :     {
     825      604736 :       const auto & qw = _current_qrule->get_weights();
     826     3308087 :       for (unsigned int qp = 0; qp != n_qp; qp++)
     827     2703351 :         computeSinglePointMapAD(elem, qw, qp, _holder_fe_helper[dim]);
     828             :     }
     829             :     else
     830             :     {
     831   112910042 :       for (unsigned qp = 0; qp < n_qp; ++qp)
     832    78247877 :         _ad_JxW[qp] = _current_JxW[qp];
     833    34662165 :       if (_calculate_xyz)
     834    62703798 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     835    49742340 :           _ad_q_points[qp] = _current_q_points[qp];
     836             :     }
     837             : 
     838    94977251 :     for (const auto & it : _fe[dim])
     839             :     {
     840    59710350 :       FEBase & fe = *it.second;
     841    59710350 :       auto fe_type = it.first;
     842    59710350 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
     843    59710350 :       auto & grad_phi = _ad_grad_phi_data[fe_type];
     844             : 
     845    59710350 :       grad_phi.resize(num_shapes);
     846   232093017 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     847   172382667 :         grad_phi[i].resize(n_qp);
     848             : 
     849    59710350 :       if (_displaced)
     850      924260 :         computeGradPhiAD(elem, n_qp, grad_phi, &fe);
     851             :       else
     852             :       {
     853    58786090 :         const auto & regular_grad_phi = _fe_shape_data[fe_type]->_grad_phi;
     854   227950999 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     855   704936162 :           for (unsigned qp = 0; qp < n_qp; ++qp)
     856   535771253 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
     857             :       }
     858             :     }
     859    38464566 :     for (const auto & it : _vector_fe[dim])
     860             :     {
     861     3197665 :       FEVectorBase & fe = *it.second;
     862     3197665 :       auto fe_type = it.first;
     863     3197665 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
     864     3197665 :       auto & grad_phi = _ad_vector_grad_phi_data[fe_type];
     865             : 
     866     3197665 :       grad_phi.resize(num_shapes);
     867    19344705 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     868    16147040 :         grad_phi[i].resize(n_qp);
     869             : 
     870     3197665 :       if (_displaced)
     871           0 :         computeGradPhiAD(elem, n_qp, grad_phi, &fe);
     872             :       else
     873             :       {
     874     3197665 :         const auto & regular_grad_phi = _vector_fe_shape_data[fe_type]->_grad_phi;
     875    19344705 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     876    82622780 :           for (unsigned qp = 0; qp < n_qp; ++qp)
     877    66475740 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
     878             :       }
     879             :     }
     880             :   }
     881             : 
     882   440075278 :   auto n = numExtraElemIntegers();
     883   443111271 :   for (auto i : make_range(n))
     884     3035993 :     _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
     885   440075278 :   _extra_elem_ids[n] = _current_elem->subdomain_id();
     886             : 
     887   440075278 :   if (_xfem != nullptr)
     888           0 :     modifyWeightsDueToXFEM(elem);
     889   440075278 : }
     890             : 
     891             : template <typename OutputType>
     892             : void
     893     1071158 : 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     1071158 :   auto dim = elem->dim();
     910     1071158 :   const auto & dphidxi = fe->get_dphidxi();
     911     1071158 :   const auto & dphideta = fe->get_dphideta();
     912     1071158 :   const auto & dphidzeta = fe->get_dphidzeta();
     913     1071158 :   auto num_shapes = grad_phi.size();
     914             : 
     915     1071158 :   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       56398 :     case 1:
     926             :     {
     927      150945 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     928      296221 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     929             :         {
     930      201674 :           grad_phi[i][qp].slice(0) = dphidxi[i][qp] * _ad_dxidx_map[qp];
     931      201674 :           grad_phi[i][qp].slice(1) = dphidxi[i][qp] * _ad_dxidy_map[qp];
     932      201674 :           grad_phi[i][qp].slice(2) = dphidxi[i][qp] * _ad_dxidz_map[qp];
     933             :         }
     934       56398 :       break;
     935             :     }
     936             : 
     937     1014760 :     case 2:
     938             :     {
     939     4907901 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     940    22436590 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     941             :         {
     942    37086898 :           grad_phi[i][qp].slice(0) =
     943    37086898 :               dphidxi[i][qp] * _ad_dxidx_map[qp] + dphideta[i][qp] * _ad_detadx_map[qp];
     944    37086898 :           grad_phi[i][qp].slice(1) =
     945    37086898 :               dphidxi[i][qp] * _ad_dxidy_map[qp] + dphideta[i][qp] * _ad_detady_map[qp];
     946    37086898 :           grad_phi[i][qp].slice(2) =
     947    37086898 :               dphidxi[i][qp] * _ad_dxidz_map[qp] + dphideta[i][qp] * _ad_detadz_map[qp];
     948             :         }
     949     1014760 :       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     1071158 : }
     971             : 
     972             : void
     973    39439685 : Assembly::resizeADMappingObjects(unsigned int n_qp, unsigned int dim)
     974             : {
     975    39439685 :   _ad_dxyzdxi_map.resize(n_qp);
     976    39439685 :   _ad_dxidx_map.resize(n_qp);
     977    39439685 :   _ad_dxidy_map.resize(n_qp); // 1D element may live in 2D ...
     978    39439685 :   _ad_dxidz_map.resize(n_qp); // ... or 3D
     979             : 
     980    39439685 :   if (dim > 1)
     981             :   {
     982    24175687 :     _ad_dxyzdeta_map.resize(n_qp);
     983    24175687 :     _ad_detadx_map.resize(n_qp);
     984    24175687 :     _ad_detady_map.resize(n_qp);
     985    24175687 :     _ad_detadz_map.resize(n_qp);
     986             : 
     987    24175687 :     if (dim > 2)
     988             :     {
     989      526662 :       _ad_dxyzdzeta_map.resize(n_qp);
     990      526662 :       _ad_dzetadx_map.resize(n_qp);
     991      526662 :       _ad_dzetady_map.resize(n_qp);
     992      526662 :       _ad_dzetadz_map.resize(n_qp);
     993             :     }
     994             :   }
     995             : 
     996    39439685 :   _ad_jac.resize(n_qp);
     997    39439685 :   _ad_JxW.resize(n_qp);
     998    39439685 :   if (_calculate_xyz)
     999    17044195 :     _ad_q_points.resize(n_qp);
    1000    39439685 : }
    1001             : 
    1002             : void
    1003     2823217 : 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     2823217 :   auto dim = elem->dim();
    1046     2823217 :   const auto & elem_nodes = elem->get_nodes();
    1047     2823217 :   auto num_shapes = FEInterface::n_shape_functions(fe->get_fe_type(), elem);
    1048     2823217 :   const auto & phi_map = fe->get_fe_map().get_phi_map();
    1049     2823217 :   const auto & dphidxi_map = fe->get_fe_map().get_dphidxi_map();
    1050     2823217 :   const auto & dphideta_map = fe->get_fe_map().get_dphideta_map();
    1051     2823217 :   const auto & dphidzeta_map = fe->get_fe_map().get_dphidzeta_map();
    1052     2823217 :   const auto sys_num = _sys.number();
    1053             :   const bool do_derivatives =
    1054     2823217 :       ADReal::do_derivatives && _sys.number() == _subproblem.currentNlSysNum();
    1055             : 
    1056     2823217 :   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       68068 :     case 1:
    1068             :     {
    1069       68068 :       if (_calculate_xyz)
    1070       12690 :         _ad_q_points[p].zero();
    1071             : 
    1072       68068 :       _ad_dxyzdxi_map[p].zero();
    1073             : 
    1074      212124 :       for (std::size_t i = 0; i < num_shapes; i++)
    1075             :       {
    1076             :         libmesh_assert(elem_nodes[i]);
    1077      144056 :         const Node & node = *elem_nodes[i];
    1078      144056 :         libMesh::VectorValue<ADReal> elem_point = node;
    1079      144056 :         if (do_derivatives)
    1080       55304 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1081        2802 :             if (node.n_dofs(sys_num, disp_num))
    1082        5604 :               Moose::derivInsert(
    1083        2802 :                   elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1084             : 
    1085      144056 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1086             : 
    1087      144056 :         if (_calculate_xyz)
    1088       33300 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1089      144056 :       }
    1090             : 
    1091       68068 :       _ad_jac[p] = _ad_dxyzdxi_map[p].norm();
    1092             : 
    1093       68068 :       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       68068 :       const auto jacm2 = 1. / _ad_jac[p] / _ad_jac[p];
    1108       68068 :       _ad_dxidx_map[p] = jacm2 * _ad_dxyzdxi_map[p](0);
    1109       68068 :       _ad_dxidy_map[p] = jacm2 * _ad_dxyzdxi_map[p](1);
    1110       68068 :       _ad_dxidz_map[p] = jacm2 * _ad_dxyzdxi_map[p](2);
    1111             : 
    1112       68068 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1113             : 
    1114       68068 :       break;
    1115       68068 :     }
    1116             : 
    1117     2755149 :     case 2:
    1118             :     {
    1119     2755149 :       if (_calculate_xyz)
    1120     1923033 :         _ad_q_points[p].zero();
    1121     2755149 :       _ad_dxyzdxi_map[p].zero();
    1122     2755149 :       _ad_dxyzdeta_map[p].zero();
    1123             : 
    1124    16781334 :       for (std::size_t i = 0; i < num_shapes; i++)
    1125             :       {
    1126             :         libmesh_assert(elem_nodes[i]);
    1127    14026185 :         const Node & node = *elem_nodes[i];
    1128    14026185 :         libMesh::VectorValue<ADReal> elem_point = node;
    1129    14026185 :         if (do_derivatives)
    1130     1669592 :           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    14026185 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1136    14026185 :         _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
    1137             : 
    1138    14026185 :         if (_calculate_xyz)
    1139    11336097 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1140    14026185 :       }
    1141             : 
    1142     2755149 :       const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dx_deta = _ad_dxyzdeta_map[p](0),
    1143     2755149 :                  &dy_dxi = _ad_dxyzdxi_map[p](1), &dy_deta = _ad_dxyzdeta_map[p](1),
    1144     2755149 :                  &dz_dxi = _ad_dxyzdxi_map[p](2), &dz_deta = _ad_dxyzdeta_map[p](2);
    1145             : 
    1146     2755149 :       const auto g11 = (dx_dxi * dx_dxi + dy_dxi * dy_dxi + dz_dxi * dz_dxi);
    1147             : 
    1148     2755149 :       const auto g12 = (dx_dxi * dx_deta + dy_dxi * dy_deta + dz_dxi * dz_deta);
    1149             : 
    1150     2755149 :       const auto & g21 = g12;
    1151             : 
    1152     2755149 :       const auto g22 = (dx_deta * dx_deta + dy_deta * dy_deta + dz_deta * dz_deta);
    1153             : 
    1154     2755149 :       auto det = (g11 * g22 - g12 * g21);
    1155             : 
    1156     2755149 :       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     2755149 :       else if (det.value() <= 0.)
    1170           0 :         det.value() = TOLERANCE * TOLERANCE;
    1171             : 
    1172     2755149 :       const auto inv_det = 1. / det;
    1173     2755149 :       _ad_jac[p] = std::sqrt(det);
    1174             : 
    1175     2755149 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1176             : 
    1177     2755149 :       const auto g11inv = g22 * inv_det;
    1178     2755149 :       const auto g12inv = -g12 * inv_det;
    1179     2755149 :       const auto g21inv = -g21 * inv_det;
    1180     2755149 :       const auto g22inv = g11 * inv_det;
    1181             : 
    1182     2755149 :       _ad_dxidx_map[p] = g11inv * dx_dxi + g12inv * dx_deta;
    1183     2755149 :       _ad_dxidy_map[p] = g11inv * dy_dxi + g12inv * dy_deta;
    1184     2755149 :       _ad_dxidz_map[p] = g11inv * dz_dxi + g12inv * dz_deta;
    1185             : 
    1186     2755149 :       _ad_detadx_map[p] = g21inv * dx_dxi + g22inv * dx_deta;
    1187     2755149 :       _ad_detady_map[p] = g21inv * dy_dxi + g22inv * dy_deta;
    1188     2755149 :       _ad_detadz_map[p] = g21inv * dz_dxi + g22inv * dz_deta;
    1189             : 
    1190     2755149 :       break;
    1191    13775745 :     }
    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    12729629 : Assembly::reinitFEFace(const Elem * elem, unsigned int side)
    1270             : {
    1271    12729629 :   unsigned int dim = elem->dim();
    1272             : 
    1273    40019190 :   for (const auto & it : _fe_face[dim])
    1274             :   {
    1275    27289561 :     FEBase & fe_face = *it.second;
    1276    27289561 :     const FEType & fe_type = it.first;
    1277    27289561 :     FEShapeData & fesd = *_fe_shape_data_face[fe_type];
    1278    27289561 :     fe_face.reinit(elem, side);
    1279    27289561 :     _current_fe_face[fe_type] = &fe_face;
    1280             : 
    1281    27289561 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
    1282    27289561 :     fesd._grad_phi.shallowCopy(
    1283    27289561 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_dphi()));
    1284    27289561 :     if (_need_second_derivative.count(fe_type))
    1285       18513 :       fesd._second_phi.shallowCopy(
    1286       18513 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
    1287             :   }
    1288    15518701 :   for (const auto & it : _vector_fe_face[dim])
    1289             :   {
    1290     2789072 :     FEVectorBase & fe_face = *it.second;
    1291     2789072 :     const FEType & fe_type = it.first;
    1292             : 
    1293     2789072 :     _current_vector_fe_face[fe_type] = &fe_face;
    1294             : 
    1295     2789072 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
    1296             : 
    1297     2789072 :     fe_face.reinit(elem, side);
    1298             : 
    1299     2789072 :     fesd._phi.shallowCopy(
    1300     2789072 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
    1301     2789072 :     fesd._grad_phi.shallowCopy(
    1302     2789072 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
    1303     2789072 :     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     2789072 :     if (_need_curl.count(fe_type))
    1307      487970 :       fesd._curl_phi.shallowCopy(
    1308      487970 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
    1309     2789072 :     if (_need_face_div.count(fe_type))
    1310       42336 :       fesd._div_phi.shallowCopy(
    1311       42336 :           const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
    1312             :   }
    1313    12729629 :   if (!_unique_fe_face_helper.empty())
    1314             :   {
    1315             :     mooseAssert(dim < _unique_fe_face_helper.size(), "We should be in bounds here");
    1316      118556 :     _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    12729629 :   _current_q_points_face.shallowCopy(
    1322    12729629 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_xyz()));
    1323    12729629 :   _current_JxW_face.shallowCopy(
    1324    12729629 :       const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_JxW()));
    1325    12729629 :   _current_normals.shallowCopy(
    1326    12729629 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_normals()));
    1327             : 
    1328    12729629 :   _mapped_normals.resize(_current_normals.size(), Eigen::Map<RealDIMValue>(nullptr));
    1329    41425756 :   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    28696127 :     new (&_mapped_normals[i]) Eigen::Map<RealDIMValue>(const_cast<Real *>(&_current_normals[i](0)));
    1332             : 
    1333    12729629 :   if (_calculate_curvatures)
    1334         468 :     _curvatures.shallowCopy(
    1335         468 :         const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_curvatures()));
    1336             : 
    1337    12729629 :   computeADFace(*elem, side);
    1338             : 
    1339    12729629 :   if (_xfem != nullptr)
    1340           0 :     modifyFaceWeightsDueToXFEM(elem, side);
    1341             : 
    1342    12729629 :   auto n = numExtraElemIntegers();
    1343    12889089 :   for (auto i : make_range(n))
    1344      159460 :     _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
    1345    12729629 :   _extra_elem_ids[n] = _current_elem->subdomain_id();
    1346    12729629 : }
    1347             : 
    1348             : void
    1349       60088 : 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       60088 :   const Elem & side_elem = _compute_face_map_side_elem_builder(elem, side);
    1358       60088 :   const auto dim = elem.dim();
    1359       60088 :   const auto n_qp = qw.size();
    1360       60088 :   const auto & dpsidxi_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsidxi();
    1361       60088 :   const auto & dpsideta_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsideta();
    1362       60088 :   const auto & psi_map = _holder_fe_face_helper[dim]->get_fe_map().get_psi();
    1363       60088 :   std::vector<std::vector<Real>> const * d2psidxi2_map = nullptr;
    1364       60088 :   std::vector<std::vector<Real>> const * d2psidxideta_map = nullptr;
    1365       60088 :   std::vector<std::vector<Real>> const * d2psideta2_map = nullptr;
    1366       60088 :   const auto sys_num = _sys.number();
    1367       60088 :   const bool do_derivatives = ADReal::do_derivatives && sys_num == _subproblem.currentNlSysNum();
    1368             : 
    1369       60088 :   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       60088 :   switch (dim)
    1377             :   {
    1378         310 :     case 1:
    1379             :     {
    1380         310 :       if (!n_qp)
    1381           0 :         break;
    1382             : 
    1383         310 :       if (side_elem.node_id(0) == elem.node_id(0))
    1384         310 :         _ad_normals[0] = Point(-1.);
    1385             :       else
    1386           0 :         _ad_normals[0] = Point(1.);
    1387             : 
    1388         310 :       VectorValue<ADReal> side_point;
    1389         310 :       if (_calculate_face_xyz)
    1390             :       {
    1391         310 :         const Node & node = side_elem.node_ref(0);
    1392         310 :         side_point = node;
    1393             : 
    1394         310 :         if (do_derivatives)
    1395         140 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1396         140 :             Moose::derivInsert(
    1397          70 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1398             :       }
    1399             : 
    1400         620 :       for (const auto p : make_range(n_qp))
    1401             :       {
    1402         310 :         if (_calculate_face_xyz)
    1403             :         {
    1404         310 :           _ad_q_points_face[p].zero();
    1405         310 :           _ad_q_points_face[p].add_scaled(side_point, psi_map[0][p]);
    1406             :         }
    1407             : 
    1408         310 :         _ad_normals[p] = _ad_normals[0];
    1409         310 :         _ad_JxW_face[p] = 1.0 * qw[p];
    1410             :       }
    1411             : 
    1412         310 :       break;
    1413         310 :     }
    1414             : 
    1415       59778 :     case 2:
    1416             :     {
    1417       59778 :       _ad_dxyzdxi_map.resize(n_qp);
    1418       59778 :       if (_calculate_curvatures)
    1419           0 :         _ad_d2xyzdxi2_map.resize(n_qp);
    1420             : 
    1421      179334 :       for (const auto p : make_range(n_qp))
    1422      119556 :         _ad_dxyzdxi_map[p].zero();
    1423       59778 :       if (_calculate_face_xyz)
    1424      111774 :         for (const auto p : make_range(n_qp))
    1425       74516 :           _ad_q_points_face[p].zero();
    1426       59778 :       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       59778 :           FE<2, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
    1432             : 
    1433      211734 :       for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
    1434             :       {
    1435      151956 :         const Node & node = side_elem.node_ref(i);
    1436      151956 :         VectorValue<ADReal> side_point = node;
    1437             : 
    1438      151956 :         if (do_derivatives)
    1439       42548 :           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      455868 :         for (const auto p : make_range(n_qp))
    1444      303912 :           _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
    1445      151956 :         if (_calculate_face_xyz)
    1446      320748 :           for (const auto p : make_range(n_qp))
    1447      213832 :             _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
    1448      151956 :         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      151956 :       }
    1452             : 
    1453      179334 :       for (const auto p : make_range(n_qp))
    1454             :       {
    1455      119556 :         _ad_normals[p] =
    1456      239112 :             (VectorValue<ADReal>(_ad_dxyzdxi_map[p](1), -_ad_dxyzdxi_map[p](0), 0.)).unit();
    1457      119556 :         const auto the_jac = _ad_dxyzdxi_map[p].norm();
    1458      119556 :         _ad_JxW_face[p] = the_jac * qw[p];
    1459      119556 :         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      119556 :       }
    1467             : 
    1468       59778 :       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       60088 : }
    1571             : 
    1572             : void
    1573     4294203 : Assembly::reinitFEFaceNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1574             : {
    1575     4294203 :   unsigned int neighbor_dim = neighbor->dim();
    1576             : 
    1577             :   // reinit neighbor face
    1578    12627429 :   for (const auto & it : _fe_face_neighbor[neighbor_dim])
    1579             :   {
    1580     8333226 :     FEBase & fe_face_neighbor = *it.second;
    1581     8333226 :     FEType fe_type = it.first;
    1582     8333226 :     FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
    1583             : 
    1584     8333226 :     fe_face_neighbor.reinit(neighbor, &reference_points);
    1585             : 
    1586     8333226 :     _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    1587             : 
    1588     8333226 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
    1589     8333226 :     fesd._grad_phi.shallowCopy(
    1590     8333226 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
    1591     8333226 :     if (_need_second_derivative_neighbor.count(fe_type))
    1592        9720 :       fesd._second_phi.shallowCopy(
    1593        9720 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
    1594             :   }
    1595     4322766 :   for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
    1596             :   {
    1597       28563 :     FEVectorBase & fe_face_neighbor = *it.second;
    1598       28563 :     const FEType & fe_type = it.first;
    1599             : 
    1600       28563 :     _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    1601             : 
    1602       28563 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
    1603             : 
    1604       28563 :     fe_face_neighbor.reinit(neighbor, &reference_points);
    1605             : 
    1606       28563 :     fesd._phi.shallowCopy(
    1607       28563 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
    1608       28563 :     fesd._grad_phi.shallowCopy(
    1609       28563 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
    1610       28563 :     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       28563 :     if (_need_curl.count(fe_type))
    1614         120 :       fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
    1615         120 :           fe_face_neighbor.get_curl_phi()));
    1616       28563 :     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     4294203 :   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       68880 :     _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
    1625             :   }
    1626             : 
    1627     4294203 :   _current_q_points_face_neighbor.shallowCopy(
    1628     4294203 :       const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
    1629     4294203 : }
    1630             : 
    1631             : void
    1632       22720 : Assembly::reinitFENeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1633             : {
    1634       22720 :   unsigned int neighbor_dim = neighbor->dim();
    1635             : 
    1636             :   // reinit neighbor face
    1637       45440 :   for (const auto & it : _fe_neighbor[neighbor_dim])
    1638             :   {
    1639       22720 :     FEBase & fe_neighbor = *it.second;
    1640       22720 :     FEType fe_type = it.first;
    1641       22720 :     FEShapeData & fesd = *_fe_shape_data_neighbor[fe_type];
    1642             : 
    1643       22720 :     fe_neighbor.reinit(neighbor, &reference_points);
    1644             : 
    1645       22720 :     _current_fe_neighbor[fe_type] = &fe_neighbor;
    1646             : 
    1647       22720 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_phi()));
    1648       22720 :     fesd._grad_phi.shallowCopy(
    1649       22720 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_neighbor.get_dphi()));
    1650       22720 :     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       22720 :   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       22720 :   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       22720 : }
    1685             : 
    1686             : void
    1687     4316923 : Assembly::reinitNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1688             : {
    1689     4316923 :   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     4316923 :       qrules(neighbor_dim, _current_neighbor_subdomain_id).neighbor.get();
    1695     4316923 :   neighbor_rule->setPoints(reference_points);
    1696     4316923 :   setNeighborQRule(neighbor_rule, neighbor_dim);
    1697             : 
    1698     4316923 :   _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     4316923 :   if (_need_neighbor_elem_volume)
    1704             :   {
    1705     2348334 :     unsigned int dim = neighbor->dim();
    1706     2348334 :     FEBase & fe = *_holder_fe_neighbor_helper[dim];
    1707     2348334 :     QBase * qrule = qrules(dim).vol.get();
    1708             : 
    1709     2348334 :     fe.attach_quadrature_rule(qrule);
    1710     2348334 :     fe.reinit(neighbor);
    1711             : 
    1712     2348334 :     const std::vector<Real> & JxW = fe.get_JxW();
    1713     2348334 :     MooseArray<Point> q_points;
    1714     2348334 :     q_points.shallowCopy(const_cast<std::vector<Point> &>(fe.get_xyz()));
    1715             : 
    1716     2348334 :     setCoordinateTransformation(qrule, q_points, _coord_neighbor, _current_neighbor_subdomain_id);
    1717             : 
    1718     2348334 :     _current_neighbor_volume = 0.;
    1719    20139236 :     for (unsigned int qp = 0; qp < qrule->n_points(); qp++)
    1720    17790902 :       _current_neighbor_volume += JxW[qp] * _coord_neighbor[qp];
    1721     2348334 :   }
    1722             : 
    1723     4316923 :   auto n = numExtraElemIntegers();
    1724     4406233 :   for (auto i : make_range(n))
    1725       89310 :     _neighbor_extra_elem_ids[i] = _current_neighbor_elem->get_extra_integer(i);
    1726     4316923 :   _neighbor_extra_elem_ids[n] = _current_neighbor_elem->subdomain_id();
    1727     4316923 : }
    1728             : 
    1729             : template <typename Points, typename Coords>
    1730             : void
    1731   472749566 : 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   472749566 :   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   472749566 :   _coord_type = _subproblem.getCoordSystem(sub_id);
    1747             : 
    1748   472749566 :   coord.resize(n_points);
    1749  2510854763 :   for (unsigned int qp = 0; qp < n_points; qp++)
    1750  2038105197 :     coordTransformFactor(_subproblem, sub_id, q_points[qp], coord[qp]);
    1751   472749566 : }
    1752             : 
    1753             : void
    1754   440075278 : Assembly::computeCurrentElemVolume()
    1755             : {
    1756   440075278 :   if (_current_elem_volume_computed)
    1757           0 :     return;
    1758             : 
    1759   440075278 :   setCoordinateTransformation(
    1760   440075278 :       _current_qrule, _current_q_points, _coord, _current_elem->subdomain_id());
    1761   440075278 :   if (_calculate_ad_coord)
    1762    13341736 :     setCoordinateTransformation(
    1763    13341736 :         _current_qrule, _ad_q_points, _ad_coord, _current_elem->subdomain_id());
    1764             : 
    1765   440075278 :   _current_elem_volume = 0.;
    1766  2369701447 :   for (unsigned int qp = 0; qp < _current_qrule->n_points(); qp++)
    1767  1929626169 :     _current_elem_volume += _current_JxW[qp] * _coord[qp];
    1768             : 
    1769   440075278 :   _current_elem_volume_computed = true;
    1770             : }
    1771             : 
    1772             : void
    1773    12729629 : Assembly::computeCurrentFaceVolume()
    1774             : {
    1775    12729629 :   if (_current_side_volume_computed)
    1776           0 :     return;
    1777             : 
    1778    12729629 :   setCoordinateTransformation(
    1779    12729629 :       _current_qrule_face, _current_q_points_face, _coord, _current_elem->subdomain_id());
    1780    12729629 :   if (_calculate_ad_coord)
    1781     3682863 :     setCoordinateTransformation(
    1782     3682863 :         _current_qrule_face, _ad_q_points_face, _ad_coord, _current_elem->subdomain_id());
    1783             : 
    1784    12729629 :   _current_side_volume = 0.;
    1785    41425756 :   for (unsigned int qp = 0; qp < _current_qrule_face->n_points(); qp++)
    1786    28696127 :     _current_side_volume += _current_JxW_face[qp] * _coord[qp];
    1787             : 
    1788    12729629 :   _current_side_volume_computed = true;
    1789             : }
    1790             : 
    1791             : void
    1792      395420 : Assembly::reinitAtPhysical(const Elem * elem, const std::vector<Point> & physical_points)
    1793             : {
    1794      395420 :   _current_elem = elem;
    1795      395420 :   _current_neighbor_elem = nullptr;
    1796             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1797             :               "current subdomain has been set incorrectly");
    1798      395420 :   _current_elem_volume_computed = false;
    1799             : 
    1800      395420 :   FEMap::inverse_map(elem->dim(), elem, physical_points, _temp_reference_points);
    1801             : 
    1802      395420 :   reinit(elem, _temp_reference_points);
    1803             : 
    1804             :   // Save off the physical points
    1805      395420 :   _current_physical_points = physical_points;
    1806      395420 : }
    1807             : 
    1808             : void
    1809   439760111 : Assembly::setVolumeQRule(const Elem * const elem)
    1810             : {
    1811   439760111 :   unsigned int elem_dimension = elem->dim();
    1812   439760111 :   _current_qrule_volume = qrules(elem_dimension).vol.get();
    1813             :   // Make sure the qrule is the right one
    1814   439760111 :   if (_current_qrule != _current_qrule_volume)
    1815      209372 :     setVolumeQRule(_current_qrule_volume, elem_dimension);
    1816   439760111 : }
    1817             : 
    1818             : void
    1819   439679886 : Assembly::reinit(const Elem * elem)
    1820             : {
    1821   439679886 :   _current_elem = elem;
    1822   439679886 :   _current_neighbor_elem = nullptr;
    1823             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1824             :               "current subdomain has been set incorrectly");
    1825   439679886 :   _current_elem_volume_computed = false;
    1826   439679886 :   if (_sc)
    1827      891388 :     _sc->set_current_elem(*elem);
    1828             : 
    1829   439679886 :   setVolumeQRule(elem);
    1830   439679886 :   reinitFE(elem);
    1831             : 
    1832   439679858 :   computeCurrentElemVolume();
    1833   439679858 : }
    1834             : 
    1835             : void
    1836      395420 : Assembly::reinit(const Elem * elem, const std::vector<Point> & reference_points)
    1837             : {
    1838      395420 :   _current_elem = elem;
    1839      395420 :   _current_neighbor_elem = nullptr;
    1840             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1841             :               "current subdomain has been set incorrectly");
    1842      395420 :   _current_elem_volume_computed = false;
    1843             : 
    1844      395420 :   unsigned int elem_dimension = _current_elem->dim();
    1845             : 
    1846      395420 :   _current_qrule_arbitrary = qrules(elem_dimension).arbitrary_vol.get();
    1847             : 
    1848             :   // Make sure the qrule is the right one
    1849      395420 :   if (_current_qrule != _current_qrule_arbitrary)
    1850       33800 :     setVolumeQRule(_current_qrule_arbitrary, elem_dimension);
    1851             : 
    1852      395420 :   _current_qrule_arbitrary->setPoints(reference_points);
    1853             : 
    1854      395420 :   reinitFE(elem);
    1855             : 
    1856      395420 :   computeCurrentElemVolume();
    1857      395420 : }
    1858             : 
    1859             : void
    1860    26519827 : Assembly::reinitFVFace(const FaceInfo & fi)
    1861             : {
    1862    26519827 :   _current_elem = &fi.elem();
    1863    26519827 :   _current_neighbor_elem = fi.neighborPtr();
    1864    26519827 :   _current_side = fi.elemSideID();
    1865    26519827 :   _current_neighbor_side = fi.neighborSideID();
    1866             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1867             :               "current subdomain has been set incorrectly");
    1868             : 
    1869    26519827 :   _current_elem_volume_computed = false;
    1870    26519827 :   _current_side_volume_computed = false;
    1871             : 
    1872    26519827 :   prepareResidual();
    1873    26519827 :   prepareNeighbor();
    1874    26519827 :   prepareJacobianBlock();
    1875             : 
    1876    26519827 :   unsigned int dim = _current_elem->dim();
    1877    26519827 :   if (_current_qrule_face != qrules(dim).fv_face.get())
    1878             :   {
    1879        5380 :     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        5380 :     if (dim == 3)
    1883          13 :       _current_qrule_face->init(QUAD4, /* p_level = */ 0, /* simple_type_only = */ true);
    1884             :     else
    1885        5367 :       _current_qrule_face->init(EDGE2, /* p_level = */ 0, /* simple_type_only = */ true);
    1886             :   }
    1887             : 
    1888    26519827 :   _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    26519827 :   _current_q_points_face.resize(1);
    1898    26519827 :   const auto & ref_points = _current_qrule_face->get_points();
    1899    26519827 :   const auto & ref_point = ref_points[0];
    1900    26519827 :   auto physical_point = FEMap::map(_current_side_elem->dim(), _current_side_elem, ref_point);
    1901    26519827 :   _current_q_points_face[0] = physical_point;
    1902             : 
    1903    26519827 :   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    24492212 :         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    24492212 :     neighbor_rule->setPoints(ref_points);
    1913    24492212 :     setNeighborQRule(neighbor_rule, _current_neighbor_elem->dim());
    1914    24492212 :     _current_q_points_face_neighbor.resize(1);
    1915    24492212 :     _current_q_points_face_neighbor[0] = std::move(physical_point);
    1916             :   }
    1917    26519827 : }
    1918             : 
    1919             : QBase *
    1920    12729629 : Assembly::qruleFace(const Elem * elem, unsigned int side)
    1921             : {
    1922    25680829 :   return qruleFaceHelper<QBase>(elem, side, [](QRules & q) { return q.face.get(); });
    1923             : }
    1924             : 
    1925             : ArbitraryQuadrature *
    1926      306709 : Assembly::qruleArbitraryFace(const Elem * elem, unsigned int side)
    1927             : {
    1928      613418 :   return qruleFaceHelper<ArbitraryQuadrature>(
    1929      920127 :       elem, side, [](QRules & q) { return q.arbitrary_face.get(); });
    1930             : }
    1931             : 
    1932             : void
    1933    12729629 : Assembly::setFaceQRule(const Elem * const elem, const unsigned int side)
    1934             : {
    1935    12729629 :   const auto elem_dimension = elem->dim();
    1936             :   //// Make sure the qrule is the right one
    1937    12729629 :   auto rule = qruleFace(elem, side);
    1938    12729629 :   if (_current_qrule_face != rule)
    1939       12681 :     setFaceQRule(rule, elem_dimension);
    1940    12729629 : }
    1941             : 
    1942             : void
    1943    12729629 : Assembly::reinit(const Elem * const elem, const unsigned int side)
    1944             : {
    1945    12729629 :   _current_elem = elem;
    1946    12729629 :   _current_neighbor_elem = nullptr;
    1947             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1948             :               "current subdomain has been set incorrectly");
    1949    12729629 :   _current_side = side;
    1950    12729629 :   _current_elem_volume_computed = false;
    1951    12729629 :   _current_side_volume_computed = false;
    1952             : 
    1953    12729629 :   _current_side_elem = &_current_side_elem_builder(*elem, side);
    1954             : 
    1955    12729629 :   setFaceQRule(elem, side);
    1956    12729629 :   reinitFEFace(elem, side);
    1957             : 
    1958    12729629 :   computeCurrentFaceVolume();
    1959    12729629 : }
    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   119348488 : Assembly::reinit(const Node * node)
    1991             : {
    1992   119348488 :   _current_node = node;
    1993   119348488 :   _current_neighbor_node = NULL;
    1994   119348488 : }
    1995             : 
    1996             : void
    1997     4128321 : 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     4128321 :   _current_neighbor_side = neighbor_side;
    2004             : 
    2005     4128321 :   reinit(elem, side);
    2006             : 
    2007     4128321 :   unsigned int neighbor_dim = neighbor->dim();
    2008             : 
    2009     4128321 :   if (neighbor_reference_points)
    2010       72006 :     _current_neighbor_ref_points = *neighbor_reference_points;
    2011             :   else
    2012     4056315 :     FEMap::inverse_map(
    2013     8112630 :         neighbor_dim, neighbor, _current_q_points_face.stdVector(), _current_neighbor_ref_points);
    2014             : 
    2015     4128321 :   _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
    2016             : 
    2017     4128321 :   reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
    2018     4128321 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2019     4128321 : }
    2020             : 
    2021             : void
    2022      306709 : 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      306709 :   _current_elem = elem;
    2029             : 
    2030      306709 :   unsigned int elem_dim = elem->dim();
    2031             : 
    2032             :   // Attach the quadrature rules
    2033      306709 :   if (pts)
    2034             :   {
    2035      306709 :     auto face_rule = qruleArbitraryFace(elem, elem_side);
    2036      306709 :     face_rule->setPoints(*pts);
    2037      306709 :     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      721868 :   for (const auto & it : _fe_face[elem_dim])
    2048             :   {
    2049      415159 :     FEBase & fe_face = *it.second;
    2050      415159 :     FEType fe_type = it.first;
    2051      415159 :     FEShapeData & fesd = *_fe_shape_data_face[fe_type];
    2052             : 
    2053      415159 :     fe_face.reinit(elem, elem_side, tolerance, pts, weights);
    2054             : 
    2055      415159 :     _current_fe_face[fe_type] = &fe_face;
    2056             : 
    2057      415159 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
    2058      415159 :     fesd._grad_phi.shallowCopy(
    2059      415159 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face.get_dphi()));
    2060      415159 :     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      306709 :   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      306709 :   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      306709 :   _current_q_points_face.shallowCopy(
    2097      306709 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_xyz()));
    2098      306709 :   _current_normals.shallowCopy(
    2099      306709 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_normals()));
    2100      306709 :   _current_tangents.shallowCopy(const_cast<std::vector<std::vector<Point>> &>(
    2101      306709 :       _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      306709 :   _current_JxW_face.shallowCopy(
    2105      306709 :       const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_JxW()));
    2106      306709 :   if (_calculate_curvatures)
    2107           0 :     _curvatures.shallowCopy(
    2108           0 :         const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_curvatures()));
    2109             : 
    2110      306709 :   computeADFace(*elem, elem_side);
    2111      306709 : }
    2112             : 
    2113             : void
    2114    13036338 : Assembly::computeADFace(const Elem & elem, const unsigned int side)
    2115             : {
    2116    13036338 :   const auto dim = elem.dim();
    2117             : 
    2118    13036338 :   if (_subproblem.haveADObjects())
    2119             :   {
    2120     4172784 :     auto n_qp = _current_qrule_face->n_points();
    2121     4172784 :     resizeADMappingObjects(n_qp, dim);
    2122     4172784 :     _ad_normals.resize(n_qp);
    2123     4172784 :     _ad_JxW_face.resize(n_qp);
    2124     4172784 :     if (_calculate_face_xyz)
    2125     3702459 :       _ad_q_points_face.resize(n_qp);
    2126     4172784 :     if (_calculate_curvatures)
    2127         468 :       _ad_curvatures.resize(n_qp);
    2128             : 
    2129     4172784 :     if (_displaced)
    2130             :     {
    2131       60088 :       const auto & qw = _current_qrule_face->get_weights();
    2132       60088 :       computeFaceMap(elem, side, qw);
    2133       60088 :       const std::vector<Real> dummy_qw(n_qp, 1.);
    2134             : 
    2135      179954 :       for (unsigned int qp = 0; qp != n_qp; qp++)
    2136      119866 :         computeSinglePointMapAD(&elem, dummy_qw, qp, _holder_fe_face_helper[dim]);
    2137       60088 :     }
    2138             :     else
    2139             :     {
    2140    13092517 :       for (unsigned qp = 0; qp < n_qp; ++qp)
    2141             :       {
    2142     8979821 :         _ad_JxW_face[qp] = _current_JxW_face[qp];
    2143     8979821 :         _ad_normals[qp] = _current_normals[qp];
    2144             :       }
    2145     4112696 :       if (_calculate_face_xyz)
    2146    11285847 :         for (unsigned qp = 0; qp < n_qp; ++qp)
    2147     7620956 :           _ad_q_points_face[qp] = _current_q_points_face[qp];
    2148     4112696 :       if (_calculate_curvatures)
    2149         936 :         for (unsigned qp = 0; qp < n_qp; ++qp)
    2150         468 :           _ad_curvatures[qp] = _curvatures[qp];
    2151             :     }
    2152             : 
    2153    13258393 :     for (const auto & it : _fe_face[dim])
    2154             :     {
    2155     9085609 :       FEBase & fe = *it.second;
    2156     9085609 :       auto fe_type = it.first;
    2157     9085609 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
    2158     9085609 :       auto & grad_phi = _ad_grad_phi_data_face[fe_type];
    2159             : 
    2160     9085609 :       grad_phi.resize(num_shapes);
    2161    67345251 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2162    58259642 :         grad_phi[i].resize(n_qp);
    2163             : 
    2164     9085609 :       const auto & regular_grad_phi = _fe_shape_data_face[fe_type]->_grad_phi;
    2165             : 
    2166     9085609 :       if (_displaced)
    2167      146898 :         computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
    2168             :       else
    2169    66428423 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2170   190882589 :           for (unsigned qp = 0; qp < n_qp; ++qp)
    2171   133392877 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
    2172             :     }
    2173     4672310 :     for (const auto & it : _vector_fe_face[dim])
    2174             :     {
    2175      499526 :       FEVectorBase & fe = *it.second;
    2176      499526 :       auto fe_type = it.first;
    2177      499526 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
    2178      499526 :       auto & grad_phi = _ad_vector_grad_phi_data_face[fe_type];
    2179             : 
    2180      499526 :       grad_phi.resize(num_shapes);
    2181     2628696 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2182     2129170 :         grad_phi[i].resize(n_qp);
    2183             : 
    2184      499526 :       const auto & regular_grad_phi = _vector_fe_shape_data_face[fe_type]->_grad_phi;
    2185             : 
    2186      499526 :       if (_displaced)
    2187           0 :         computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
    2188             :       else
    2189     2628696 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2190     6511452 :           for (unsigned qp = 0; qp < n_qp; ++qp)
    2191     4382282 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
    2192             :     }
    2193             :   }
    2194    13036338 : }
    2195             : 
    2196             : void
    2197      306709 : 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      306709 :   _current_neighbor_elem = neighbor;
    2204             : 
    2205      306709 :   unsigned int neighbor_dim = neighbor->dim();
    2206             : 
    2207             :   ArbitraryQuadrature * neighbor_rule =
    2208      306709 :       qrules(neighbor_dim, neighbor->subdomain_id()).neighbor.get();
    2209      306709 :   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      306709 :   setNeighborQRule(neighbor_rule, neighbor_dim);
    2217             : 
    2218             :   // reinit neighbor face
    2219      721868 :   for (const auto & it : _fe_face_neighbor[neighbor_dim])
    2220             :   {
    2221      415159 :     FEBase & fe_face_neighbor = *it.second;
    2222      415159 :     FEType fe_type = it.first;
    2223      415159 :     FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
    2224             : 
    2225      415159 :     fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
    2226             : 
    2227      415159 :     _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    2228             : 
    2229      415159 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
    2230      415159 :     fesd._grad_phi.shallowCopy(
    2231      415159 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
    2232      415159 :     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      306709 :   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      306709 :   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      306709 :   _current_q_points_face_neighbor.shallowCopy(
    2271      306709 :       const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
    2272      306709 : }
    2273             : 
    2274             : void
    2275        4587 : Assembly::reinitDual(const Elem * elem,
    2276             :                      const std::vector<Point> & pts,
    2277             :                      const std::vector<Real> & JxW)
    2278             : {
    2279        4587 :   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        9489 :   for (const auto & it : _fe_lower[elem_dim])
    2284             :   {
    2285        4902 :     FEBase & fe_lower = *it.second;
    2286             :     // We use customized quadrature rule for integration along the mortar segment elements
    2287        4902 :     fe_lower.set_calculate_default_dual_coeff(false);
    2288        4902 :     fe_lower.reinit_dual_shape_coeffs(elem, pts, JxW);
    2289             :   }
    2290        4587 : }
    2291             : 
    2292             : void
    2293      325712 : Assembly::reinitLowerDElem(const Elem * elem,
    2294             :                            const std::vector<Point> * const pts,
    2295             :                            const std::vector<Real> * const weights)
    2296             : {
    2297      325712 :   _current_lower_d_elem = elem;
    2298             : 
    2299      325712 :   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      325712 :   if (pts)
    2304             :   {
    2305             :     // Lower rule matches the face rule for the higher dimensional element
    2306      284081 :     ArbitraryQuadrature * lower_rule = qrules(elem_dim + 1).arbitrary_face.get();
    2307             : 
    2308             :     // This also sets the quadrature weights to unity
    2309      284081 :     lower_rule->setPoints(*pts);
    2310             : 
    2311      284081 :     if (weights)
    2312           0 :       lower_rule->setWeights(*weights);
    2313             : 
    2314      284081 :     setLowerQRule(lower_rule, elem_dim);
    2315             :   }
    2316       41631 :   else if (_current_qrule_lower != qrules(elem_dim + 1).face.get())
    2317         468 :     setLowerQRule(qrules(elem_dim + 1).face.get(), elem_dim);
    2318             : 
    2319      801188 :   for (const auto & it : _fe_lower[elem_dim])
    2320             :   {
    2321      475476 :     FEBase & fe_lower = *it.second;
    2322      475476 :     FEType fe_type = it.first;
    2323             : 
    2324      475476 :     fe_lower.reinit(elem);
    2325             : 
    2326      475476 :     if (FEShapeData * fesd = _fe_shape_data_lower[fe_type].get())
    2327             :     {
    2328      475476 :       fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_phi()));
    2329      475476 :       fesd->_grad_phi.shallowCopy(
    2330      475476 :           const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dphi()));
    2331      475476 :       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      475476 :     if (FEShapeData * fesd = _fe_shape_data_dual_lower[fe_type].get())
    2338             :     {
    2339       13688 :       fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_dual_phi()));
    2340       13688 :       fesd->_grad_phi.shallowCopy(
    2341       13688 :           const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dual_dphi()));
    2342       13688 :       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      325712 :   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      325712 :   if (!_need_lower_d_elem_volume)
    2354      219481 :     return;
    2355             : 
    2356      106231 :   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      102667 :     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      102667 :       _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        3564 :     FEBase & helper_fe = *_holder_fe_lower_helper[elem_dim];
    2374        3564 :     const auto & physical_q_points = helper_fe.get_xyz();
    2375        3564 :     const auto & JxW = helper_fe.get_JxW();
    2376        3564 :     MooseArray<Real> coord;
    2377        3564 :     setCoordinateTransformation(
    2378        3564 :         _current_qrule_lower, physical_q_points, coord, elem->subdomain_id());
    2379        3564 :     _current_lower_d_elem_volume = 0;
    2380       52812 :     for (const auto qp : make_range(_current_qrule_lower->n_points()))
    2381       49248 :       _current_lower_d_elem_volume += JxW[qp] * coord[qp];
    2382        3564 :   }
    2383             : }
    2384             : 
    2385             : void
    2386      284081 : 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      284081 :   _current_neighbor_lower_d_elem = elem;
    2392             : 
    2393      284081 :   if (!_need_neighbor_lower_d_elem_volume)
    2394      181414 :     return;
    2395             : 
    2396      102667 :   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      102667 :     _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      568162 : 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      568162 :   _fe_msm->reinit(elem);
    2413      568162 :   _msm_elem = elem;
    2414             : 
    2415      568162 :   MooseArray<Point> array_q_points;
    2416      568162 :   array_q_points.shallowCopy(const_cast<std::vector<Point> &>(_fe_msm->get_xyz()));
    2417      568162 :   setCoordinateTransformation(_qrule_msm, array_q_points, _coord_msm, elem->subdomain_id());
    2418      568162 : }
    2419             : 
    2420             : void
    2421      165882 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
    2422             :                                    unsigned int neighbor_side,
    2423             :                                    const std::vector<Point> & physical_points)
    2424             : {
    2425      165882 :   unsigned int neighbor_dim = neighbor->dim();
    2426      165882 :   FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
    2427             : 
    2428      165882 :   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      108178 :     _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      108178 :     _current_JxW_neighbor.resize(1);
    2446      108178 :     _current_JxW_neighbor[0] = _current_neighbor_side_elem->volume();
    2447             :   }
    2448             : 
    2449      165882 :   reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
    2450      165882 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2451             : 
    2452             :   // Save off the physical points
    2453      165882 :   _current_physical_points = physical_points;
    2454      165882 : }
    2455             : 
    2456             : void
    2457       22720 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
    2458             :                                    const std::vector<Point> & physical_points)
    2459             : {
    2460       22720 :   unsigned int neighbor_dim = neighbor->dim();
    2461       22720 :   FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
    2462             : 
    2463       22720 :   reinitFENeighbor(neighbor, _current_neighbor_ref_points);
    2464       22720 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2465             :   // Save off the physical points
    2466       22720 :   _current_physical_points = physical_points;
    2467       22720 : }
    2468             : 
    2469             : void
    2470       67702 : Assembly::init(const CouplingMatrix * cm)
    2471             : {
    2472       67702 :   _cm = cm;
    2473             : 
    2474       67702 :   unsigned int n_vars = _sys.nVariables();
    2475             : 
    2476       67702 :   _cm_ss_entry.clear();
    2477       67702 :   _cm_sf_entry.clear();
    2478       67702 :   _cm_fs_entry.clear();
    2479       67702 :   _cm_ff_entry.clear();
    2480             : 
    2481       67702 :   auto & vars = _sys.getVariables(_tid);
    2482             : 
    2483       67702 :   _block_diagonal_matrix = true;
    2484      136152 :   for (auto & ivar : vars)
    2485             :   {
    2486       68450 :     auto i = ivar->number();
    2487       68450 :     if (i >= _component_block_diagonal.size())
    2488       68450 :       _component_block_diagonal.resize(i + 1, true);
    2489             : 
    2490       68450 :     auto ivar_start = _cm_ff_entry.size();
    2491      138626 :     for (unsigned int k = 0; k < ivar->count(); ++k)
    2492             :     {
    2493       70176 :       unsigned int iv = i + k;
    2494      164233 :       for (const auto & j : ConstCouplingRow(iv, *_cm))
    2495             :       {
    2496       94057 :         if (_sys.isScalarVariable(j))
    2497             :         {
    2498        1156 :           auto & jvar = _sys.getScalarVariable(_tid, j);
    2499        1156 :           _cm_fs_entry.push_back(std::make_pair(ivar, &jvar));
    2500        1156 :           _block_diagonal_matrix = false;
    2501             :         }
    2502             :         else
    2503             :         {
    2504       92901 :           auto & jvar = _sys.getVariable(_tid, j);
    2505       92901 :           auto pair = std::make_pair(ivar, &jvar);
    2506       92901 :           auto c = ivar_start;
    2507             :           // check if the pair has been pushed or not
    2508       92901 :           bool has_pair = false;
    2509      121285 :           for (; c < _cm_ff_entry.size(); ++c)
    2510       34456 :             if (_cm_ff_entry[c] == pair)
    2511             :             {
    2512        6072 :               has_pair = true;
    2513        6072 :               break;
    2514             :             }
    2515       92901 :           if (!has_pair)
    2516       86829 :             _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       92901 :           if (i != jvar.number())
    2522       21007 :             _block_diagonal_matrix = false;
    2523       71894 :           else if (iv != j)
    2524        1718 :             _component_block_diagonal[i] = false;
    2525             :         }
    2526             :       }
    2527             :     }
    2528             :   }
    2529             : 
    2530       67702 :   auto & scalar_vars = _sys.getScalarVariables(_tid);
    2531             : 
    2532       69222 :   for (auto & ivar : scalar_vars)
    2533             :   {
    2534        1520 :     auto i = ivar->number();
    2535        1520 :     if (i >= _component_block_diagonal.size())
    2536        1442 :       _component_block_diagonal.resize(i + 1, true);
    2537             : 
    2538        4340 :     for (const auto & j : ConstCouplingRow(i, *_cm))
    2539        2820 :       if (_sys.isScalarVariable(j))
    2540             :       {
    2541        1664 :         auto & jvar = _sys.getScalarVariable(_tid, j);
    2542        1664 :         _cm_ss_entry.push_back(std::make_pair(ivar, &jvar));
    2543             :       }
    2544             :       else
    2545             :       {
    2546        1156 :         auto & jvar = _sys.getVariable(_tid, j);
    2547        1156 :         _cm_sf_entry.push_back(std::make_pair(ivar, &jvar));
    2548             :       }
    2549             :   }
    2550             : 
    2551       67702 :   if (_block_diagonal_matrix && scalar_vars.size() != 0)
    2552         476 :     _block_diagonal_matrix = false;
    2553             : 
    2554       67702 :   auto num_vector_tags = _residual_vector_tags.size();
    2555             : 
    2556       67702 :   _sub_Re.resize(num_vector_tags);
    2557       67702 :   _sub_Rn.resize(num_vector_tags);
    2558       67702 :   _sub_Rl.resize(num_vector_tags);
    2559      240578 :   for (MooseIndex(_sub_Re) i = 0; i < _sub_Re.size(); i++)
    2560             :   {
    2561      172876 :     _sub_Re[i].resize(n_vars);
    2562      172876 :     _sub_Rn[i].resize(n_vars);
    2563      172876 :     _sub_Rl[i].resize(n_vars);
    2564             :   }
    2565             : 
    2566       67702 :   _cached_residual_values.resize(num_vector_tags);
    2567       67702 :   _cached_residual_rows.resize(num_vector_tags);
    2568             : 
    2569       67702 :   auto num_matrix_tags = _subproblem.numMatrixTags();
    2570             : 
    2571       67702 :   _cached_jacobian_values.resize(num_matrix_tags);
    2572       67702 :   _cached_jacobian_rows.resize(num_matrix_tags);
    2573       67702 :   _cached_jacobian_cols.resize(num_matrix_tags);
    2574             : 
    2575             :   // Element matrices
    2576       67702 :   _sub_Kee.resize(num_matrix_tags);
    2577       67702 :   _sub_Keg.resize(num_matrix_tags);
    2578       67702 :   _sub_Ken.resize(num_matrix_tags);
    2579       67702 :   _sub_Kne.resize(num_matrix_tags);
    2580       67702 :   _sub_Knn.resize(num_matrix_tags);
    2581       67702 :   _sub_Kll.resize(num_matrix_tags);
    2582       67702 :   _sub_Kle.resize(num_matrix_tags);
    2583       67702 :   _sub_Kln.resize(num_matrix_tags);
    2584       67702 :   _sub_Kel.resize(num_matrix_tags);
    2585       67702 :   _sub_Knl.resize(num_matrix_tags);
    2586             : 
    2587       67702 :   _jacobian_block_used.resize(num_matrix_tags);
    2588       67702 :   _jacobian_block_neighbor_used.resize(num_matrix_tags);
    2589       67702 :   _jacobian_block_lower_used.resize(num_matrix_tags);
    2590       67702 :   _jacobian_block_nonlocal_used.resize(num_matrix_tags);
    2591             : 
    2592      205506 :   for (MooseIndex(num_matrix_tags) tag = 0; tag < num_matrix_tags; tag++)
    2593             :   {
    2594      137804 :     _sub_Keg[tag].resize(n_vars);
    2595      137804 :     _sub_Ken[tag].resize(n_vars);
    2596      137804 :     _sub_Kne[tag].resize(n_vars);
    2597      137804 :     _sub_Knn[tag].resize(n_vars);
    2598      137804 :     _sub_Kee[tag].resize(n_vars);
    2599      137804 :     _sub_Kll[tag].resize(n_vars);
    2600      137804 :     _sub_Kle[tag].resize(n_vars);
    2601      137804 :     _sub_Kln[tag].resize(n_vars);
    2602      137804 :     _sub_Kel[tag].resize(n_vars);
    2603      137804 :     _sub_Knl[tag].resize(n_vars);
    2604             : 
    2605      137804 :     _jacobian_block_used[tag].resize(n_vars);
    2606      137804 :     _jacobian_block_neighbor_used[tag].resize(n_vars);
    2607      137804 :     _jacobian_block_lower_used[tag].resize(n_vars);
    2608      137804 :     _jacobian_block_nonlocal_used[tag].resize(n_vars);
    2609      284932 :     for (MooseIndex(n_vars) i = 0; i < n_vars; ++i)
    2610             :     {
    2611      147128 :       if (!_block_diagonal_matrix)
    2612             :       {
    2613       33956 :         _sub_Kee[tag][i].resize(n_vars);
    2614       33956 :         _sub_Keg[tag][i].resize(n_vars);
    2615       33956 :         _sub_Ken[tag][i].resize(n_vars);
    2616       33956 :         _sub_Kne[tag][i].resize(n_vars);
    2617       33956 :         _sub_Knn[tag][i].resize(n_vars);
    2618       33956 :         _sub_Kll[tag][i].resize(n_vars);
    2619       33956 :         _sub_Kle[tag][i].resize(n_vars);
    2620       33956 :         _sub_Kln[tag][i].resize(n_vars);
    2621       33956 :         _sub_Kel[tag][i].resize(n_vars);
    2622       33956 :         _sub_Knl[tag][i].resize(n_vars);
    2623             : 
    2624       33956 :         _jacobian_block_used[tag][i].resize(n_vars);
    2625       33956 :         _jacobian_block_neighbor_used[tag][i].resize(n_vars);
    2626       33956 :         _jacobian_block_lower_used[tag][i].resize(n_vars);
    2627       33956 :         _jacobian_block_nonlocal_used[tag][i].resize(n_vars);
    2628             :       }
    2629             :       else
    2630             :       {
    2631      113172 :         _sub_Kee[tag][i].resize(1);
    2632      113172 :         _sub_Keg[tag][i].resize(1);
    2633      113172 :         _sub_Ken[tag][i].resize(1);
    2634      113172 :         _sub_Kne[tag][i].resize(1);
    2635      113172 :         _sub_Knn[tag][i].resize(1);
    2636      113172 :         _sub_Kll[tag][i].resize(1);
    2637      113172 :         _sub_Kle[tag][i].resize(1);
    2638      113172 :         _sub_Kln[tag][i].resize(1);
    2639      113172 :         _sub_Kel[tag][i].resize(1);
    2640      113172 :         _sub_Knl[tag][i].resize(1);
    2641             : 
    2642      113172 :         _jacobian_block_used[tag][i].resize(1);
    2643      113172 :         _jacobian_block_neighbor_used[tag][i].resize(1);
    2644      113172 :         _jacobian_block_lower_used[tag][i].resize(1);
    2645      113172 :         _jacobian_block_nonlocal_used[tag][i].resize(1);
    2646             :       }
    2647             :     }
    2648             :   }
    2649       67702 : }
    2650             : 
    2651             : void
    2652          81 : Assembly::initNonlocalCoupling()
    2653             : {
    2654          81 :   _cm_nonlocal_entry.clear();
    2655             : 
    2656          81 :   auto & vars = _sys.getVariables(_tid);
    2657             : 
    2658         243 :   for (auto & ivar : vars)
    2659             :   {
    2660         162 :     auto i = ivar->number();
    2661         162 :     auto ivar_start = _cm_nonlocal_entry.size();
    2662         324 :     for (unsigned int k = 0; k < ivar->count(); ++k)
    2663             :     {
    2664         162 :       unsigned int iv = i + k;
    2665         278 :       for (const auto & j : ConstCouplingRow(iv, _nonlocal_cm))
    2666         116 :         if (!_sys.isScalarVariable(j))
    2667             :         {
    2668         116 :           auto & jvar = _sys.getVariable(_tid, j);
    2669         116 :           auto pair = std::make_pair(ivar, &jvar);
    2670         116 :           auto c = ivar_start;
    2671             :           // check if the pair has been pushed or not
    2672         116 :           bool has_pair = false;
    2673         151 :           for (; c < _cm_nonlocal_entry.size(); ++c)
    2674          35 :             if (_cm_nonlocal_entry[c] == pair)
    2675             :             {
    2676           0 :               has_pair = true;
    2677           0 :               break;
    2678             :             }
    2679         116 :           if (!has_pair)
    2680         116 :             _cm_nonlocal_entry.push_back(pair);
    2681             :         }
    2682             :     }
    2683             :   }
    2684          81 : }
    2685             : 
    2686             : void
    2687    91545900 : Assembly::prepareJacobianBlock()
    2688             : {
    2689   238770871 :   for (const auto & it : _cm_ff_entry)
    2690             :   {
    2691   147224971 :     MooseVariableFEBase & ivar = *(it.first);
    2692   147224971 :     MooseVariableFEBase & jvar = *(it.second);
    2693             : 
    2694   147224971 :     unsigned int vi = ivar.number();
    2695   147224971 :     unsigned int vj = jvar.number();
    2696             : 
    2697   147224971 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2698             : 
    2699   444638938 :     for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2700             :     {
    2701   297413967 :       jacobianBlock(vi, vj, LocalDataKey{}, tag)
    2702   297413967 :           .resize(ivar.dofIndices().size() * ivar.count(), jvar.dofIndices().size() * jcount);
    2703   297413967 :       jacobianBlockUsed(tag, vi, vj, false);
    2704             :     }
    2705             :   }
    2706    91545900 : }
    2707             : 
    2708             : void
    2709   466342720 : Assembly::prepareResidual()
    2710             : {
    2711   466342720 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2712   984353520 :   for (const auto & var : vars)
    2713  1941090599 :     for (auto & tag_Re : _sub_Re)
    2714  1423079799 :       tag_Re[var->number()].resize(var->dofIndices().size() * var->count());
    2715   466342720 : }
    2716             : 
    2717             : void
    2718      611878 : Assembly::prepare()
    2719             : {
    2720      611878 :   prepareJacobianBlock();
    2721      611878 :   prepareResidual();
    2722      611878 : }
    2723             : 
    2724             : void
    2725       11792 : Assembly::prepareNonlocal()
    2726             : {
    2727       23876 :   for (const auto & it : _cm_nonlocal_entry)
    2728             :   {
    2729       12084 :     MooseVariableFEBase & ivar = *(it.first);
    2730       12084 :     MooseVariableFEBase & jvar = *(it.second);
    2731             : 
    2732       12084 :     unsigned int vi = ivar.number();
    2733       12084 :     unsigned int vj = jvar.number();
    2734             : 
    2735       12084 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2736             : 
    2737       36252 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2738       36252 :          tag < _jacobian_block_nonlocal_used.size();
    2739             :          tag++)
    2740             :     {
    2741       24168 :       jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
    2742       24168 :           .resize(ivar.dofIndices().size() * ivar.count(), jvar.allDofIndices().size() * jcount);
    2743       24168 :       jacobianBlockNonlocalUsed(tag, vi, vj, false);
    2744             :     }
    2745             :   }
    2746       11792 : }
    2747             : 
    2748             : void
    2749        1625 : Assembly::prepareVariable(MooseVariableFEBase * var)
    2750             : {
    2751        6222 :   for (const auto & it : _cm_ff_entry)
    2752             :   {
    2753        4597 :     MooseVariableFEBase & ivar = *(it.first);
    2754        4597 :     MooseVariableFEBase & jvar = *(it.second);
    2755             : 
    2756        4597 :     unsigned int vi = ivar.number();
    2757        4597 :     unsigned int vj = jvar.number();
    2758             : 
    2759        4597 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2760             : 
    2761        4597 :     if (vi == var->number() || vj == var->number())
    2762             :     {
    2763        9699 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2764             :       {
    2765        6466 :         jacobianBlock(vi, vj, LocalDataKey{}, tag)
    2766        6466 :             .resize(ivar.dofIndices().size() * ivar.count(), jvar.dofIndices().size() * jcount);
    2767        6466 :         jacobianBlockUsed(tag, vi, vj, false);
    2768             :       }
    2769             :     }
    2770             :   }
    2771             : 
    2772        5679 :   for (auto & tag_Re : _sub_Re)
    2773        4054 :     tag_Re[var->number()].resize(var->dofIndices().size() * var->count());
    2774        1625 : }
    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    31143459 : Assembly::prepareNeighbor()
    2805             : {
    2806    93587004 :   for (const auto & it : _cm_ff_entry)
    2807             :   {
    2808    62443545 :     MooseVariableFEBase & ivar = *(it.first);
    2809    62443545 :     MooseVariableFEBase & jvar = *(it.second);
    2810             : 
    2811    62443545 :     unsigned int vi = ivar.number();
    2812    62443545 :     unsigned int vj = jvar.number();
    2813             : 
    2814    62443545 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2815             : 
    2816   187339059 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    2817   187339059 :          tag < _jacobian_block_neighbor_used.size();
    2818             :          tag++)
    2819             :     {
    2820   124895514 :       jacobianBlockNeighbor(Moose::ElementNeighbor, vi, vj, LocalDataKey{}, tag)
    2821   124895514 :           .resize(ivar.dofIndices().size() * ivar.count(),
    2822   124895514 :                   jvar.dofIndicesNeighbor().size() * jcount);
    2823             : 
    2824   124895514 :       jacobianBlockNeighbor(Moose::NeighborElement, vi, vj, LocalDataKey{}, tag)
    2825   124895514 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2826   124895514 :                   jvar.dofIndices().size() * jcount);
    2827             : 
    2828   124895514 :       jacobianBlockNeighbor(Moose::NeighborNeighbor, vi, vj, LocalDataKey{}, tag)
    2829   124895514 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2830   124895514 :                   jvar.dofIndicesNeighbor().size() * jcount);
    2831             : 
    2832   124895514 :       jacobianBlockNeighborUsed(tag, vi, vj, false);
    2833             :     }
    2834             :   }
    2835             : 
    2836    31143459 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2837    72012198 :   for (const auto & var : vars)
    2838   145691696 :     for (auto & tag_Rn : _sub_Rn)
    2839   104822957 :       tag_Rn[var->number()].resize(var->dofIndicesNeighbor().size() * var->count());
    2840    31143459 : }
    2841             : 
    2842             : void
    2843      325712 : Assembly::prepareLowerD()
    2844             : {
    2845     1386404 :   for (const auto & it : _cm_ff_entry)
    2846             :   {
    2847     1060692 :     MooseVariableFEBase & ivar = *(it.first);
    2848     1060692 :     MooseVariableFEBase & jvar = *(it.second);
    2849             : 
    2850     1060692 :     unsigned int vi = ivar.number();
    2851     1060692 :     unsigned int vj = jvar.number();
    2852             : 
    2853     1060692 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2854             : 
    2855     3182076 :     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     2121384 :       jacobianBlockMortar(Moose::LowerLower, vi, vj, LocalDataKey{}, tag)
    2867     2121384 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2868     2121384 :                   jvar.dofIndicesLower().size() * jcount);
    2869             : 
    2870     2121384 :       jacobianBlockMortar(Moose::LowerSecondary, vi, vj, LocalDataKey{}, tag)
    2871     2121384 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2872     2121384 :                   jvar.dofIndices().size() * jvar.count());
    2873             : 
    2874     2121384 :       jacobianBlockMortar(Moose::LowerPrimary, vi, vj, LocalDataKey{}, tag)
    2875     2121384 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2876     2121384 :                   jvar.dofIndicesNeighbor().size() * jvar.count());
    2877             : 
    2878             :       // derivatives w.r.t. interior secondary residuals
    2879     2121384 :       jacobianBlockMortar(Moose::SecondaryLower, vi, vj, LocalDataKey{}, tag)
    2880     2121384 :           .resize(ivar.dofIndices().size() * ivar.count(),
    2881     2121384 :                   jvar.dofIndicesLower().size() * jvar.count());
    2882             : 
    2883             :       // derivatives w.r.t. interior primary residuals
    2884     2121384 :       jacobianBlockMortar(Moose::PrimaryLower, vi, vj, LocalDataKey{}, tag)
    2885     2121384 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2886     2121384 :                   jvar.dofIndicesLower().size() * jvar.count());
    2887             : 
    2888     2121384 :       jacobianBlockLowerUsed(tag, vi, vj, false);
    2889             :     }
    2890             :   }
    2891             : 
    2892      325712 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2893      872914 :   for (const auto & var : vars)
    2894     1724314 :     for (auto & tag_Rl : _sub_Rl)
    2895     1177112 :       tag_Rl[var->number()].resize(var->dofIndicesLower().size() * var->count());
    2896      325712 : }
    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     9223623 : Assembly::prepareScalar()
    2951             : {
    2952     9223623 :   const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
    2953     9541448 :   for (const auto & ivar : vars)
    2954             :   {
    2955      317825 :     auto idofs = ivar->dofIndices().size();
    2956             : 
    2957     1260665 :     for (auto & tag_Re : _sub_Re)
    2958      942840 :       tag_Re[ivar->number()].resize(idofs);
    2959             : 
    2960      796650 :     for (const auto & jvar : vars)
    2961             :     {
    2962      478825 :       auto jdofs = jvar->dofIndices().size();
    2963             : 
    2964     1440845 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2965             :       {
    2966      962020 :         jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
    2967      962020 :         jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
    2968             :       }
    2969             :     }
    2970             :   }
    2971     9223623 : }
    2972             : 
    2973             : void
    2974      210656 : Assembly::prepareOffDiagScalar()
    2975             : {
    2976      210656 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2977      210656 :   const std::vector<MooseVariableScalar *> & scalar_vars = _sys.getScalarVariables(_tid);
    2978             : 
    2979      427196 :   for (const auto & ivar : scalar_vars)
    2980             :   {
    2981      216540 :     auto idofs = ivar->dofIndices().size();
    2982             : 
    2983      533411 :     for (const auto & jvar : vars)
    2984             :     {
    2985      316871 :       auto jdofs = jvar->dofIndices().size() * jvar->count();
    2986      950613 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2987             :       {
    2988      633742 :         jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
    2989      633742 :         jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
    2990             : 
    2991      633742 :         jacobianBlock(jvar->number(), ivar->number(), LocalDataKey{}, tag).resize(jdofs, idofs);
    2992      633742 :         jacobianBlockUsed(tag, jvar->number(), ivar->number(), false);
    2993             :       }
    2994             :     }
    2995             :   }
    2996      210656 : }
    2997             : 
    2998             : template <typename T>
    2999             : void
    3000   146022209 : Assembly::copyShapes(MooseVariableField<T> & v)
    3001             : {
    3002   146022209 :   phi(v).shallowCopy(v.phi());
    3003   146022209 :   gradPhi(v).shallowCopy(v.gradPhi());
    3004   146022209 :   if (v.computingSecond())
    3005       28970 :     secondPhi(v).shallowCopy(v.secondPhi());
    3006   146022209 : }
    3007             : 
    3008             : void
    3009   146022209 : Assembly::copyShapes(unsigned int var)
    3010             : {
    3011   146022209 :   auto & v = _sys.getVariable(_tid, var);
    3012   146022209 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3013             :   {
    3014   142636250 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3015   142636250 :     copyShapes(v);
    3016             :   }
    3017     3385959 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3018             :   {
    3019     1272769 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3020     1272769 :     copyShapes(v);
    3021             :   }
    3022     2113190 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3023             :   {
    3024     2113190 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3025     2113190 :     copyShapes(v);
    3026     2113190 :     if (v.computingCurl())
    3027       56824 :       curlPhi(v).shallowCopy(v.curlPhi());
    3028     2113190 :     if (v.computingDiv())
    3029      505440 :       divPhi(v).shallowCopy(v.divPhi());
    3030             :   }
    3031             :   else
    3032           0 :     mooseError("Unsupported variable field type!");
    3033   146022209 : }
    3034             : 
    3035             : template <typename T>
    3036             : void
    3037      714657 : Assembly::copyFaceShapes(MooseVariableField<T> & v)
    3038             : {
    3039      714657 :   phiFace(v).shallowCopy(v.phiFace());
    3040      714657 :   gradPhiFace(v).shallowCopy(v.gradPhiFace());
    3041      714657 :   if (v.computingSecond())
    3042        6089 :     secondPhiFace(v).shallowCopy(v.secondPhiFace());
    3043      714657 : }
    3044             : 
    3045             : void
    3046      714657 : Assembly::copyFaceShapes(unsigned int var)
    3047             : {
    3048      714657 :   auto & v = _sys.getVariable(_tid, var);
    3049      714657 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3050             :   {
    3051      633561 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3052      633561 :     copyFaceShapes(v);
    3053             :   }
    3054       81096 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3055             :   {
    3056       14570 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3057       14570 :     copyFaceShapes(v);
    3058             :   }
    3059       66526 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3060             :   {
    3061       66526 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3062       66526 :     copyFaceShapes(v);
    3063       66526 :     if (v.computingCurl())
    3064        7180 :       _vector_curl_phi_face.shallowCopy(v.curlPhi());
    3065       66526 :     if (v.computingDiv())
    3066       21168 :       _vector_div_phi_face.shallowCopy(v.divPhi());
    3067             :   }
    3068             :   else
    3069           0 :     mooseError("Unsupported variable field type!");
    3070      714657 : }
    3071             : 
    3072             : template <typename T>
    3073             : void
    3074      212349 : Assembly::copyNeighborShapes(MooseVariableField<T> & v)
    3075             : {
    3076      212349 :   if (v.usesPhiNeighbor())
    3077             :   {
    3078      212349 :     phiFaceNeighbor(v).shallowCopy(v.phiFaceNeighbor());
    3079      212349 :     phiNeighbor(v).shallowCopy(v.phiNeighbor());
    3080             :   }
    3081      212349 :   if (v.usesGradPhiNeighbor())
    3082             :   {
    3083      212349 :     gradPhiFaceNeighbor(v).shallowCopy(v.gradPhiFaceNeighbor());
    3084      212349 :     gradPhiNeighbor(v).shallowCopy(v.gradPhiNeighbor());
    3085             :   }
    3086      212349 :   if (v.usesSecondPhiNeighbor())
    3087             :   {
    3088           0 :     secondPhiFaceNeighbor(v).shallowCopy(v.secondPhiFaceNeighbor());
    3089           0 :     secondPhiNeighbor(v).shallowCopy(v.secondPhiNeighbor());
    3090             :   }
    3091      212349 : }
    3092             : 
    3093             : void
    3094      212349 : Assembly::copyNeighborShapes(unsigned int var)
    3095             : {
    3096      212349 :   auto & v = _sys.getVariable(_tid, var);
    3097      212349 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3098             :   {
    3099      208037 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3100      208037 :     copyNeighborShapes(v);
    3101             :   }
    3102        4312 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3103             :   {
    3104        4008 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3105        4008 :     copyNeighborShapes(v);
    3106             :   }
    3107         304 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3108             :   {
    3109         304 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3110         304 :     copyNeighborShapes(v);
    3111             :   }
    3112             :   else
    3113           0 :     mooseError("Unsupported variable field type!");
    3114      212349 : }
    3115             : 
    3116             : DenseMatrix<Number> &
    3117   375541096 : Assembly::jacobianBlockNeighbor(
    3118             :     Moose::DGJacobianType type, unsigned int ivar, unsigned int jvar, LocalDataKey, TagID tag)
    3119             : {
    3120   375541096 :   if (type == Moose::ElementElement)
    3121           0 :     jacobianBlockUsed(tag, ivar, jvar, true);
    3122             :   else
    3123   375541096 :     jacobianBlockNeighborUsed(tag, ivar, jvar, true);
    3124             : 
    3125   375541096 :   if (_block_diagonal_matrix)
    3126             :   {
    3127   145220858 :     switch (type)
    3128             :     {
    3129           0 :       default:
    3130             :       case Moose::ElementElement:
    3131           0 :         return _sub_Kee[tag][ivar][0];
    3132    48408330 :       case Moose::ElementNeighbor:
    3133    48408330 :         return _sub_Ken[tag][ivar][0];
    3134    48401258 :       case Moose::NeighborElement:
    3135    48401258 :         return _sub_Kne[tag][ivar][0];
    3136    48411270 :       case Moose::NeighborNeighbor:
    3137    48411270 :         return _sub_Knn[tag][ivar][0];
    3138             :     }
    3139             :   }
    3140             :   else
    3141             :   {
    3142   230320238 :     switch (type)
    3143             :     {
    3144           0 :       default:
    3145             :       case Moose::ElementElement:
    3146           0 :         return _sub_Kee[tag][ivar][jvar];
    3147    76773674 :       case Moose::ElementNeighbor:
    3148    76773674 :         return _sub_Ken[tag][ivar][jvar];
    3149    76772890 :       case Moose::NeighborElement:
    3150    76772890 :         return _sub_Kne[tag][ivar][jvar];
    3151    76773674 :       case Moose::NeighborNeighbor:
    3152    76773674 :         return _sub_Knn[tag][ivar][jvar];
    3153             :     }
    3154             :   }
    3155             : }
    3156             : 
    3157             : DenseMatrix<Number> &
    3158    11411555 : Assembly::jacobianBlockMortar(Moose::ConstraintJacobianType type,
    3159             :                               unsigned int ivar,
    3160             :                               unsigned int jvar,
    3161             :                               LocalDataKey,
    3162             :                               TagID tag)
    3163             : {
    3164    11411555 :   jacobianBlockLowerUsed(tag, ivar, jvar, true);
    3165    11411555 :   if (_block_diagonal_matrix)
    3166             :   {
    3167     2134825 :     switch (type)
    3168             :     {
    3169      364343 :       default:
    3170             :       case Moose::LowerLower:
    3171      364343 :         return _sub_Kll[tag][ivar][0];
    3172      363911 :       case Moose::LowerSecondary:
    3173      363911 :         return _sub_Kle[tag][ivar][0];
    3174      363695 :       case Moose::LowerPrimary:
    3175      363695 :         return _sub_Kln[tag][ivar][0];
    3176      395438 :       case Moose::SecondaryLower:
    3177      395438 :         return _sub_Kel[tag][ivar][0];
    3178       63054 :       case Moose::SecondarySecondary:
    3179       63054 :         return _sub_Kee[tag][ivar][0];
    3180       63054 :       case Moose::SecondaryPrimary:
    3181       63054 :         return _sub_Ken[tag][ivar][0];
    3182      395222 :       case Moose::PrimaryLower:
    3183      395222 :         return _sub_Knl[tag][ivar][0];
    3184       63054 :       case Moose::PrimarySecondary:
    3185       63054 :         return _sub_Kne[tag][ivar][0];
    3186       63054 :       case Moose::PrimaryPrimary:
    3187       63054 :         return _sub_Knn[tag][ivar][0];
    3188             :     }
    3189             :   }
    3190             :   else
    3191             :   {
    3192     9276730 :     switch (type)
    3193             :     {
    3194     1836950 :       default:
    3195             :       case Moose::LowerLower:
    3196     1836950 :         return _sub_Kll[tag][ivar][jvar];
    3197     1835960 :       case Moose::LowerSecondary:
    3198     1835960 :         return _sub_Kle[tag][ivar][jvar];
    3199     1827446 :       case Moose::LowerPrimary:
    3200     1827446 :         return _sub_Kln[tag][ivar][jvar];
    3201     1838228 :       case Moose::SecondaryLower:
    3202     1838228 :         return _sub_Kel[tag][ivar][jvar];
    3203       27108 :       case Moose::SecondarySecondary:
    3204       27108 :         return _sub_Kee[tag][ivar][jvar];
    3205       27108 :       case Moose::SecondaryPrimary:
    3206       27108 :         return _sub_Ken[tag][ivar][jvar];
    3207     1829714 :       case Moose::PrimaryLower:
    3208     1829714 :         return _sub_Knl[tag][ivar][jvar];
    3209       27108 :       case Moose::PrimarySecondary:
    3210       27108 :         return _sub_Kne[tag][ivar][jvar];
    3211       27108 :       case Moose::PrimaryPrimary:
    3212       27108 :         return _sub_Knn[tag][ivar][jvar];
    3213             :     }
    3214             :   }
    3215             : }
    3216             : 
    3217             : void
    3218  1207530983 : 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  1207530983 :   auto ndof = dof_indices.size();
    3227  1207530983 :   auto ntdof = res_block.size();
    3228  1207530983 :   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  1207530983 :   if (count > 1)
    3232             :   {
    3233             :     // expanding dof indices
    3234     5526913 :     dof_indices.resize(ntdof);
    3235     5526913 :     unsigned int p = 0;
    3236    19243119 :     for (MooseIndex(count) j = 0; j < count; ++j)
    3237    75393490 :       for (MooseIndex(ndof) i = 0; i < ndof; ++i)
    3238             :       {
    3239    61677284 :         dof_indices[p] = dof_indices[i] + (is_nodal ? j : j * ndof);
    3240    61677284 :         res_block(p) *= scaling_factor[j];
    3241    61677284 :         ++p;
    3242             :       }
    3243             :   }
    3244             :   else
    3245             :   {
    3246  1202004070 :     if (scaling_factor[0] != 1.0)
    3247     4991931 :       res_block *= scaling_factor[0];
    3248             :   }
    3249             : 
    3250  1207530983 :   _dof_map.constrain_element_vector(res_block, dof_indices, false);
    3251  1207530983 : }
    3252             : 
    3253             : void
    3254    15246856 : 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    15246856 :   if (dof_indices.size() > 0 && res_block.size())
    3261             :   {
    3262     7826394 :     _temp_dof_indices = dof_indices;
    3263     7826394 :     _tmp_Re = res_block;
    3264     7826394 :     processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor, is_nodal);
    3265     7826394 :     residual.add_vector(_tmp_Re, _temp_dof_indices);
    3266             :   }
    3267    15246856 : }
    3268             : 
    3269             : void
    3270  1281158447 : 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  1281158447 :   if (dof_indices.size() > 0 && res_block.size())
    3278             :   {
    3279  1199704589 :     _temp_dof_indices = dof_indices;
    3280  1199704589 :     _tmp_Re = res_block;
    3281  1199704589 :     processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor, is_nodal);
    3282             : 
    3283  5753504231 :     for (MooseIndex(_tmp_Re) i = 0; i < _tmp_Re.size(); i++)
    3284             :     {
    3285  4553799642 :       cached_residual_values.push_back(_tmp_Re(i));
    3286  4553799642 :       cached_residual_rows.push_back(_temp_dof_indices[i]);
    3287             :     }
    3288             :   }
    3289             : 
    3290  1281158447 :   res_block.zero();
    3291  1281158447 : }
    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      883666 : 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      883666 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3316      883666 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3317      883666 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3318     2546396 :   for (const auto & var : vars)
    3319     1662730 :     addResidualBlock(residual,
    3320     1662730 :                      tag_Re[var->number()],
    3321     1662730 :                      var->dofIndices(),
    3322     1662730 :                      var->arrayScalingFactor(),
    3323     1662730 :                      var->isNodal());
    3324      883666 : }
    3325             : 
    3326             : void
    3327      305189 : Assembly::addResidual(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3328             : {
    3329     1188855 :   for (const auto & vector_tag : vector_tags)
    3330      883666 :     if (_sys.hasVector(vector_tag._id))
    3331      883666 :       addResidual(vector_tag);
    3332      305189 : }
    3333             : 
    3334             : void
    3335     5386690 : 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     5386690 :   auto & tag_Rn = _sub_Rn[vector_tag._type_id];
    3341     5386690 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3342     5386690 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3343    12080020 :   for (const auto & var : vars)
    3344     6693330 :     addResidualBlock(residual,
    3345     6693330 :                      tag_Rn[var->number()],
    3346     6693330 :                      var->dofIndicesNeighbor(),
    3347     6693330 :                      var->arrayScalingFactor(),
    3348     6693330 :                      var->isNodal());
    3349     5386690 : }
    3350             : 
    3351             : void
    3352     2168119 : Assembly::addResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3353             : {
    3354     7554809 :   for (const auto & vector_tag : vector_tags)
    3355     5386690 :     if (_sys.hasVector(vector_tag._id))
    3356     5386690 :       addResidualNeighbor(vector_tag);
    3357     2168119 : }
    3358             : 
    3359             : void
    3360     5348820 : 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     5348820 :   auto & tag_Rl = _sub_Rl[vector_tag._type_id];
    3366     5348820 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3367     5348820 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3368    11986714 :   for (const auto & var : vars)
    3369     6637894 :     addResidualBlock(residual,
    3370     6637894 :                      tag_Rl[var->number()],
    3371     6637894 :                      var->dofIndicesLower(),
    3372     6637894 :                      var->arrayScalingFactor(),
    3373     6637894 :                      var->isNodal());
    3374     5348820 : }
    3375             : 
    3376             : void
    3377     2144175 : Assembly::addResidualLower(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3378             : {
    3379     7492995 :   for (const auto & vector_tag : vector_tags)
    3380     5348820 :     if (_sys.hasVector(vector_tag._id))
    3381     5348820 :       addResidualLower(vector_tag);
    3382     2144175 : }
    3383             : 
    3384             : // private method, so no key required
    3385             : void
    3386      193481 : 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      193481 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3393      193481 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3394      193481 :   const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
    3395      446383 :   for (const auto & var : vars)
    3396      252902 :     addResidualBlock(
    3397      252902 :         residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor(), false);
    3398      193481 : }
    3399             : 
    3400             : void
    3401       64520 : Assembly::addResidualScalar(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3402             : {
    3403      258001 :   for (const auto & vector_tag : vector_tags)
    3404      193481 :     if (_sys.hasVector(vector_tag._id))
    3405      193481 :       addResidualScalar(vector_tag);
    3406       64520 : }
    3407             : 
    3408             : void
    3409   374538654 : Assembly::cacheResidual(GlobalDataKey, const std::vector<VectorTag> & tags)
    3410             : {
    3411   374538654 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3412   796510606 :   for (const auto & var : vars)
    3413  1572185753 :     for (const auto & vector_tag : tags)
    3414  1150213801 :       if (_sys.hasVector(vector_tag._id))
    3415  1150213801 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3416  1150213801 :                            _cached_residual_rows[vector_tag._type_id],
    3417  1150213801 :                            _sub_Re[vector_tag._type_id][var->number()],
    3418  1150213801 :                            var->dofIndices(),
    3419  1150213801 :                            var->arrayScalingFactor(),
    3420  1150213801 :                            var->isNodal());
    3421   374538654 : }
    3422             : 
    3423             : // private method, so no key required
    3424             : void
    3425   120745181 : Assembly::cacheResidual(dof_id_type dof, Real value, TagID tag_id)
    3426             : {
    3427   120745181 :   const VectorTag & tag = _subproblem.getVectorTag(tag_id);
    3428             : 
    3429   120745181 :   _cached_residual_values[tag._type_id].push_back(value);
    3430   120745181 :   _cached_residual_rows[tag._type_id].push_back(dof);
    3431   120745181 : }
    3432             : 
    3433             : // private method, so no key required
    3434             : void
    3435   120262028 : Assembly::cacheResidual(dof_id_type dof, Real value, const std::set<TagID> & tags)
    3436             : {
    3437   241007209 :   for (auto & tag : tags)
    3438   120745181 :     cacheResidual(dof, value, tag);
    3439   120262028 : }
    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    38608438 : Assembly::cacheResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & tags)
    3461             : {
    3462    38608438 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3463    89642332 :   for (const auto & var : vars)
    3464   181349956 :     for (const auto & vector_tag : tags)
    3465   130316062 :       if (_sys.hasVector(vector_tag._id))
    3466   130316062 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3467   130316062 :                            _cached_residual_rows[vector_tag._type_id],
    3468   130316062 :                            _sub_Rn[vector_tag._type_id][var->number()],
    3469   130316062 :                            var->dofIndicesNeighbor(),
    3470   130316062 :                            var->arrayScalingFactor(),
    3471   130316062 :                            var->isNodal());
    3472    38608438 : }
    3473             : 
    3474             : void
    3475      194418 : Assembly::cacheResidualLower(GlobalDataKey, const std::vector<VectorTag> & tags)
    3476             : {
    3477      194418 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3478      491278 :   for (const auto & var : vars)
    3479      925444 :     for (const auto & vector_tag : tags)
    3480      628584 :       if (_sys.hasVector(vector_tag._id))
    3481      628584 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3482      628584 :                            _cached_residual_rows[vector_tag._type_id],
    3483      628584 :                            _sub_Rl[vector_tag._type_id][var->number()],
    3484      628584 :                            var->dofIndicesLower(),
    3485      628584 :                            var->arrayScalingFactor(),
    3486      628584 :                            var->isNodal());
    3487      194418 : }
    3488             : 
    3489             : void
    3490    57663993 : Assembly::addCachedResiduals(GlobalDataKey, const std::vector<VectorTag> & tags)
    3491             : {
    3492   208827820 :   for (const auto & vector_tag : tags)
    3493             :   {
    3494   151163827 :     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   151163827 :     addCachedResidualDirectly(_sys.getVector(vector_tag._id), GlobalDataKey{}, vector_tag);
    3501             :   }
    3502    57663993 : }
    3503             : 
    3504             : void
    3505       11874 : Assembly::clearCachedResiduals(GlobalDataKey)
    3506             : {
    3507       46473 :   for (const auto & vector_tag : _residual_vector_tags)
    3508       34599 :     clearCachedResiduals(vector_tag);
    3509       11874 : }
    3510             : 
    3511             : // private method, so no key required
    3512             : void
    3513   142600753 : Assembly::clearCachedResiduals(const VectorTag & vector_tag)
    3514             : {
    3515   142600753 :   auto & values = _cached_residual_values[vector_tag._type_id];
    3516   142600753 :   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   142600753 :   if (_max_cached_residuals < values.size())
    3524       48422 :     _max_cached_residuals = values.size();
    3525             : 
    3526             :   // Clear both vectors (keeps the capacity the same)
    3527   142600753 :   values.clear();
    3528   142600753 :   rows.clear();
    3529             :   // And then reserve: use 2 as a fudge factor to *really* avoid dynamic allocation!
    3530   142600753 :   values.reserve(_max_cached_residuals * 2);
    3531   142600753 :   rows.reserve(_max_cached_residuals * 2);
    3532   142600753 : }
    3533             : 
    3534             : void
    3535   151186552 : Assembly::addCachedResidualDirectly(NumericVector<Number> & residual,
    3536             :                                     GlobalDataKey,
    3537             :                                     const VectorTag & vector_tag)
    3538             : {
    3539   151186552 :   const auto & values = _cached_residual_values[vector_tag._type_id];
    3540   151186552 :   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   151186552 :   if (!values.empty())
    3546             :   {
    3547   142566154 :     residual.add_vector(values, rows);
    3548   142566154 :     clearCachedResiduals(vector_tag);
    3549             :   }
    3550   151186552 : }
    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      506243 : 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      506243 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3590       97516 :     return;
    3591      408727 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3592           0 :     return;
    3593             : 
    3594      408727 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3595             : 
    3596      832898 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3597             :   {
    3598      424171 :     unsigned int iv = ivar.number();
    3599     1025853 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3600             :     {
    3601      601682 :       unsigned int jv = jvar.number();
    3602      601682 :       if (jt < jv || jt >= jv + jvar.count())
    3603      148783 :         continue;
    3604      452899 :       unsigned int j = jt - jv;
    3605             : 
    3606      452899 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3607      452899 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3608      452899 :       auto indof = di.size();
    3609      452899 :       auto jndof = dj.size();
    3610             : 
    3611      452899 :       unsigned int jj = j;
    3612      452899 :       if (iv == jv && _component_block_diagonal[iv])
    3613             :         // here i must be equal to j
    3614      366046 :         jj = 0;
    3615             : 
    3616      452899 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3617      452899 :       if (scaling_factor[i] != 1.0)
    3618        6130 :         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      452899 :       if (!_sys.computingScalingJacobian())
    3624      452829 :         _dof_map.constrain_element_matrix(sub, di, dj, false);
    3625             : 
    3626      452899 :       jacobian.add_matrix(sub, di, dj);
    3627      452899 :     }
    3628             :   }
    3629             : }
    3630             : 
    3631             : // private method, so no key required
    3632             : void
    3633    67460537 : 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    67460537 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3641      432121 :     return;
    3642    67028416 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3643           0 :     return;
    3644    67028416 :   if (!_sys.hasMatrix(tag))
    3645           0 :     return;
    3646             : 
    3647    67028416 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3648             : 
    3649   135006041 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3650             :   {
    3651    67977625 :     unsigned int iv = ivar.number();
    3652   170766620 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3653             :     {
    3654   102788995 :       unsigned int jv = jvar.number();
    3655   102788995 :       if (jt < jv || jt >= jv + jvar.count())
    3656    31980558 :         continue;
    3657    70808437 :       unsigned int j = jt - jv;
    3658             : 
    3659    70808437 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3660    70808437 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3661    70808437 :       auto indof = di.size();
    3662    70808437 :       auto jndof = dj.size();
    3663             : 
    3664    70808437 :       unsigned int jj = j;
    3665    70808437 :       if (iv == jv && _component_block_diagonal[iv])
    3666             :         // here i must be equal to j
    3667    56049363 :         jj = 0;
    3668             : 
    3669    70808437 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3670    70808437 :       if (scaling_factor[i] != 1.0)
    3671     1805486 :         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    70808437 :       if (!_sys.computingScalingJacobian())
    3677    70585080 :         _dof_map.constrain_element_matrix(sub, di, dj, false);
    3678             : 
    3679   383783695 :       for (MooseIndex(di) i = 0; i < di.size(); i++)
    3680  1890595593 :         for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3681             :         {
    3682  1577620335 :           _cached_jacobian_values[tag].push_back(sub(i, j));
    3683  1577620335 :           _cached_jacobian_rows[tag].push_back(di[i]);
    3684  1577620335 :           _cached_jacobian_cols[tag].push_back(dj[j]);
    3685             :         }
    3686    70808437 :     }
    3687             :   }
    3688             : 
    3689    67028416 :   jac_block.zero();
    3690             : }
    3691             : 
    3692             : // private method, so no key required
    3693             : void
    3694         854 : 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         854 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3702           0 :     return;
    3703         854 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3704           0 :     return;
    3705         854 :   if (!_sys.hasMatrix(tag))
    3706           0 :     return;
    3707             : 
    3708         854 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3709             : 
    3710        1708 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3711             :   {
    3712         854 :     unsigned int iv = ivar.number();
    3713        2506 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3714             :     {
    3715        1652 :       unsigned int jv = jvar.number();
    3716        1652 :       if (jt < jv || jt >= jv + jvar.count())
    3717         798 :         continue;
    3718         854 :       unsigned int j = jt - jv;
    3719             : 
    3720         854 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3721         854 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3722         854 :       auto indof = di.size();
    3723         854 :       auto jndof = dj.size();
    3724             : 
    3725         854 :       unsigned int jj = j;
    3726         854 :       if (iv == jv && _component_block_diagonal[iv])
    3727             :         // here i must be equal to j
    3728         208 :         jj = 0;
    3729             : 
    3730         854 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3731         854 :       if (scaling_factor[i] != 1.0)
    3732         376 :         sub *= scaling_factor[i];
    3733             : 
    3734         854 :       _dof_map.constrain_element_matrix(sub, di, dj, false);
    3735             : 
    3736        4222 :       for (MooseIndex(di) i = 0; i < di.size(); i++)
    3737      261872 :         for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3738      258504 :           if (sub(i, j) != 0.0) // no storage allocated for unimplemented jacobian terms,
    3739             :                                 // maintaining maximum sparsity possible
    3740             :           {
    3741       34856 :             _cached_jacobian_values[tag].push_back(sub(i, j));
    3742       34856 :             _cached_jacobian_rows[tag].push_back(di[i]);
    3743       34856 :             _cached_jacobian_cols[tag].push_back(dj[j]);
    3744             :           }
    3745         854 :     }
    3746             :   }
    3747             : 
    3748         854 :   jac_block.zero();
    3749             : }
    3750             : 
    3751             : void
    3752     6719819 : 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    13417991 :   if ((idof_indices.size() > 0) && (jdof_indices.size() > 0) && jac_block.n() && jac_block.m() &&
    3761     6698172 :       _sys.hasMatrix(tag))
    3762             :   {
    3763     6698172 :     std::vector<dof_id_type> di(idof_indices);
    3764     6698172 :     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     6698172 :     if (!_sys.computingScalingJacobian())
    3770     6698172 :       _dof_map.constrain_element_matrix(jac_block, di, dj, false);
    3771             : 
    3772     6698172 :     if (scaling_factor != 1.0)
    3773        8473 :       jac_block *= scaling_factor;
    3774             : 
    3775    39628885 :     for (MooseIndex(di) i = 0; i < di.size(); i++)
    3776   217803943 :       for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3777             :       {
    3778   184873230 :         _cached_jacobian_values[tag].push_back(jac_block(i, j));
    3779   184873230 :         _cached_jacobian_rows[tag].push_back(di[i]);
    3780   184873230 :         _cached_jacobian_cols[tag].push_back(dj[j]);
    3781             :       }
    3782     6698172 :   }
    3783     6719819 :   jac_block.zero();
    3784     6719819 : }
    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     4222649 : 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    12745090 :   for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3834     8522445 :     if (_sys.hasMatrix(i))
    3835  2007698494 :       for (MooseIndex(_cached_jacobian_rows[i]) j = 0; j < _cached_jacobian_rows[i].size(); j++)
    3836  4006917522 :         _sys.getMatrix(i).add(_cached_jacobian_rows[i][j],
    3837  2003458761 :                               _cached_jacobian_cols[i][j],
    3838  2003458761 :                               _cached_jacobian_values[i][j]);
    3839             : 
    3840    12745086 :   for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3841             :   {
    3842     8522441 :     if (!_sys.hasMatrix(i))
    3843     4282708 :       continue;
    3844             : 
    3845     4239733 :     if (_max_cached_jacobians < _cached_jacobian_values[i].size())
    3846       50374 :       _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     4239733 :     _cached_jacobian_values[i].clear();
    3851     4239733 :     _cached_jacobian_values[i].reserve(_max_cached_jacobians * 2);
    3852             : 
    3853     4239733 :     _cached_jacobian_rows[i].clear();
    3854     4239733 :     _cached_jacobian_rows[i].reserve(_max_cached_jacobians * 2);
    3855             : 
    3856     4239733 :     _cached_jacobian_cols[i].clear();
    3857     4239733 :     _cached_jacobian_cols[i].reserve(_max_cached_jacobians * 2);
    3858             :   }
    3859     4222645 : }
    3860             : 
    3861             : inline void
    3862      116916 : Assembly::addJacobianCoupledVarPair(const MooseVariableBase & ivar, const MooseVariableBase & jvar)
    3863             : {
    3864      116916 :   auto i = ivar.number();
    3865      116916 :   auto j = jvar.number();
    3866      351936 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    3867      235020 :     if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
    3868       62474 :       addJacobianBlock(_sys.getMatrix(tag),
    3869      124948 :                        jacobianBlock(i, j, LocalDataKey{}, tag),
    3870             :                        ivar,
    3871             :                        jvar,
    3872       62474 :                        ivar.dofIndices(),
    3873       62474 :                        jvar.dofIndices());
    3874      116916 : }
    3875             : 
    3876             : void
    3877       42272 : Assembly::addJacobian(GlobalDataKey)
    3878             : {
    3879      124590 :   for (const auto & it : _cm_ff_entry)
    3880       82318 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3881             : 
    3882       42272 :   for (const auto & it : _cm_sf_entry)
    3883           0 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3884             : 
    3885       42272 :   for (const auto & it : _cm_fs_entry)
    3886           0 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3887       42272 : }
    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        9087 : Assembly::addJacobianNeighbor(GlobalDataKey)
    3913             : {
    3914       42579 :   for (const auto & it : _cm_ff_entry)
    3915             :   {
    3916       33492 :     auto ivar = it.first;
    3917       33492 :     auto jvar = it.second;
    3918       33492 :     auto i = ivar->number();
    3919       33492 :     auto j = jvar->number();
    3920      100908 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    3921      100908 :          tag < _jacobian_block_neighbor_used.size();
    3922             :          tag++)
    3923       67416 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    3924             :       {
    3925       25192 :         addJacobianBlock(_sys.getMatrix(tag),
    3926       25192 :                          jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    3927             :                          *ivar,
    3928             :                          *jvar,
    3929       25192 :                          ivar->dofIndices(),
    3930       25192 :                          jvar->dofIndicesNeighbor());
    3931             : 
    3932       25192 :         addJacobianBlock(_sys.getMatrix(tag),
    3933       25192 :                          jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    3934             :                          *ivar,
    3935             :                          *jvar,
    3936       25192 :                          ivar->dofIndicesNeighbor(),
    3937       25192 :                          jvar->dofIndices());
    3938             : 
    3939       25192 :         addJacobianBlock(_sys.getMatrix(tag),
    3940       50384 :                          jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    3941             :                          *ivar,
    3942             :                          *jvar,
    3943       25192 :                          ivar->dofIndicesNeighbor(),
    3944       25192 :                          jvar->dofIndicesNeighbor());
    3945             :       }
    3946             :   }
    3947        9087 : }
    3948             : 
    3949             : void
    3950      126338 : Assembly::addJacobianNeighborLowerD(GlobalDataKey)
    3951             : {
    3952      328513 :   for (const auto & it : _cm_ff_entry)
    3953             :   {
    3954      202175 :     auto ivar = it.first;
    3955      202175 :     auto jvar = it.second;
    3956      202175 :     auto i = ivar->number();
    3957      202175 :     auto j = jvar->number();
    3958      612249 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    3959             :          tag++)
    3960      410074 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    3961             :       {
    3962        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3963        8814 :                          jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    3964             :                          *ivar,
    3965             :                          *jvar,
    3966        8814 :                          ivar->dofIndicesLower(),
    3967        8814 :                          jvar->dofIndicesLower());
    3968             : 
    3969        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3970        8814 :                          jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    3971             :                          *ivar,
    3972             :                          *jvar,
    3973        8814 :                          ivar->dofIndicesLower(),
    3974        8814 :                          jvar->dofIndicesNeighbor());
    3975             : 
    3976        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3977        8814 :                          jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
    3978             :                          *ivar,
    3979             :                          *jvar,
    3980        8814 :                          ivar->dofIndicesLower(),
    3981        8814 :                          jvar->dofIndices());
    3982             : 
    3983        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3984        8814 :                          jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    3985             :                          *ivar,
    3986             :                          *jvar,
    3987        8814 :                          ivar->dofIndicesNeighbor(),
    3988        8814 :                          jvar->dofIndicesLower());
    3989             : 
    3990        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3991       17628 :                          jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
    3992             :                          *ivar,
    3993             :                          *jvar,
    3994        8814 :                          ivar->dofIndices(),
    3995        8814 :                          jvar->dofIndicesLower());
    3996             :       }
    3997             : 
    3998      612249 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    3999      612249 :          tag < _jacobian_block_neighbor_used.size();
    4000             :          tag++)
    4001      410074 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    4002             :       {
    4003      100499 :         addJacobianBlock(_sys.getMatrix(tag),
    4004      100499 :                          jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    4005             :                          *ivar,
    4006             :                          *jvar,
    4007      100499 :                          ivar->dofIndices(),
    4008      100499 :                          jvar->dofIndicesNeighbor());
    4009             : 
    4010      100499 :         addJacobianBlock(_sys.getMatrix(tag),
    4011      100499 :                          jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    4012             :                          *ivar,
    4013             :                          *jvar,
    4014      100499 :                          ivar->dofIndicesNeighbor(),
    4015      100499 :                          jvar->dofIndices());
    4016             : 
    4017      100499 :         addJacobianBlock(_sys.getMatrix(tag),
    4018      200998 :                          jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    4019             :                          *ivar,
    4020             :                          *jvar,
    4021      100499 :                          ivar->dofIndicesNeighbor(),
    4022      100499 :                          jvar->dofIndicesNeighbor());
    4023             :       }
    4024             :   }
    4025      126338 : }
    4026             : 
    4027             : void
    4028        5436 : Assembly::addJacobianLowerD(GlobalDataKey)
    4029             : {
    4030       47010 :   for (const auto & it : _cm_ff_entry)
    4031             :   {
    4032       41574 :     auto ivar = it.first;
    4033       41574 :     auto jvar = it.second;
    4034       41574 :     auto i = ivar->number();
    4035       41574 :     auto j = jvar->number();
    4036      124722 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    4037             :          tag++)
    4038       83148 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    4039             :       {
    4040        7542 :         addJacobianBlock(_sys.getMatrix(tag),
    4041        7542 :                          jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    4042             :                          *ivar,
    4043             :                          *jvar,
    4044        7542 :                          ivar->dofIndicesLower(),
    4045        7542 :                          jvar->dofIndicesLower());
    4046             : 
    4047        7542 :         addJacobianBlock(_sys.getMatrix(tag),
    4048        7542 :                          jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    4049             :                          *ivar,
    4050             :                          *jvar,
    4051        7542 :                          ivar->dofIndicesLower(),
    4052        7542 :                          jvar->dofIndices());
    4053             : 
    4054        7542 :         addJacobianBlock(_sys.getMatrix(tag),
    4055       15084 :                          jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    4056             :                          *ivar,
    4057             :                          *jvar,
    4058        7542 :                          ivar->dofIndices(),
    4059        7542 :                          jvar->dofIndicesLower());
    4060             :       }
    4061             :   }
    4062        5436 : }
    4063             : 
    4064             : void
    4065    56920459 : Assembly::cacheJacobian(GlobalDataKey)
    4066             : {
    4067   142883593 :   for (const auto & it : _cm_ff_entry)
    4068    85963134 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4069             : 
    4070    57202456 :   for (const auto & it : _cm_fs_entry)
    4071      281997 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4072             : 
    4073    57202456 :   for (const auto & it : _cm_sf_entry)
    4074      281997 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4075    56920459 : }
    4076             : 
    4077             : // private method, so no key required
    4078             : void
    4079    86527128 : Assembly::cacheJacobianCoupledVarPair(const MooseVariableBase & ivar,
    4080             :                                       const MooseVariableBase & jvar)
    4081             : {
    4082    86527128 :   auto i = ivar.number();
    4083    86527128 :   auto j = jvar.number();
    4084   261807117 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    4085   175279989 :     if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
    4086    66998054 :       cacheJacobianBlock(jacobianBlock(i, j, LocalDataKey{}, tag),
    4087             :                          ivar,
    4088             :                          jvar,
    4089    66998054 :                          ivar.dofIndices(),
    4090    66998054 :                          jvar.dofIndices(),
    4091             :                          tag);
    4092    86527128 : }
    4093             : 
    4094             : void
    4095        5880 : Assembly::cacheJacobianNonlocal(GlobalDataKey)
    4096             : {
    4097       11900 :   for (const auto & it : _cm_nonlocal_entry)
    4098             :   {
    4099        6020 :     auto ivar = it.first;
    4100        6020 :     auto jvar = it.second;
    4101        6020 :     auto i = ivar->number();
    4102        6020 :     auto j = jvar->number();
    4103       18060 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    4104       18060 :          tag < _jacobian_block_nonlocal_used.size();
    4105             :          tag++)
    4106       12040 :       if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
    4107        1708 :         cacheJacobianBlockNonzero(jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
    4108             :                                   *ivar,
    4109             :                                   *jvar,
    4110         854 :                                   ivar->dofIndices(),
    4111             :                                   jvar->allDofIndices(),
    4112             :                                   tag);
    4113             :   }
    4114        5880 : }
    4115             : 
    4116             : void
    4117       10576 : Assembly::cacheJacobianNeighbor(GlobalDataKey)
    4118             : {
    4119       36944 :   for (const auto & it : _cm_ff_entry)
    4120             :   {
    4121       26368 :     auto ivar = it.first;
    4122       26368 :     auto jvar = it.second;
    4123       26368 :     auto i = ivar->number();
    4124       26368 :     auto j = jvar->number();
    4125             : 
    4126       79104 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    4127       79104 :          tag < _jacobian_block_neighbor_used.size();
    4128             :          tag++)
    4129       52736 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    4130             :       {
    4131        8784 :         cacheJacobianBlock(jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    4132             :                            *ivar,
    4133             :                            *jvar,
    4134        8784 :                            ivar->dofIndices(),
    4135        8784 :                            jvar->dofIndicesNeighbor(),
    4136             :                            tag);
    4137        8784 :         cacheJacobianBlock(jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    4138             :                            *ivar,
    4139             :                            *jvar,
    4140        8784 :                            ivar->dofIndicesNeighbor(),
    4141        8784 :                            jvar->dofIndices(),
    4142             :                            tag);
    4143        8784 :         cacheJacobianBlock(
    4144       17568 :             jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    4145             :             *ivar,
    4146             :             *jvar,
    4147        8784 :             ivar->dofIndicesNeighbor(),
    4148        8784 :             jvar->dofIndicesNeighbor(),
    4149             :             tag);
    4150             :       }
    4151             :   }
    4152       10576 : }
    4153             : 
    4154             : void
    4155       91615 : Assembly::cacheJacobianMortar(GlobalDataKey)
    4156             : {
    4157      368213 :   for (const auto & it : _cm_ff_entry)
    4158             :   {
    4159      276598 :     auto ivar = it.first;
    4160      276598 :     auto jvar = it.second;
    4161      276598 :     auto i = ivar->number();
    4162      276598 :     auto j = jvar->number();
    4163      829794 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    4164             :          tag++)
    4165      553196 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    4166             :       {
    4167       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    4168             :                            *ivar,
    4169             :                            *jvar,
    4170       48459 :                            ivar->dofIndicesLower(),
    4171       48459 :                            jvar->dofIndicesLower(),
    4172             :                            tag);
    4173             : 
    4174       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    4175             :                            *ivar,
    4176             :                            *jvar,
    4177       48459 :                            ivar->dofIndicesLower(),
    4178       48459 :                            jvar->dofIndices(),
    4179             :                            tag);
    4180             : 
    4181       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
    4182             :                            *ivar,
    4183             :                            *jvar,
    4184       48459 :                            ivar->dofIndicesLower(),
    4185       48459 :                            jvar->dofIndicesNeighbor(),
    4186             :                            tag);
    4187             : 
    4188       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    4189             :                            *ivar,
    4190             :                            *jvar,
    4191       48459 :                            ivar->dofIndices(),
    4192       48459 :                            jvar->dofIndicesLower(),
    4193             :                            tag);
    4194             : 
    4195       48459 :         cacheJacobianBlock(
    4196       48459 :             jacobianBlockMortar(Moose::SecondarySecondary, i, j, LocalDataKey{}, tag),
    4197             :             *ivar,
    4198             :             *jvar,
    4199       48459 :             ivar->dofIndices(),
    4200       48459 :             jvar->dofIndices(),
    4201             :             tag);
    4202             : 
    4203       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryPrimary, i, j, LocalDataKey{}, tag),
    4204             :                            *ivar,
    4205             :                            *jvar,
    4206       48459 :                            ivar->dofIndices(),
    4207       48459 :                            jvar->dofIndicesNeighbor(),
    4208             :                            tag);
    4209             : 
    4210       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
    4211             :                            *ivar,
    4212             :                            *jvar,
    4213       48459 :                            ivar->dofIndicesNeighbor(),
    4214       48459 :                            jvar->dofIndicesLower(),
    4215             :                            tag);
    4216             : 
    4217       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimarySecondary, i, j, LocalDataKey{}, tag),
    4218             :                            *ivar,
    4219             :                            *jvar,
    4220       48459 :                            ivar->dofIndicesNeighbor(),
    4221       48459 :                            jvar->dofIndices(),
    4222             :                            tag);
    4223             : 
    4224       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryPrimary, i, j, LocalDataKey{}, tag),
    4225             :                            *ivar,
    4226             :                            *jvar,
    4227       48459 :                            ivar->dofIndicesNeighbor(),
    4228       48459 :                            jvar->dofIndicesNeighbor(),
    4229             :                            tag);
    4230             :       }
    4231             :   }
    4232       91615 : }
    4233             : 
    4234             : void
    4235       69972 : 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      177660 :   for (auto tag : tags)
    4244      107688 :     addJacobianBlock(jacobian, ivar, jvar, dof_map, dof_indices, GlobalDataKey{}, tag);
    4245       69972 : }
    4246             : 
    4247             : void
    4248      107688 : 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      107688 :   if (dof_indices.size() == 0)
    4257           0 :     return;
    4258      107688 :   if (!(*_cm)(ivar, jvar))
    4259           0 :     return;
    4260             : 
    4261      107688 :   auto & iv = _sys.getVariable(_tid, ivar);
    4262      107688 :   auto & jv = _sys.getVariable(_tid, jvar);
    4263      107688 :   auto & scaling_factor = iv.arrayScalingFactor();
    4264             : 
    4265      107688 :   const unsigned int ivn = iv.number();
    4266      107688 :   const unsigned int jvn = jv.number();
    4267      107688 :   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      107688 :   const unsigned int i = ivar - ivn;
    4276      107688 :   const unsigned int j = jvar - jvn;
    4277             : 
    4278             :   // DoF indices are independently given
    4279      107688 :   auto di = dof_indices;
    4280      107688 :   auto dj = dof_indices;
    4281             : 
    4282      107688 :   auto indof = di.size();
    4283      107688 :   auto jndof = dj.size();
    4284             : 
    4285      107688 :   unsigned int jj = j;
    4286      107688 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4287      102608 :     jj = 0;
    4288             : 
    4289      107688 :   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      107688 :   if (!_sys.computingScalingJacobian())
    4294      107688 :     dof_map.constrain_element_matrix(sub, di, dj, false);
    4295             : 
    4296      107688 :   if (scaling_factor[i] != 1.0)
    4297           0 :     sub *= scaling_factor[i];
    4298             : 
    4299      107688 :   jacobian.add_matrix(sub, di, dj);
    4300      107688 : }
    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       15594 : Assembly::addJacobianScalar(GlobalDataKey)
    4461             : {
    4462       35579 :   for (const auto & it : _cm_ss_entry)
    4463       19985 :     addJacobianCoupledVarPair(*it.first, *it.second);
    4464       15594 : }
    4465             : 
    4466             : void
    4467       39177 : Assembly::addJacobianOffDiagScalar(unsigned int ivar, GlobalDataKey)
    4468             : {
    4469       39177 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    4470       39177 :   MooseVariableScalar & var_i = _sys.getScalarVariable(_tid, ivar);
    4471       53790 :   for (const auto & var_j : vars)
    4472       14613 :     addJacobianCoupledVarPair(var_i, *var_j);
    4473       39177 : }
    4474             : 
    4475             : void
    4476   250173463 : Assembly::cacheJacobian(
    4477             :     numeric_index_type i, numeric_index_type j, Real value, LocalDataKey, TagID tag)
    4478             : {
    4479   250173463 :   _cached_jacobian_rows[tag].push_back(i);
    4480   250173463 :   _cached_jacobian_cols[tag].push_back(j);
    4481   250173463 :   _cached_jacobian_values[tag].push_back(value);
    4482   250173463 : }
    4483             : 
    4484             : void
    4485   250113154 : Assembly::cacheJacobian(numeric_index_type i,
    4486             :                         numeric_index_type j,
    4487             :                         Real value,
    4488             :                         LocalDataKey,
    4489             :                         const std::set<TagID> & tags)
    4490             : {
    4491   517087385 :   for (auto tag : tags)
    4492   266974231 :     if (_sys.hasMatrix(tag))
    4493   250173463 :       cacheJacobian(i, j, value, LocalDataKey{}, tag);
    4494   250113154 : }
    4495             : 
    4496             : void
    4497      428690 : Assembly::setCachedJacobian(GlobalDataKey)
    4498             : {
    4499     1298744 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4500      870054 :     if (_sys.hasMatrix(tag))
    4501             :     {
    4502             :       // First zero the rows (including the diagonals) to prepare for
    4503             :       // setting the cached values.
    4504      430202 :       _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
    4505             : 
    4506             :       // TODO: Use SparseMatrix::set_values() for efficiency
    4507     9662781 :       for (MooseIndex(_cached_jacobian_values) i = 0; i < _cached_jacobian_values[tag].size(); ++i)
    4508    18465158 :         _sys.getMatrix(tag).set(_cached_jacobian_rows[tag][i],
    4509     9232579 :                                 _cached_jacobian_cols[tag][i],
    4510     9232579 :                                 _cached_jacobian_values[tag][i]);
    4511             :     }
    4512             : 
    4513      428690 :   clearCachedJacobian();
    4514      428690 : }
    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      428690 : Assembly::clearCachedJacobian()
    4528             : {
    4529     1298744 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4530             :   {
    4531      870054 :     _cached_jacobian_rows[tag].clear();
    4532      870054 :     _cached_jacobian_cols[tag].clear();
    4533      870054 :     _cached_jacobian_values[tag].clear();
    4534             :   }
    4535      428690 : }
    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         423 : Assembly::hasScalingVector()
    4580             : {
    4581         423 :   _scaling_vector = &_sys.getVector("scaling_factors");
    4582         423 : }
    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        1679 : Assembly::fePhi<VectorValue<Real>>(FEType type) const
    4597             : {
    4598        1679 :   buildVectorFE(type);
    4599        1679 :   return _vector_fe_shape_data[type]->_phi;
    4600             : }
    4601             : 
    4602             : template <>
    4603             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4604        1679 : Assembly::feGradPhi<VectorValue<Real>>(FEType type) const
    4605             : {
    4606        1679 :   buildVectorFE(type);
    4607        1679 :   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        3358 : Assembly::fePhiLower<VectorValue<Real>>(FEType type) const
    4622             : {
    4623        3358 :   buildVectorLowerDFE(type);
    4624        3358 :   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        3358 : Assembly::feGradPhiLower<VectorValue<Real>>(FEType type) const
    4638             : {
    4639        3358 :   buildVectorLowerDFE(type);
    4640        3358 :   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        1679 : Assembly::fePhiFace<VectorValue<Real>>(FEType type) const
    4654             : {
    4655        1679 :   buildVectorFaceFE(type);
    4656        1679 :   return _vector_fe_shape_data_face[type]->_phi;
    4657             : }
    4658             : 
    4659             : template <>
    4660             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4661        1679 : Assembly::feGradPhiFace<VectorValue<Real>>(FEType type) const
    4662             : {
    4663        1679 :   buildVectorFaceFE(type);
    4664        1679 :   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        1679 : Assembly::fePhiNeighbor<VectorValue<Real>>(FEType type) const
    4685             : {
    4686        1679 :   buildVectorNeighborFE(type);
    4687        1679 :   return _vector_fe_shape_data_neighbor[type]->_phi;
    4688             : }
    4689             : 
    4690             : template <>
    4691             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4692        1679 : Assembly::feGradPhiNeighbor<VectorValue<Real>>(FEType type) const
    4693             : {
    4694        1679 :   buildVectorNeighborFE(type);
    4695        1679 :   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        1679 : Assembly::fePhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4710             : {
    4711        1679 :   buildVectorFaceNeighborFE(type);
    4712        1679 :   return _vector_fe_shape_data_face_neighbor[type]->_phi;
    4713             : }
    4714             : 
    4715             : template <>
    4716             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4717        1679 : Assembly::feGradPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4718             : {
    4719        1679 :   buildVectorFaceNeighborFE(type);
    4720        1679 :   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       64382 : Assembly::feCurlPhi<VectorValue<Real>>(FEType type) const
    4735             : {
    4736       64382 :   _need_curl.insert(type);
    4737       64382 :   buildVectorFE(type);
    4738       64382 :   return _vector_fe_shape_data[type]->_curl_phi;
    4739             : }
    4740             : 
    4741             : template <>
    4742             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4743         224 : Assembly::feCurlPhiFace<VectorValue<Real>>(FEType type) const
    4744             : {
    4745         224 :   _need_curl.insert(type);
    4746         224 :   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         224 :   buildVectorFaceNeighborFE(type);
    4752             : 
    4753         224 :   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      527632 : Assembly::feDivPhi<VectorValue<Real>>(FEType type) const
    4778             : {
    4779      527632 :   _need_div.insert(type);
    4780      527632 :   buildVectorFE(type);
    4781      527632 :   return _vector_fe_shape_data[type]->_div_phi;
    4782             : }
    4783             : 
    4784             : template <>
    4785             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4786         336 : Assembly::feDivPhiFace<VectorValue<Real>>(FEType type) const
    4787             : {
    4788         336 :   _need_face_div.insert(type);
    4789         336 :   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         336 :   buildVectorFaceNeighborFE(type);
    4795             : 
    4796         336 :   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          28 : Assembly::adCurvatures() const
    4819             : {
    4820          28 :   _calculate_curvatures = true;
    4821          28 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
    4822          28 :   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          28 :   feSecondPhi<Real>(helper_type);
    4826          28 :   feSecondPhiFace<Real>(helper_type);
    4827          28 :   return _ad_curvatures;
    4828             : }
    4829             : 
    4830             : void
    4831       71595 : Assembly::helpersRequestData()
    4832             : {
    4833      278352 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
    4834             :   {
    4835      206757 :     _holder_fe_helper[dim]->get_phi();
    4836      206757 :     _holder_fe_helper[dim]->get_dphi();
    4837      206757 :     _holder_fe_helper[dim]->get_xyz();
    4838      206757 :     _holder_fe_helper[dim]->get_JxW();
    4839             : 
    4840      206757 :     _holder_fe_face_helper[dim]->get_phi();
    4841      206757 :     _holder_fe_face_helper[dim]->get_dphi();
    4842      206757 :     _holder_fe_face_helper[dim]->get_xyz();
    4843      206757 :     _holder_fe_face_helper[dim]->get_JxW();
    4844      206757 :     _holder_fe_face_helper[dim]->get_normals();
    4845             : 
    4846      206757 :     _holder_fe_face_neighbor_helper[dim]->get_xyz();
    4847      206757 :     _holder_fe_face_neighbor_helper[dim]->get_JxW();
    4848      206757 :     _holder_fe_face_neighbor_helper[dim]->get_normals();
    4849             : 
    4850      206757 :     _holder_fe_neighbor_helper[dim]->get_xyz();
    4851      206757 :     _holder_fe_neighbor_helper[dim]->get_JxW();
    4852             :   }
    4853             : 
    4854      206757 :   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      135162 :     _holder_fe_lower_helper[dim]->get_xyz();
    4859      135162 :     _holder_fe_lower_helper[dim]->get_JxW();
    4860             :   }
    4861       71595 : }
    4862             : 
    4863             : void
    4864         252 : Assembly::havePRefinement(const std::unordered_set<FEFamily> & disable_families)
    4865             : {
    4866         252 :   if (_have_p_refinement)
    4867             :     // Already performed tasks for p-refinement
    4868           0 :     return;
    4869             : 
    4870         252 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
    4871         252 :   const FEType helper_type(helper_order, LAGRANGE);
    4872             :   auto process_fe =
    4873       10752 :       [&disable_families](const unsigned int num_dimensionalities, auto & fe_container)
    4874             :   {
    4875        2520 :     if (!disable_families.empty())
    4876        8120 :       for (const auto dim : make_range(num_dimensionalities))
    4877             :       {
    4878        6020 :         auto fe_container_it = fe_container.find(dim);
    4879        6020 :         if (fe_container_it != fe_container.end())
    4880       12222 :           for (auto & [fe_type, fe_ptr] : fe_container_it->second)
    4881        8232 :             if (disable_families.count(fe_type.family))
    4882        2870 :               fe_ptr->add_p_level_in_reinit(false);
    4883             :       }
    4884        2772 :   };
    4885        1260 :   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        6146 :                                                            auto & fe_container)
    4890             :   {
    4891        1260 :     unique_helper_container.resize(num_dimensionalities);
    4892        4858 :     for (const auto dim : make_range(num_dimensionalities))
    4893             :     {
    4894        3598 :       auto & unique_helper = unique_helper_container[dim];
    4895        3598 :       unique_helper = FEGenericBase<Real>::build(dim, helper_type);
    4896             :       // don't participate in p-refinement
    4897        3598 :       unique_helper->add_p_level_in_reinit(false);
    4898        3598 :       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        3598 :       if (!user_added_helper_type)
    4904             :       {
    4905        2548 :         auto & fe_container_dim = libmesh_map_find(fe_container, dim);
    4906        2548 :         auto fe_it = fe_container_dim.find(helper_type);
    4907             :         mooseAssert(fe_it != fe_container_dim.end(), "We should have the helper type");
    4908        2548 :         delete fe_it->second;
    4909        2548 :         fe_container_dim.erase(fe_it);
    4910             :       }
    4911             :     }
    4912             : 
    4913        1260 :     process_fe(num_dimensionalities, fe_container);
    4914        1260 :   };
    4915             : 
    4916             :   // Handle scalar field families
    4917         252 :   process_fe_and_helpers(_unique_fe_helper,
    4918         252 :                          _holder_fe_helper,
    4919         252 :                          _mesh_dimension + 1,
    4920         252 :                          _user_added_fe_of_helper_type,
    4921         252 :                          _fe);
    4922         252 :   process_fe_and_helpers(_unique_fe_face_helper,
    4923         252 :                          _holder_fe_face_helper,
    4924         252 :                          _mesh_dimension + 1,
    4925         252 :                          _user_added_fe_face_of_helper_type,
    4926         252 :                          _fe_face);
    4927         252 :   process_fe_and_helpers(_unique_fe_face_neighbor_helper,
    4928         252 :                          _holder_fe_face_neighbor_helper,
    4929         252 :                          _mesh_dimension + 1,
    4930         252 :                          _user_added_fe_face_neighbor_of_helper_type,
    4931         252 :                          _fe_face_neighbor);
    4932         252 :   process_fe_and_helpers(_unique_fe_neighbor_helper,
    4933         252 :                          _holder_fe_neighbor_helper,
    4934         252 :                          _mesh_dimension + 1,
    4935         252 :                          _user_added_fe_neighbor_of_helper_type,
    4936         252 :                          _fe_neighbor);
    4937         252 :   process_fe_and_helpers(_unique_fe_lower_helper,
    4938         252 :                          _holder_fe_lower_helper,
    4939             :                          _mesh_dimension,
    4940         252 :                          _user_added_fe_lower_of_helper_type,
    4941         252 :                          _fe_lower);
    4942             :   // Handle vector field families
    4943         252 :   process_fe(_mesh_dimension + 1, _vector_fe);
    4944         252 :   process_fe(_mesh_dimension + 1, _vector_fe_face);
    4945         252 :   process_fe(_mesh_dimension + 1, _vector_fe_neighbor);
    4946         252 :   process_fe(_mesh_dimension + 1, _vector_fe_face_neighbor);
    4947         252 :   process_fe(_mesh_dimension, _vector_fe_lower);
    4948             : 
    4949         252 :   helpersRequestData();
    4950             : 
    4951         252 :   _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          25 : Assembly::genericQPoints<false>() const
    4978             : {
    4979          25 :   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