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

Generated by: LCOV version 1.14