LCOV - code coverage report
Current view: top level - src/base - Assembly.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: fef103 Lines: 2214 2765 80.1 %
Date: 2025-09-03 20:01:23 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  2043039289 : coordTransformFactor(const SubProblem & s,
      42             :                      const SubdomainID sub_id,
      43             :                      const P & point,
      44             :                      C & factor,
      45             :                      const SubdomainID neighbor_sub_id)
      46             : {
      47  2043039289 :   coordTransformFactor(s.mesh(), sub_id, point, factor, neighbor_sub_id);
      48  2043039289 : }
      49             : 
      50             : template <typename P, typename C>
      51             : void
      52  2046485381 : 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  2046485381 :   const auto coord_type = mesh.getCoordSystem(sub_id);
      63             : 
      64  2046485381 :   if (coord_type == Moose::COORD_RZ)
      65             :   {
      66     4107324 :     if (mesh.usingGeneralAxisymmetricCoordAxes())
      67             :     {
      68     1212256 :       const auto & axis = mesh.getGeneralAxisymmetricCoordAxis(sub_id);
      69     1212256 :       MooseMeshUtils::coordTransformFactorRZGeneral(point, axis, factor);
      70             :     }
      71             :     else
      72     2895068 :       MooseMeshUtils::coordTransformFactor(
      73             :           point, factor, coord_type, mesh.getAxisymmetricRadialCoord());
      74             :   }
      75             :   else
      76  2042378057 :     MooseMeshUtils::coordTransformFactor(point, factor, coord_type, libMesh::invalid_uint);
      77  2046485381 : }
      78             : 
      79       72190 : Assembly::Assembly(SystemBase & sys, THREAD_ID tid)
      80       72190 :   : _sys(sys),
      81      144380 :     _subproblem(_sys.subproblem()),
      82       72190 :     _displaced(dynamic_cast<DisplacedSystem *>(&sys) ? true : false),
      83       72190 :     _nonlocal_cm(_subproblem.nonlocalCouplingMatrix(_sys.number())),
      84       72190 :     _computing_residual(_subproblem.currentlyComputingResidual()),
      85       72190 :     _computing_jacobian(_subproblem.currentlyComputingJacobian()),
      86       72190 :     _computing_residual_and_jacobian(_subproblem.currentlyComputingResidualAndJacobian()),
      87       72190 :     _dof_map(_sys.dofMap()),
      88       72190 :     _tid(tid),
      89       72190 :     _mesh(sys.mesh()),
      90       72190 :     _mesh_dimension(_mesh.dimension()),
      91       72190 :     _helper_type(_mesh.hasSecondOrderElements() ? SECOND : FIRST, LAGRANGE),
      92       72190 :     _user_added_fe_of_helper_type(false),
      93       72190 :     _user_added_fe_face_of_helper_type(false),
      94       72190 :     _user_added_fe_face_neighbor_of_helper_type(false),
      95       72190 :     _user_added_fe_neighbor_of_helper_type(false),
      96       72190 :     _user_added_fe_lower_of_helper_type(false),
      97       72190 :     _building_helpers(false),
      98       72190 :     _current_qrule(nullptr),
      99       72190 :     _current_qrule_volume(nullptr),
     100       72190 :     _current_qrule_arbitrary(nullptr),
     101       72190 :     _coord_type(Moose::COORD_XYZ),
     102       72190 :     _current_qrule_face(nullptr),
     103       72190 :     _current_qface_arbitrary(nullptr),
     104       72190 :     _current_qrule_neighbor(nullptr),
     105       72190 :     _need_JxW_neighbor(false),
     106       72190 :     _qrule_msm(nullptr),
     107       72190 :     _custom_mortar_qrule(false),
     108       72190 :     _current_qrule_lower(nullptr),
     109             : 
     110       72190 :     _current_elem(nullptr),
     111       72190 :     _current_elem_volume(0),
     112       72190 :     _current_side(0),
     113       72190 :     _current_side_elem(nullptr),
     114       72190 :     _current_side_volume(0),
     115       72190 :     _current_neighbor_elem(nullptr),
     116       72190 :     _current_neighbor_side(0),
     117       72190 :     _current_neighbor_side_elem(nullptr),
     118       72190 :     _need_neighbor_elem_volume(false),
     119       72190 :     _current_neighbor_volume(0),
     120       72190 :     _current_node(nullptr),
     121       72190 :     _current_neighbor_node(nullptr),
     122       72190 :     _current_elem_volume_computed(false),
     123       72190 :     _current_side_volume_computed(false),
     124             : 
     125       72190 :     _current_lower_d_elem(nullptr),
     126       72190 :     _current_neighbor_lower_d_elem(nullptr),
     127       72190 :     _need_lower_d_elem_volume(false),
     128       72190 :     _need_neighbor_lower_d_elem_volume(false),
     129       72190 :     _need_dual(false),
     130             : 
     131       72190 :     _residual_vector_tags(_subproblem.getVectorTags(Moose::VECTOR_TAG_RESIDUAL)),
     132      144380 :     _cached_residual_values(2), // The 2 is for TIME and NONTIME
     133      144380 :     _cached_residual_rows(2),   // The 2 is for TIME and NONTIME
     134       72190 :     _max_cached_residuals(0),
     135       72190 :     _max_cached_jacobians(0),
     136             : 
     137       72190 :     _block_diagonal_matrix(false),
     138       72190 :     _calculate_xyz(false),
     139       72190 :     _calculate_face_xyz(false),
     140       72190 :     _calculate_curvatures(false),
     141       72190 :     _calculate_ad_coord(false),
     142      288760 :     _have_p_refinement(false)
     143             : {
     144       72190 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
     145       72190 :   _building_helpers = true;
     146             :   // Build fe's for the helpers
     147       72190 :   buildFE(FEType(helper_order, LAGRANGE));
     148       72190 :   buildFaceFE(FEType(helper_order, LAGRANGE));
     149       72190 :   buildNeighborFE(FEType(helper_order, LAGRANGE));
     150       72190 :   buildFaceNeighborFE(FEType(helper_order, LAGRANGE));
     151       72190 :   buildLowerDFE(FEType(helper_order, LAGRANGE));
     152       72190 :   _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      280581 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     157             :   {
     158      208391 :     _holder_fe_helper[dim] = _fe[dim][FEType(helper_order, LAGRANGE)];
     159      208391 :     _holder_fe_face_helper[dim] = _fe_face[dim][FEType(helper_order, LAGRANGE)];
     160      208391 :     _holder_fe_face_neighbor_helper[dim] = _fe_face_neighbor[dim][FEType(helper_order, LAGRANGE)];
     161      208391 :     _holder_fe_neighbor_helper[dim] = _fe_neighbor[dim][FEType(helper_order, LAGRANGE)];
     162             :   }
     163             : 
     164      208391 :   for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
     165      136201 :     _holder_fe_lower_helper[dim] = _fe_lower[dim][FEType(helper_order, LAGRANGE)];
     166             : 
     167             :   // request phi, dphi, xyz, JxW, etc. data
     168       72190 :   helpersRequestData();
     169             : 
     170             :   // For 3D mortar, mortar segments are always TRI3 elements so we want FIRST LAGRANGE regardless
     171             :   // of discretization
     172       72190 :   _fe_msm = (_mesh_dimension == 2)
     173      144380 :                 ? FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(helper_order, LAGRANGE))
     174       72190 :                 : FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(FIRST, LAGRANGE));
     175             :   // This FE object should not take part in p-refinement
     176       72190 :   _fe_msm->add_p_level_in_reinit(false);
     177       72190 :   _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       72190 :   _fe_msm->get_xyz();
     181             : 
     182       72190 :   _extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
     183       72190 :   _neighbor_extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
     184       72190 : }
     185             : 
     186      133414 : Assembly::~Assembly()
     187             : {
     188      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     189      474744 :     for (auto & it : _fe[dim])
     190      281536 :       delete it.second;
     191             : 
     192      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     193      474744 :     for (auto & it : _fe_face[dim])
     194      281536 :       delete it.second;
     195             : 
     196      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     197      474744 :     for (auto & it : _fe_neighbor[dim])
     198      281536 :       delete it.second;
     199             : 
     200      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     201      474744 :     for (auto & it : _fe_face_neighbor[dim])
     202      281536 :       delete it.second;
     203             : 
     204      193208 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     205      303722 :     for (auto & it : _fe_lower[dim])
     206      177221 :       delete it.second;
     207             : 
     208      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     209      196420 :     for (auto & it : _vector_fe[dim])
     210        3212 :       delete it.second;
     211             : 
     212      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     213      196420 :     for (auto & it : _vector_fe_face[dim])
     214        3212 :       delete it.second;
     215             : 
     216      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     217      196420 :     for (auto & it : _vector_fe_neighbor[dim])
     218        3212 :       delete it.second;
     219             : 
     220      259915 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     221      196420 :     for (auto & it : _vector_fe_face_neighbor[dim])
     222        3212 :       delete it.second;
     223             : 
     224      193208 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     225      128168 :     for (auto & it : _vector_fe_lower[dim])
     226        1667 :       delete it.second;
     227             : 
     228      149811 :   for (auto & it : _ad_grad_phi_data)
     229       83104 :     it.second.release();
     230             : 
     231       67992 :   for (auto & it : _ad_vector_grad_phi_data)
     232        1285 :     it.second.release();
     233             : 
     234      143472 :   for (auto & it : _ad_grad_phi_data_face)
     235       76765 :     it.second.release();
     236             : 
     237       67992 :   for (auto & it : _ad_vector_grad_phi_data_face)
     238        1285 :     it.second.release();
     239             : 
     240       66707 :   _current_physical_points.release();
     241             : 
     242       66707 :   _coord.release();
     243       66707 :   _coord_neighbor.release();
     244       66707 :   _coord_msm.release();
     245             : 
     246       66707 :   _ad_JxW.release();
     247       66707 :   _ad_q_points.release();
     248       66707 :   _ad_JxW_face.release();
     249       66707 :   _ad_normals.release();
     250       66707 :   _ad_q_points_face.release();
     251       66707 :   _curvatures.release();
     252       66707 :   _ad_curvatures.release();
     253       66707 :   _ad_coord.release();
     254             : 
     255       66707 :   delete _qrule_msm;
     256      133414 : }
     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      476340 : Assembly::buildFE(FEType type) const
     267             : {
     268      476340 :   if (!_building_helpers && type == _helper_type)
     269      211935 :     _user_added_fe_of_helper_type = true;
     270             : 
     271      476340 :   if (!_fe_shape_data[type])
     272      103739 :     _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     1902825 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     276             :   {
     277     1426485 :     if (!_fe[dim][type])
     278      301870 :       _fe[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     279             : 
     280     1426485 :     _fe[dim][type]->get_phi();
     281     1426485 :     _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     1426485 :     _fe[dim][type]->get_xyz();
     286     1426485 :     if (_need_second_derivative.count(type))
     287       87752 :       _fe[dim][type]->get_d2phi();
     288             :   }
     289      476340 : }
     290             : 
     291             : void
     292      448384 : Assembly::buildFaceFE(FEType type) const
     293             : {
     294      448384 :   if (!_building_helpers && type == _helper_type)
     295      206267 :     _user_added_fe_face_of_helper_type = true;
     296             : 
     297      448384 :   if (!_fe_shape_data_face[type])
     298      103739 :     _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     1790937 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     302             :   {
     303     1342553 :     if (!_fe_face[dim][type])
     304      301870 :       _fe_face[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     305             : 
     306     1342553 :     _fe_face[dim][type]->get_phi();
     307     1342553 :     _fe_face[dim][type]->get_dphi();
     308     1342553 :     if (_need_second_derivative.count(type))
     309       18884 :       _fe_face[dim][type]->get_d2phi();
     310             :   }
     311      448384 : }
     312             : 
     313             : void
     314      442136 : Assembly::buildNeighborFE(FEType type) const
     315             : {
     316      442136 :   if (!_building_helpers && type == _helper_type)
     317      206146 :     _user_added_fe_neighbor_of_helper_type = true;
     318             : 
     319      442136 :   if (!_fe_shape_data_neighbor[type])
     320      103739 :     _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     1765931 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     324             :   {
     325     1323795 :     if (!_fe_neighbor[dim][type])
     326      301870 :       _fe_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     327             : 
     328     1323795 :     _fe_neighbor[dim][type]->get_phi();
     329     1323795 :     _fe_neighbor[dim][type]->get_dphi();
     330     1323795 :     if (_need_second_derivative_neighbor.count(type))
     331         126 :       _fe_neighbor[dim][type]->get_d2phi();
     332             :   }
     333      442136 : }
     334             : 
     335             : void
     336      442136 : Assembly::buildFaceNeighborFE(FEType type) const
     337             : {
     338      442136 :   if (!_building_helpers && type == _helper_type)
     339      206146 :     _user_added_fe_face_neighbor_of_helper_type = true;
     340             : 
     341      442136 :   if (!_fe_shape_data_face_neighbor[type])
     342      103739 :     _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     1765931 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
     346             :   {
     347     1323795 :     if (!_fe_face_neighbor[dim][type])
     348      301870 :       _fe_face_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     349             : 
     350     1323795 :     _fe_face_neighbor[dim][type]->get_phi();
     351     1323795 :     _fe_face_neighbor[dim][type]->get_dphi();
     352     1323795 :     if (_need_second_derivative_neighbor.count(type))
     353         126 :       _fe_face_neighbor[dim][type]->get_d2phi();
     354             :   }
     355      442136 : }
     356             : 
     357             : void
     358      778150 : Assembly::buildLowerDFE(FEType type) const
     359             : {
     360      778150 :   if (!_building_helpers && type == _helper_type)
     361      411708 :     _user_added_fe_lower_of_helper_type = true;
     362             : 
     363      778150 :   if (!_fe_shape_data_lower[type])
     364       98459 :     _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     2353143 :   for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
     370             :   {
     371     1574993 :     if (!_fe_lower[dim][type])
     372      190094 :       _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
     373             : 
     374     1574993 :     _fe_lower[dim][type]->get_phi();
     375     1574993 :     _fe_lower[dim][type]->get_dphi();
     376     1574993 :     if (_need_second_derivative.count(type))
     377           0 :       _fe_lower[dim][type]->get_d2phi();
     378             :   }
     379      778150 : }
     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        6664 : Assembly::buildVectorLowerDFE(FEType type) const
     404             : {
     405        6664 :   if (!_vector_fe_shape_data_lower[type])
     406        1335 :     _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        6664 :   unsigned int dim = ((type.family == LAGRANGE_VEC) || (type.family == MONOMIAL_VEC)) ? 0 : 2;
     412        6664 :   const auto ending_dim = cast_int<unsigned int>(_mesh_dimension - 1);
     413        6664 :   if (ending_dim < dim)
     414        1796 :     return;
     415       14444 :   for (; dim <= ending_dim; dim++)
     416             :   {
     417        9576 :     if (!_vector_fe_lower[dim][type])
     418        1782 :       _vector_fe_lower[dim][type] = FEVectorBase::build(dim, type).release();
     419             : 
     420        9576 :     _vector_fe_lower[dim][type]->get_phi();
     421        9576 :     _vector_fe_lower[dim][type]->get_dphi();
     422        9576 :     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      595346 : Assembly::buildVectorFE(const FEType type) const
     454             : {
     455      595346 :   if (!_vector_fe_shape_data[type])
     456        1335 :     _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      595346 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     461        3124 :       type.family == L2_RAVIART_THOMAS)
     462      592530 :     min_dim = 2;
     463             :   else
     464        2816 :     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     1709818 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     469             :   {
     470     1114472 :     if (!_vector_fe[dim][type])
     471        3377 :       _vector_fe[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     472             : 
     473     1114472 :     _vector_fe[dim][type]->get_phi();
     474     1114472 :     _vector_fe[dim][type]->get_dphi();
     475     1114472 :     if (_need_curl.count(type))
     476       71860 :       _vector_fe[dim][type]->get_curl_phi();
     477     1114472 :     if (_need_div.count(type))
     478     1033972 :       _vector_fe[dim][type]->get_div_phi();
     479     1114472 :     _vector_fe[dim][type]->get_xyz();
     480             :   }
     481      595346 : }
     482             : 
     483             : void
     484        3892 : Assembly::buildVectorFaceFE(const FEType type) const
     485             : {
     486        3892 :   if (!_vector_fe_shape_data_face[type])
     487        1335 :     _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        3892 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     492        2604 :       type.family == L2_RAVIART_THOMAS)
     493        1442 :     min_dim = 2;
     494             :   else
     495        2450 :     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       13284 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     500             :   {
     501        9392 :     if (!_vector_fe_face[dim][type])
     502        3377 :       _vector_fe_face[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     503             : 
     504        9392 :     _vector_fe_face[dim][type]->get_phi();
     505        9392 :     _vector_fe_face[dim][type]->get_dphi();
     506        9392 :     if (_need_curl.count(type))
     507         304 :       _vector_fe_face[dim][type]->get_curl_phi();
     508        9392 :     if (_need_face_div.count(type))
     509         448 :       _vector_fe_face[dim][type]->get_div_phi();
     510             :   }
     511        3892 : }
     512             : 
     513             : void
     514        3332 : Assembly::buildVectorNeighborFE(const FEType type) const
     515             : {
     516        3332 :   if (!_vector_fe_shape_data_neighbor[type])
     517        1335 :     _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        3332 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     522        2604 :       type.family == L2_RAVIART_THOMAS)
     523         882 :     min_dim = 2;
     524             :   else
     525        2450 :     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       11972 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     530             :   {
     531        8640 :     if (!_vector_fe_neighbor[dim][type])
     532        3377 :       _vector_fe_neighbor[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     533             : 
     534        8640 :     _vector_fe_neighbor[dim][type]->get_phi();
     535        8640 :     _vector_fe_neighbor[dim][type]->get_dphi();
     536        8640 :     if (_need_curl.count(type))
     537           0 :       _vector_fe_neighbor[dim][type]->get_curl_phi();
     538        8640 :     if (_need_neighbor_div.count(type))
     539           0 :       _vector_fe_neighbor[dim][type]->get_div_phi();
     540             :   }
     541        3332 : }
     542             : 
     543             : void
     544        3892 : Assembly::buildVectorFaceNeighborFE(const FEType type) const
     545             : {
     546        3892 :   if (!_vector_fe_shape_data_face_neighbor[type])
     547        1335 :     _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        3892 :   if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
     552        2604 :       type.family == L2_RAVIART_THOMAS)
     553        1442 :     min_dim = 2;
     554             :   else
     555        2450 :     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       13284 :   for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
     560             :   {
     561        9392 :     if (!_vector_fe_face_neighbor[dim][type])
     562        3377 :       _vector_fe_face_neighbor[dim][type] =
     563        6754 :           FEGenericBase<VectorValue<Real>>::build(dim, type).release();
     564             : 
     565        9392 :     _vector_fe_face_neighbor[dim][type]->get_phi();
     566        9392 :     _vector_fe_face_neighbor[dim][type]->get_dphi();
     567        9392 :     if (_need_curl.count(type))
     568         304 :       _vector_fe_face_neighbor[dim][type]->get_curl_phi();
     569        9392 :     if (_need_face_neighbor_div.count(type))
     570           0 :       _vector_fe_face_neighbor[dim][type]->get_div_phi();
     571             :   }
     572        3892 : }
     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       71800 : 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       71800 :   auto & qvec = _qrules[block];
     625       71800 :   unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
     626       71800 :   if (qvec.size() != ndims)
     627       71800 :     qvec.resize(ndims);
     628             : 
     629      279025 :   for (unsigned int i = 0; i < qvec.size(); i++)
     630             :   {
     631      207225 :     int dim = i;
     632      207225 :     auto & q = qvec[dim];
     633      207225 :     q.vol = QBase::build(type, dim, volume_order);
     634      207225 :     q.vol->allow_rules_with_negative_weights = allow_negative_qweights;
     635      207225 :     q.face = QBase::build(type, dim - 1, face_order);
     636      207225 :     q.face->allow_rules_with_negative_weights = allow_negative_qweights;
     637      207225 :     q.fv_face = QBase::build(QMONOMIAL, dim - 1, CONSTANT);
     638      207225 :     q.fv_face->allow_rules_with_negative_weights = allow_negative_qweights;
     639      207225 :     q.neighbor = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
     640      207225 :     q.neighbor->allow_rules_with_negative_weights = allow_negative_qweights;
     641      207225 :     q.arbitrary_vol = std::make_unique<ArbitraryQuadrature>(dim, order);
     642      207225 :     q.arbitrary_vol->allow_rules_with_negative_weights = allow_negative_qweights;
     643      207225 :     q.arbitrary_face = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
     644      207225 :     q.arbitrary_face->allow_rules_with_negative_weights = allow_negative_qweights;
     645             :   }
     646             : 
     647       71800 :   delete _qrule_msm;
     648       71800 :   _custom_mortar_qrule = false;
     649       71800 :   _qrule_msm = QBase::build(type, _mesh_dimension - 1, face_order).release();
     650       71800 :   _qrule_msm->allow_rules_with_negative_weights = allow_negative_qweights;
     651       71800 :   _fe_msm->attach_quadrature_rule(_qrule_msm);
     652       71800 : }
     653             : 
     654             : void
     655      246395 : Assembly::setVolumeQRule(QBase * qrule, unsigned int dim)
     656             : {
     657      246395 :   _current_qrule = qrule;
     658             : 
     659      246395 :   if (qrule) // Don't set a NULL qrule
     660             :   {
     661      596773 :     for (auto & it : _fe[dim])
     662      350378 :       it.second->attach_quadrature_rule(qrule);
     663      250658 :     for (auto & it : _vector_fe[dim])
     664        4263 :       it.second->attach_quadrature_rule(qrule);
     665      246395 :     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      246395 : }
     672             : 
     673             : void
     674      610519 : Assembly::setFaceQRule(QBase * qrule, unsigned int dim)
     675             : {
     676      610519 :   _current_qrule_face = qrule;
     677             : 
     678     1437277 :   for (auto & it : _fe_face[dim])
     679      826758 :     it.second->attach_quadrature_rule(qrule);
     680      611180 :   for (auto & it : _vector_fe_face[dim])
     681         661 :     it.second->attach_quadrature_rule(qrule);
     682      610519 :   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      610519 : }
     688             : 
     689             : void
     690      284852 : Assembly::setLowerQRule(QBase * qrule, unsigned int dim)
     691             : {
     692             :   // The lower-dimensional quadrature rule matches the face quadrature rule
     693      284852 :   setFaceQRule(qrule, dim);
     694             : 
     695      284852 :   _current_qrule_lower = qrule;
     696             : 
     697      662169 :   for (auto & it : _fe_lower[dim])
     698      377317 :     it.second->attach_quadrature_rule(qrule);
     699      284852 :   for (auto & it : _vector_fe_lower[dim])
     700           0 :     it.second->attach_quadrature_rule(qrule);
     701      284852 :   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      284852 : }
     707             : 
     708             : void
     709    29130469 : Assembly::setNeighborQRule(QBase * qrule, unsigned int dim)
     710             : {
     711    29130469 :   _current_qrule_neighbor = qrule;
     712             : 
     713    86915698 :   for (auto & it : _fe_face_neighbor[dim])
     714    57785229 :     it.second->attach_quadrature_rule(qrule);
     715    29159032 :   for (auto & it : _vector_fe_face_neighbor[dim])
     716       28563 :     it.second->attach_quadrature_rule(qrule);
     717    29130469 :   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    29130469 : }
     724             : 
     725             : void
     726       68038 : Assembly::clearCachedQRules()
     727             : {
     728       68038 :   _current_qrule = nullptr;
     729       68038 :   _current_qrule_face = nullptr;
     730       68038 :   _current_qrule_lower = nullptr;
     731       68038 :   _current_qrule_neighbor = nullptr;
     732       68038 : }
     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   440914360 : Assembly::reinitFE(const Elem * elem)
     761             : {
     762   440914360 :   unsigned int dim = elem->dim();
     763             : 
     764   993513571 :   for (const auto & it : _fe[dim])
     765             :   {
     766   552599239 :     FEBase & fe = *it.second;
     767   552599239 :     const FEType & fe_type = it.first;
     768             : 
     769   552599239 :     _current_fe[fe_type] = &fe;
     770             : 
     771   552599239 :     FEShapeData & fesd = *_fe_shape_data[fe_type];
     772             : 
     773   552599239 :     fe.reinit(elem);
     774             : 
     775   552599211 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_phi()));
     776   552599211 :     fesd._grad_phi.shallowCopy(
     777   552599211 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_dphi()));
     778   552599211 :     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   446802251 :   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   440914332 :   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   440914332 :   _current_q_points.shallowCopy(
     814   440914332 :       const_cast<std::vector<Point> &>(_holder_fe_helper[dim]->get_xyz()));
     815   440914332 :   _current_JxW.shallowCopy(const_cast<std::vector<Real> &>(_holder_fe_helper[dim]->get_JxW()));
     816             : 
     817   440914332 :   if (_subproblem.haveADObjects())
     818             :   {
     819    35348109 :     auto n_qp = _current_qrule->n_points();
     820    35348109 :     resizeADMappingObjects(n_qp, dim);
     821    35348109 :     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   113295120 :       for (unsigned qp = 0; qp < n_qp; ++qp)
     830    78556883 :         _ad_JxW[qp] = _current_JxW[qp];
     831    34738237 :       if (_calculate_xyz)
     832    62990068 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     833    49971126 :           _ad_q_points[qp] = _current_q_points[qp];
     834             :     }
     835             : 
     836    95199407 :     for (const auto & it : _fe[dim])
     837             :     {
     838    59851298 :       FEBase & fe = *it.second;
     839    59851298 :       auto fe_type = it.first;
     840    59851298 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
     841    59851298 :       auto & grad_phi = _ad_grad_phi_data[fe_type];
     842             : 
     843    59851298 :       grad_phi.resize(num_shapes);
     844   232713321 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     845   172862023 :         grad_phi[i].resize(n_qp);
     846             : 
     847    59851298 :       if (_displaced)
     848      939668 :         computeGradPhiAD(elem, n_qp, grad_phi, &fe);
     849             :       else
     850             :       {
     851    58911630 :         const auto & regular_grad_phi = _fe_shape_data[fe_type]->_grad_phi;
     852   228497687 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     853   707421710 :           for (unsigned qp = 0; qp < n_qp; ++qp)
     854   537835653 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
     855             :       }
     856             :     }
     857    38545774 :     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   440914332 :   auto n = numExtraElemIntegers();
     881   443950877 :   for (auto i : make_range(n))
     882     3036545 :     _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
     883   440914332 :   _extra_elem_ids[n] = _current_elem->subdomain_id();
     884             : 
     885   440914332 :   if (_xfem != nullptr)
     886           0 :     modifyWeightsDueToXFEM(elem);
     887   440914332 : }
     888             : 
     889             : template <typename OutputType>
     890             : void
     891     1087016 : 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     1087016 :   auto dim = elem->dim();
     908     1087016 :   const auto & dphidxi = fe->get_dphidxi();
     909     1087016 :   const auto & dphideta = fe->get_dphideta();
     910     1087016 :   const auto & dphidzeta = fe->get_dphidzeta();
     911     1087016 :   auto num_shapes = grad_phi.size();
     912             : 
     913     1087016 :   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     1025482 :     case 2:
     936             :     {
     937     4968659 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
     938    22924350 :         for (unsigned qp = 0; qp < n_qp; ++qp)
     939             :         {
     940    37962346 :           grad_phi[i][qp].slice(0) =
     941    37962346 :               dphidxi[i][qp] * _ad_dxidx_map[qp] + dphideta[i][qp] * _ad_detadx_map[qp];
     942    37962346 :           grad_phi[i][qp].slice(1) =
     943    37962346 :               dphidxi[i][qp] * _ad_dxidy_map[qp] + dphideta[i][qp] * _ad_detady_map[qp];
     944    37962346 :           grad_phi[i][qp].slice(2) =
     945    37962346 :               dphidxi[i][qp] * _ad_dxidz_map[qp] + dphideta[i][qp] * _ad_detadz_map[qp];
     946             :         }
     947     1025482 :       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     1087016 : }
     969             : 
     970             : void
     971    39530042 : Assembly::resizeADMappingObjects(unsigned int n_qp, unsigned int dim)
     972             : {
     973    39530042 :   _ad_dxyzdxi_map.resize(n_qp);
     974    39530042 :   _ad_dxidx_map.resize(n_qp);
     975    39530042 :   _ad_dxidy_map.resize(n_qp); // 1D element may live in 2D ...
     976    39530042 :   _ad_dxidz_map.resize(n_qp); // ... or 3D
     977             : 
     978    39530042 :   if (dim > 1)
     979             :   {
     980    24251879 :     _ad_dxyzdeta_map.resize(n_qp);
     981    24251879 :     _ad_detadx_map.resize(n_qp);
     982    24251879 :     _ad_detady_map.resize(n_qp);
     983    24251879 :     _ad_detadz_map.resize(n_qp);
     984             : 
     985    24251879 :     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    39530042 :   _ad_jac.resize(n_qp);
     995    39530042 :   _ad_JxW.resize(n_qp);
     996    39530042 :   if (_calculate_xyz)
     997    17110378 :     _ad_q_points.resize(n_qp);
     998    39530042 : }
     999             : 
    1000             : void
    1001     2859619 : 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     2859619 :   auto dim = elem->dim();
    1044     2859619 :   const auto & elem_nodes = elem->get_nodes();
    1045     2859619 :   auto num_shapes = FEInterface::n_shape_functions(fe->get_fe_type(), elem);
    1046     2859619 :   const auto & phi_map = fe->get_fe_map().get_phi_map();
    1047     2859619 :   const auto & dphidxi_map = fe->get_fe_map().get_dphidxi_map();
    1048     2859619 :   const auto & dphideta_map = fe->get_fe_map().get_dphideta_map();
    1049     2859619 :   const auto & dphidzeta_map = fe->get_fe_map().get_dphidzeta_map();
    1050     2859619 :   const auto sys_num = _sys.number();
    1051             :   const bool do_derivatives =
    1052     2859619 :       ADReal::do_derivatives && _sys.number() == _subproblem.currentNlSysNum();
    1053             : 
    1054     2859619 :   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     2786415 :     case 2:
    1116             :     {
    1117     2786415 :       if (_calculate_xyz)
    1118     1923033 :         _ad_q_points[p].zero();
    1119     2786415 :       _ad_dxyzdxi_map[p].zero();
    1120     2786415 :       _ad_dxyzdeta_map[p].zero();
    1121             : 
    1122    17093994 :       for (std::size_t i = 0; i < num_shapes; i++)
    1123             :       {
    1124             :         libmesh_assert(elem_nodes[i]);
    1125    14307579 :         const Node & node = *elem_nodes[i];
    1126    14307579 :         libMesh::VectorValue<ADReal> elem_point = node;
    1127    14307579 :         if (do_derivatives)
    1128     1887293 :           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    14307579 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1134    14307579 :         _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
    1135             : 
    1136    14307579 :         if (_calculate_xyz)
    1137    11336097 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1138    14307579 :       }
    1139             : 
    1140     2786415 :       const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dx_deta = _ad_dxyzdeta_map[p](0),
    1141     2786415 :                  &dy_dxi = _ad_dxyzdxi_map[p](1), &dy_deta = _ad_dxyzdeta_map[p](1),
    1142     2786415 :                  &dz_dxi = _ad_dxyzdxi_map[p](2), &dz_deta = _ad_dxyzdeta_map[p](2);
    1143             : 
    1144     2786415 :       const auto g11 = (dx_dxi * dx_dxi + dy_dxi * dy_dxi + dz_dxi * dz_dxi);
    1145             : 
    1146     2786415 :       const auto g12 = (dx_dxi * dx_deta + dy_dxi * dy_deta + dz_dxi * dz_deta);
    1147             : 
    1148     2786415 :       const auto & g21 = g12;
    1149             : 
    1150     2786415 :       const auto g22 = (dx_deta * dx_deta + dy_deta * dy_deta + dz_deta * dz_deta);
    1151             : 
    1152     2786415 :       auto det = (g11 * g22 - g12 * g21);
    1153             : 
    1154     2786415 :       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     2786415 :       else if (det.value() <= 0.)
    1168           0 :         det.value() = TOLERANCE * TOLERANCE;
    1169             : 
    1170     2786415 :       const auto inv_det = 1. / det;
    1171     2786415 :       _ad_jac[p] = std::sqrt(det);
    1172             : 
    1173     2786415 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1174             : 
    1175     2786415 :       const auto g11inv = g22 * inv_det;
    1176     2786415 :       const auto g12inv = -g12 * inv_det;
    1177     2786415 :       const auto g21inv = -g21 * inv_det;
    1178     2786415 :       const auto g22inv = g11 * inv_det;
    1179             : 
    1180     2786415 :       _ad_dxidx_map[p] = g11inv * dx_dxi + g12inv * dx_deta;
    1181     2786415 :       _ad_dxidy_map[p] = g11inv * dy_dxi + g12inv * dy_deta;
    1182     2786415 :       _ad_dxidz_map[p] = g11inv * dz_dxi + g12inv * dz_deta;
    1183             : 
    1184     2786415 :       _ad_detadx_map[p] = g21inv * dx_dxi + g22inv * dx_deta;
    1185     2786415 :       _ad_detady_map[p] = g21inv * dy_dxi + g22inv * dy_deta;
    1186     2786415 :       _ad_detadz_map[p] = g21inv * dz_dxi + g22inv * dz_deta;
    1187             : 
    1188     2786415 :       break;
    1189    13932075 :     }
    1190             : 
    1191           0 :     case 3:
    1192             :     {
    1193           0 :       if (_calculate_xyz)
    1194           0 :         _ad_q_points[p].zero();
    1195           0 :       _ad_dxyzdxi_map[p].zero();
    1196           0 :       _ad_dxyzdeta_map[p].zero();
    1197           0 :       _ad_dxyzdzeta_map[p].zero();
    1198             : 
    1199           0 :       for (std::size_t i = 0; i < num_shapes; i++)
    1200             :       {
    1201             :         libmesh_assert(elem_nodes[i]);
    1202           0 :         const Node & node = *elem_nodes[i];
    1203           0 :         libMesh::VectorValue<ADReal> elem_point = node;
    1204           0 :         if (do_derivatives)
    1205           0 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1206           0 :             if (node.n_dofs(sys_num, disp_num))
    1207           0 :               Moose::derivInsert(
    1208           0 :                   elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1209             : 
    1210           0 :         _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
    1211           0 :         _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
    1212           0 :         _ad_dxyzdzeta_map[p].add_scaled(elem_point, dphidzeta_map[i][p]);
    1213             : 
    1214           0 :         if (_calculate_xyz)
    1215           0 :           _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
    1216           0 :       }
    1217             : 
    1218           0 :       const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dy_dxi = _ad_dxyzdxi_map[p](1),
    1219           0 :                  &dz_dxi = _ad_dxyzdxi_map[p](2), &dx_deta = _ad_dxyzdeta_map[p](0),
    1220           0 :                  &dy_deta = _ad_dxyzdeta_map[p](1), &dz_deta = _ad_dxyzdeta_map[p](2),
    1221           0 :                  &dx_dzeta = _ad_dxyzdzeta_map[p](0), &dy_dzeta = _ad_dxyzdzeta_map[p](1),
    1222           0 :                  &dz_dzeta = _ad_dxyzdzeta_map[p](2);
    1223             : 
    1224           0 :       _ad_jac[p] = (dx_dxi * (dy_deta * dz_dzeta - dz_deta * dy_dzeta) +
    1225           0 :                     dy_dxi * (dz_deta * dx_dzeta - dx_deta * dz_dzeta) +
    1226           0 :                     dz_dxi * (dx_deta * dy_dzeta - dy_deta * dx_dzeta));
    1227             : 
    1228           0 :       if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
    1229             :       {
    1230             :         static bool failing = false;
    1231           0 :         if (!failing)
    1232             :         {
    1233           0 :           failing = true;
    1234           0 :           elem->print_info(libMesh::err);
    1235           0 :           libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
    1236             :                                                         << p << " in element " << elem->id());
    1237             :         }
    1238             :         else
    1239           0 :           return;
    1240             :       }
    1241             : 
    1242           0 :       _ad_JxW[p] = _ad_jac[p] * qw[p];
    1243             : 
    1244           0 :       const auto inv_jac = 1. / _ad_jac[p];
    1245             : 
    1246           0 :       _ad_dxidx_map[p] = (dy_deta * dz_dzeta - dz_deta * dy_dzeta) * inv_jac;
    1247           0 :       _ad_dxidy_map[p] = (dz_deta * dx_dzeta - dx_deta * dz_dzeta) * inv_jac;
    1248           0 :       _ad_dxidz_map[p] = (dx_deta * dy_dzeta - dy_deta * dx_dzeta) * inv_jac;
    1249             : 
    1250           0 :       _ad_detadx_map[p] = (dz_dxi * dy_dzeta - dy_dxi * dz_dzeta) * inv_jac;
    1251           0 :       _ad_detady_map[p] = (dx_dxi * dz_dzeta - dz_dxi * dx_dzeta) * inv_jac;
    1252           0 :       _ad_detadz_map[p] = (dy_dxi * dx_dzeta - dx_dxi * dy_dzeta) * inv_jac;
    1253             : 
    1254           0 :       _ad_dzetadx_map[p] = (dy_dxi * dz_deta - dz_dxi * dy_deta) * inv_jac;
    1255           0 :       _ad_dzetady_map[p] = (dz_dxi * dx_deta - dx_dxi * dz_deta) * inv_jac;
    1256           0 :       _ad_dzetadz_map[p] = (dx_dxi * dy_deta - dy_dxi * dx_deta) * inv_jac;
    1257             : 
    1258           0 :       break;
    1259           0 :     }
    1260             : 
    1261           0 :     default:
    1262           0 :       libmesh_error_msg("Invalid dim = " << dim);
    1263             :   }
    1264             : }
    1265             : 
    1266             : void
    1267    12742770 : Assembly::reinitFEFace(const Elem * elem, unsigned int side)
    1268             : {
    1269    12742770 :   unsigned int dim = elem->dim();
    1270             : 
    1271    40068743 :   for (const auto & it : _fe_face[dim])
    1272             :   {
    1273    27325973 :     FEBase & fe_face = *it.second;
    1274    27325973 :     const FEType & fe_type = it.first;
    1275    27325973 :     FEShapeData & fesd = *_fe_shape_data_face[fe_type];
    1276    27325973 :     fe_face.reinit(elem, side);
    1277    27325973 :     _current_fe_face[fe_type] = &fe_face;
    1278             : 
    1279    27325973 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
    1280    27325973 :     fesd._grad_phi.shallowCopy(
    1281    27325973 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_dphi()));
    1282    27325973 :     if (_need_second_derivative.count(fe_type))
    1283       18513 :       fesd._second_phi.shallowCopy(
    1284       18513 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
    1285             :   }
    1286    15531842 :   for (const auto & it : _vector_fe_face[dim])
    1287             :   {
    1288     2789072 :     FEVectorBase & fe_face = *it.second;
    1289     2789072 :     const FEType & fe_type = it.first;
    1290             : 
    1291     2789072 :     _current_vector_fe_face[fe_type] = &fe_face;
    1292             : 
    1293     2789072 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
    1294             : 
    1295     2789072 :     fe_face.reinit(elem, side);
    1296             : 
    1297     2789072 :     fesd._phi.shallowCopy(
    1298     2789072 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
    1299     2789072 :     fesd._grad_phi.shallowCopy(
    1300     2789072 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
    1301     2789072 :     if (_need_second_derivative.count(fe_type))
    1302           0 :       fesd._second_phi.shallowCopy(
    1303           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
    1304     2789072 :     if (_need_curl.count(fe_type))
    1305      487970 :       fesd._curl_phi.shallowCopy(
    1306      487970 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
    1307     2789072 :     if (_need_face_div.count(fe_type))
    1308       42336 :       fesd._div_phi.shallowCopy(
    1309       42336 :           const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
    1310             :   }
    1311    12742770 :   if (!_unique_fe_face_helper.empty())
    1312             :   {
    1313             :     mooseAssert(dim < _unique_fe_face_helper.size(), "We should be in bounds here");
    1314      118556 :     _unique_fe_face_helper[dim]->reinit(elem, side);
    1315             :   }
    1316             : 
    1317             :   // During that last loop the helper objects will have been reinitialized as well
    1318             :   // We need to dig out the q_points and JxW from it.
    1319    12742770 :   _current_q_points_face.shallowCopy(
    1320    12742770 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_xyz()));
    1321    12742770 :   _current_JxW_face.shallowCopy(
    1322    12742770 :       const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_JxW()));
    1323    12742770 :   _current_normals.shallowCopy(
    1324    12742770 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_normals()));
    1325             : 
    1326    12742770 :   _mapped_normals.resize(_current_normals.size(), Eigen::Map<RealDIMValue>(nullptr));
    1327    41469229 :   for (unsigned int i = 0; i < _current_normals.size(); i++)
    1328             :     // Note: this does NOT do any allocation.  It is "reconstructing" the object in place
    1329    28726459 :     new (&_mapped_normals[i]) Eigen::Map<RealDIMValue>(const_cast<Real *>(&_current_normals[i](0)));
    1330             : 
    1331    12742770 :   if (_calculate_curvatures)
    1332         468 :     _curvatures.shallowCopy(
    1333         468 :         const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_curvatures()));
    1334             : 
    1335    12742770 :   computeADFace(*elem, side);
    1336             : 
    1337    12742770 :   if (_xfem != nullptr)
    1338           0 :     modifyFaceWeightsDueToXFEM(elem, side);
    1339             : 
    1340    12742770 :   auto n = numExtraElemIntegers();
    1341    12902230 :   for (auto i : make_range(n))
    1342      159460 :     _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
    1343    12742770 :   _extra_elem_ids[n] = _current_elem->subdomain_id();
    1344    12742770 : }
    1345             : 
    1346             : void
    1347       60238 : Assembly::computeFaceMap(const Elem & elem, const unsigned int side, const std::vector<Real> & qw)
    1348             : {
    1349             :   // Important quantities calculated by this method:
    1350             :   //   - _ad_JxW_face
    1351             :   //   - _ad_q_points_face
    1352             :   //   - _ad_normals
    1353             :   //   - _ad_curvatures
    1354             : 
    1355       60238 :   const Elem & side_elem = _compute_face_map_side_elem_builder(elem, side);
    1356       60238 :   const auto dim = elem.dim();
    1357       60238 :   const auto n_qp = qw.size();
    1358       60238 :   const auto & dpsidxi_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsidxi();
    1359       60238 :   const auto & dpsideta_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsideta();
    1360       60238 :   const auto & psi_map = _holder_fe_face_helper[dim]->get_fe_map().get_psi();
    1361       60238 :   std::vector<std::vector<Real>> const * d2psidxi2_map = nullptr;
    1362       60238 :   std::vector<std::vector<Real>> const * d2psidxideta_map = nullptr;
    1363       60238 :   std::vector<std::vector<Real>> const * d2psideta2_map = nullptr;
    1364       60238 :   const auto sys_num = _sys.number();
    1365       60238 :   const bool do_derivatives = ADReal::do_derivatives && sys_num == _subproblem.currentNlSysNum();
    1366             : 
    1367       60238 :   if (_calculate_curvatures)
    1368             :   {
    1369           0 :     d2psidxi2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxi2();
    1370           0 :     d2psidxideta_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxideta();
    1371           0 :     d2psideta2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psideta2();
    1372             :   }
    1373             : 
    1374       60238 :   switch (dim)
    1375             :   {
    1376         310 :     case 1:
    1377             :     {
    1378         310 :       if (!n_qp)
    1379           0 :         break;
    1380             : 
    1381         310 :       if (side_elem.node_id(0) == elem.node_id(0))
    1382         310 :         _ad_normals[0] = Point(-1.);
    1383             :       else
    1384           0 :         _ad_normals[0] = Point(1.);
    1385             : 
    1386         310 :       VectorValue<ADReal> side_point;
    1387         310 :       if (_calculate_face_xyz)
    1388             :       {
    1389         310 :         const Node & node = side_elem.node_ref(0);
    1390         310 :         side_point = node;
    1391             : 
    1392         310 :         if (do_derivatives)
    1393         140 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1394         140 :             Moose::derivInsert(
    1395          70 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1396             :       }
    1397             : 
    1398         620 :       for (const auto p : make_range(n_qp))
    1399             :       {
    1400         310 :         if (_calculate_face_xyz)
    1401             :         {
    1402         310 :           _ad_q_points_face[p].zero();
    1403         310 :           _ad_q_points_face[p].add_scaled(side_point, psi_map[0][p]);
    1404             :         }
    1405             : 
    1406         310 :         _ad_normals[p] = _ad_normals[0];
    1407         310 :         _ad_JxW_face[p] = 1.0 * qw[p];
    1408             :       }
    1409             : 
    1410         310 :       break;
    1411         310 :     }
    1412             : 
    1413       59928 :     case 2:
    1414             :     {
    1415       59928 :       _ad_dxyzdxi_map.resize(n_qp);
    1416       59928 :       if (_calculate_curvatures)
    1417           0 :         _ad_d2xyzdxi2_map.resize(n_qp);
    1418             : 
    1419      179934 :       for (const auto p : make_range(n_qp))
    1420      120006 :         _ad_dxyzdxi_map[p].zero();
    1421       59928 :       if (_calculate_face_xyz)
    1422      111774 :         for (const auto p : make_range(n_qp))
    1423       74516 :           _ad_q_points_face[p].zero();
    1424       59928 :       if (_calculate_curvatures)
    1425           0 :         for (const auto p : make_range(n_qp))
    1426           0 :           _ad_d2xyzdxi2_map[p].zero();
    1427             : 
    1428             :       const auto n_mapping_shape_functions =
    1429       59928 :           FE<2, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
    1430             : 
    1431      212334 :       for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
    1432             :       {
    1433      152406 :         const Node & node = side_elem.node_ref(i);
    1434      152406 :         VectorValue<ADReal> side_point = node;
    1435             : 
    1436      152406 :         if (do_derivatives)
    1437       42689 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1438           0 :             Moose::derivInsert(
    1439           0 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1440             : 
    1441      457668 :         for (const auto p : make_range(n_qp))
    1442      305262 :           _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
    1443      152406 :         if (_calculate_face_xyz)
    1444      320748 :           for (const auto p : make_range(n_qp))
    1445      213832 :             _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
    1446      152406 :         if (_calculate_curvatures)
    1447           0 :           for (const auto p : make_range(n_qp))
    1448           0 :             _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
    1449      152406 :       }
    1450             : 
    1451      179934 :       for (const auto p : make_range(n_qp))
    1452             :       {
    1453      120006 :         _ad_normals[p] =
    1454      240012 :             (VectorValue<ADReal>(_ad_dxyzdxi_map[p](1), -_ad_dxyzdxi_map[p](0), 0.)).unit();
    1455      120006 :         const auto the_jac = _ad_dxyzdxi_map[p].norm();
    1456      120006 :         _ad_JxW_face[p] = the_jac * qw[p];
    1457      120006 :         if (_calculate_curvatures)
    1458             :         {
    1459           0 :           const auto numerator = _ad_d2xyzdxi2_map[p] * _ad_normals[p];
    1460           0 :           const auto denominator = _ad_dxyzdxi_map[p].norm_sq();
    1461             :           libmesh_assert_not_equal_to(denominator, 0);
    1462           0 :           _ad_curvatures[p] = numerator / denominator;
    1463           0 :         }
    1464      120006 :       }
    1465             : 
    1466       59928 :       break;
    1467             :     }
    1468             : 
    1469           0 :     case 3:
    1470             :     {
    1471           0 :       _ad_dxyzdxi_map.resize(n_qp);
    1472           0 :       _ad_dxyzdeta_map.resize(n_qp);
    1473           0 :       if (_calculate_curvatures)
    1474             :       {
    1475           0 :         _ad_d2xyzdxi2_map.resize(n_qp);
    1476           0 :         _ad_d2xyzdxideta_map.resize(n_qp);
    1477           0 :         _ad_d2xyzdeta2_map.resize(n_qp);
    1478             :       }
    1479             : 
    1480           0 :       for (const auto p : make_range(n_qp))
    1481             :       {
    1482           0 :         _ad_dxyzdxi_map[p].zero();
    1483           0 :         _ad_dxyzdeta_map[p].zero();
    1484             :       }
    1485           0 :       if (_calculate_face_xyz)
    1486           0 :         for (const auto p : make_range(n_qp))
    1487           0 :           _ad_q_points_face[p].zero();
    1488           0 :       if (_calculate_curvatures)
    1489           0 :         for (const auto p : make_range(n_qp))
    1490             :         {
    1491           0 :           _ad_d2xyzdxi2_map[p].zero();
    1492           0 :           _ad_d2xyzdxideta_map[p].zero();
    1493           0 :           _ad_d2xyzdeta2_map[p].zero();
    1494             :         }
    1495             : 
    1496             :       const unsigned int n_mapping_shape_functions =
    1497           0 :           FE<3, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
    1498             : 
    1499           0 :       for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
    1500             :       {
    1501           0 :         const Node & node = side_elem.node_ref(i);
    1502           0 :         VectorValue<ADReal> side_point = node;
    1503             : 
    1504           0 :         if (do_derivatives)
    1505           0 :           for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
    1506           0 :             Moose::derivInsert(
    1507           0 :                 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
    1508             : 
    1509           0 :         for (const auto p : make_range(n_qp))
    1510             :         {
    1511           0 :           _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
    1512           0 :           _ad_dxyzdeta_map[p].add_scaled(side_point, dpsideta_map[i][p]);
    1513             :         }
    1514           0 :         if (_calculate_face_xyz)
    1515           0 :           for (const auto p : make_range(n_qp))
    1516           0 :             _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
    1517           0 :         if (_calculate_curvatures)
    1518           0 :           for (const auto p : make_range(n_qp))
    1519             :           {
    1520           0 :             _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
    1521           0 :             _ad_d2xyzdxideta_map[p].add_scaled(side_point, (*d2psidxideta_map)[i][p]);
    1522           0 :             _ad_d2xyzdeta2_map[p].add_scaled(side_point, (*d2psideta2_map)[i][p]);
    1523             :           }
    1524           0 :       }
    1525             : 
    1526           0 :       for (const auto p : make_range(n_qp))
    1527             :       {
    1528           0 :         _ad_normals[p] = _ad_dxyzdxi_map[p].cross(_ad_dxyzdeta_map[p]).unit();
    1529             : 
    1530           0 :         const auto &dxdxi = _ad_dxyzdxi_map[p](0), &dxdeta = _ad_dxyzdeta_map[p](0),
    1531           0 :                    &dydxi = _ad_dxyzdxi_map[p](1), &dydeta = _ad_dxyzdeta_map[p](1),
    1532           0 :                    &dzdxi = _ad_dxyzdxi_map[p](2), &dzdeta = _ad_dxyzdeta_map[p](2);
    1533             : 
    1534           0 :         const auto g11 = (dxdxi * dxdxi + dydxi * dydxi + dzdxi * dzdxi);
    1535             : 
    1536           0 :         const auto g12 = (dxdxi * dxdeta + dydxi * dydeta + dzdxi * dzdeta);
    1537             : 
    1538           0 :         const auto & g21 = g12;
    1539             : 
    1540           0 :         const auto g22 = (dxdeta * dxdeta + dydeta * dydeta + dzdeta * dzdeta);
    1541             : 
    1542           0 :         const auto the_jac = std::sqrt(g11 * g22 - g12 * g21);
    1543             : 
    1544           0 :         _ad_JxW_face[p] = the_jac * qw[p];
    1545             : 
    1546           0 :         if (_calculate_curvatures)
    1547             :         {
    1548           0 :           const auto L = -_ad_d2xyzdxi2_map[p] * _ad_normals[p];
    1549           0 :           const auto M = -_ad_d2xyzdxideta_map[p] * _ad_normals[p];
    1550           0 :           const auto N = -_ad_d2xyzdeta2_map[p] * _ad_normals[p];
    1551           0 :           const auto E = _ad_dxyzdxi_map[p].norm_sq();
    1552           0 :           const auto F = _ad_dxyzdxi_map[p] * _ad_dxyzdeta_map[p];
    1553           0 :           const auto G = _ad_dxyzdeta_map[p].norm_sq();
    1554             : 
    1555           0 :           const auto numerator = E * N - 2. * F * M + G * L;
    1556           0 :           const auto denominator = E * G - F * F;
    1557             :           libmesh_assert_not_equal_to(denominator, 0.);
    1558           0 :           _ad_curvatures[p] = 0.5 * numerator / denominator;
    1559           0 :         }
    1560           0 :       }
    1561             : 
    1562           0 :       break;
    1563             :     }
    1564             : 
    1565           0 :     default:
    1566           0 :       mooseError("Invalid dimension dim = ", dim);
    1567             :   }
    1568       60238 : }
    1569             : 
    1570             : void
    1571     4294203 : Assembly::reinitFEFaceNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1572             : {
    1573     4294203 :   unsigned int neighbor_dim = neighbor->dim();
    1574             : 
    1575             :   // reinit neighbor face
    1576    12627429 :   for (const auto & it : _fe_face_neighbor[neighbor_dim])
    1577             :   {
    1578     8333226 :     FEBase & fe_face_neighbor = *it.second;
    1579     8333226 :     FEType fe_type = it.first;
    1580     8333226 :     FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
    1581             : 
    1582     8333226 :     fe_face_neighbor.reinit(neighbor, &reference_points);
    1583             : 
    1584     8333226 :     _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    1585             : 
    1586     8333226 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
    1587     8333226 :     fesd._grad_phi.shallowCopy(
    1588     8333226 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
    1589     8333226 :     if (_need_second_derivative_neighbor.count(fe_type))
    1590        9720 :       fesd._second_phi.shallowCopy(
    1591        9720 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
    1592             :   }
    1593     4322766 :   for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
    1594             :   {
    1595       28563 :     FEVectorBase & fe_face_neighbor = *it.second;
    1596       28563 :     const FEType & fe_type = it.first;
    1597             : 
    1598       28563 :     _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    1599             : 
    1600       28563 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
    1601             : 
    1602       28563 :     fe_face_neighbor.reinit(neighbor, &reference_points);
    1603             : 
    1604       28563 :     fesd._phi.shallowCopy(
    1605       28563 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
    1606       28563 :     fesd._grad_phi.shallowCopy(
    1607       28563 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
    1608       28563 :     if (_need_second_derivative.count(fe_type))
    1609           0 :       fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
    1610           0 :           fe_face_neighbor.get_d2phi()));
    1611       28563 :     if (_need_curl.count(fe_type))
    1612         120 :       fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
    1613         120 :           fe_face_neighbor.get_curl_phi()));
    1614       28563 :     if (_need_face_neighbor_div.count(fe_type))
    1615           0 :       fesd._div_phi.shallowCopy(
    1616           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
    1617             :   }
    1618     4294203 :   if (!_unique_fe_face_neighbor_helper.empty())
    1619             :   {
    1620             :     mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
    1621             :                 "We should be in bounds here");
    1622       68880 :     _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
    1623             :   }
    1624             : 
    1625     4294203 :   _current_q_points_face_neighbor.shallowCopy(
    1626     4294203 :       const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
    1627     4294203 : }
    1628             : 
    1629             : void
    1630       22720 : Assembly::reinitFENeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1631             : {
    1632       22720 :   unsigned int neighbor_dim = neighbor->dim();
    1633             : 
    1634             :   // reinit neighbor face
    1635       45440 :   for (const auto & it : _fe_neighbor[neighbor_dim])
    1636             :   {
    1637       22720 :     FEBase & fe_neighbor = *it.second;
    1638       22720 :     FEType fe_type = it.first;
    1639       22720 :     FEShapeData & fesd = *_fe_shape_data_neighbor[fe_type];
    1640             : 
    1641       22720 :     fe_neighbor.reinit(neighbor, &reference_points);
    1642             : 
    1643       22720 :     _current_fe_neighbor[fe_type] = &fe_neighbor;
    1644             : 
    1645       22720 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_phi()));
    1646       22720 :     fesd._grad_phi.shallowCopy(
    1647       22720 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_neighbor.get_dphi()));
    1648       22720 :     if (_need_second_derivative_neighbor.count(fe_type))
    1649           0 :       fesd._second_phi.shallowCopy(
    1650           0 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_d2phi()));
    1651             :   }
    1652       22720 :   for (const auto & it : _vector_fe_neighbor[neighbor_dim])
    1653             :   {
    1654           0 :     FEVectorBase & fe_neighbor = *it.second;
    1655           0 :     const FEType & fe_type = it.first;
    1656             : 
    1657           0 :     _current_vector_fe_neighbor[fe_type] = &fe_neighbor;
    1658             : 
    1659           0 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_neighbor[fe_type];
    1660             : 
    1661           0 :     fe_neighbor.reinit(neighbor, &reference_points);
    1662             : 
    1663           0 :     fesd._phi.shallowCopy(
    1664           0 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_phi()));
    1665           0 :     fesd._grad_phi.shallowCopy(
    1666           0 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_dphi()));
    1667           0 :     if (_need_second_derivative.count(fe_type))
    1668           0 :       fesd._second_phi.shallowCopy(
    1669           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_neighbor.get_d2phi()));
    1670           0 :     if (_need_curl.count(fe_type))
    1671           0 :       fesd._curl_phi.shallowCopy(
    1672           0 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_curl_phi()));
    1673           0 :     if (_need_neighbor_div.count(fe_type))
    1674           0 :       fesd._div_phi.shallowCopy(
    1675           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_div_phi()));
    1676             :   }
    1677       22720 :   if (!_unique_fe_neighbor_helper.empty())
    1678             :   {
    1679             :     mooseAssert(neighbor_dim < _unique_fe_neighbor_helper.size(), "We should be in bounds here");
    1680           0 :     _unique_fe_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
    1681             :   }
    1682       22720 : }
    1683             : 
    1684             : void
    1685     4316923 : Assembly::reinitNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
    1686             : {
    1687     4316923 :   unsigned int neighbor_dim = neighbor->dim();
    1688             :   mooseAssert(_current_neighbor_subdomain_id == neighbor->subdomain_id(),
    1689             :               "Neighbor subdomain ID has not been correctly set");
    1690             : 
    1691             :   ArbitraryQuadrature * neighbor_rule =
    1692     4316923 :       qrules(neighbor_dim, _current_neighbor_subdomain_id).neighbor.get();
    1693     4316923 :   neighbor_rule->setPoints(reference_points);
    1694     4316923 :   setNeighborQRule(neighbor_rule, neighbor_dim);
    1695             : 
    1696     4316923 :   _current_neighbor_elem = neighbor;
    1697             :   mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
    1698             :               "current neighbor subdomain has been set incorrectly");
    1699             : 
    1700             :   // Calculate the volume of the neighbor
    1701     4316923 :   if (_need_neighbor_elem_volume)
    1702             :   {
    1703     2348334 :     unsigned int dim = neighbor->dim();
    1704     2348334 :     FEBase & fe = *_holder_fe_neighbor_helper[dim];
    1705     2348334 :     QBase * qrule = qrules(dim).vol.get();
    1706             : 
    1707     2348334 :     fe.attach_quadrature_rule(qrule);
    1708     2348334 :     fe.reinit(neighbor);
    1709             : 
    1710     2348334 :     const std::vector<Real> & JxW = fe.get_JxW();
    1711     2348334 :     MooseArray<Point> q_points;
    1712     2348334 :     q_points.shallowCopy(const_cast<std::vector<Point> &>(fe.get_xyz()));
    1713             : 
    1714     2348334 :     setCoordinateTransformation(qrule, q_points, _coord_neighbor, _current_neighbor_subdomain_id);
    1715             : 
    1716     2348334 :     _current_neighbor_volume = 0.;
    1717    20139236 :     for (unsigned int qp = 0; qp < qrule->n_points(); qp++)
    1718    17790902 :       _current_neighbor_volume += JxW[qp] * _coord_neighbor[qp];
    1719     2348334 :   }
    1720             : 
    1721     4316923 :   auto n = numExtraElemIntegers();
    1722     4406233 :   for (auto i : make_range(n))
    1723       89310 :     _neighbor_extra_elem_ids[i] = _current_neighbor_elem->get_extra_integer(i);
    1724     4316923 :   _neighbor_extra_elem_ids[n] = _current_neighbor_elem->subdomain_id();
    1725     4316923 : }
    1726             : 
    1727             : template <typename Points, typename Coords>
    1728             : void
    1729   473668544 : Assembly::setCoordinateTransformation(const QBase * qrule,
    1730             :                                       const Points & q_points,
    1731             :                                       Coords & coord,
    1732             :                                       SubdomainID sub_id)
    1733             : {
    1734             : 
    1735             :   mooseAssert(qrule, "The quadrature rule is null in Assembly::setCoordinateTransformation");
    1736   473668544 :   auto n_points = qrule->n_points();
    1737             :   mooseAssert(n_points == q_points.size(),
    1738             :               "The number of points in the quadrature rule doesn't match the number of passed-in "
    1739             :               "points in Assembly::setCoordinateTransformation");
    1740             : 
    1741             :   // Make sure to honor the name of this method and set the _coord_type member because users may
    1742             :   // make use of the const Moose::CoordinateSystem & coordTransformation() { return _coord_type; }
    1743             :   // API. MaterialBase for example uses it
    1744   473668544 :   _coord_type = _subproblem.getCoordSystem(sub_id);
    1745             : 
    1746   473668544 :   coord.resize(n_points);
    1747  2516707833 :   for (unsigned int qp = 0; qp < n_points; qp++)
    1748  2043039289 :     coordTransformFactor(_subproblem, sub_id, q_points[qp], coord[qp]);
    1749   473668544 : }
    1750             : 
    1751             : void
    1752   440914332 : Assembly::computeCurrentElemVolume()
    1753             : {
    1754   440914332 :   if (_current_elem_volume_computed)
    1755           0 :     return;
    1756             : 
    1757   440914332 :   setCoordinateTransformation(
    1758   440914332 :       _current_qrule, _current_q_points, _coord, _current_elem->subdomain_id());
    1759   440914332 :   if (_calculate_ad_coord)
    1760    13399220 :     setCoordinateTransformation(
    1761    13399220 :         _current_qrule, _ad_q_points, _ad_coord, _current_elem->subdomain_id());
    1762             : 
    1763   440914332 :   _current_elem_volume = 0.;
    1764  2375196513 :   for (unsigned int qp = 0; qp < _current_qrule->n_points(); qp++)
    1765  1934282181 :     _current_elem_volume += _current_JxW[qp] * _coord[qp];
    1766             : 
    1767   440914332 :   _current_elem_volume_computed = true;
    1768             : }
    1769             : 
    1770             : void
    1771    12742770 : Assembly::computeCurrentFaceVolume()
    1772             : {
    1773    12742770 :   if (_current_side_volume_computed)
    1774           0 :     return;
    1775             : 
    1776    12742770 :   setCoordinateTransformation(
    1777    12742770 :       _current_qrule_face, _current_q_points_face, _coord, _current_elem->subdomain_id());
    1778    12742770 :   if (_calculate_ad_coord)
    1779     3691562 :     setCoordinateTransformation(
    1780     3691562 :         _current_qrule_face, _ad_q_points_face, _ad_coord, _current_elem->subdomain_id());
    1781             : 
    1782    12742770 :   _current_side_volume = 0.;
    1783    41469229 :   for (unsigned int qp = 0; qp < _current_qrule_face->n_points(); qp++)
    1784    28726459 :     _current_side_volume += _current_JxW_face[qp] * _coord[qp];
    1785             : 
    1786    12742770 :   _current_side_volume_computed = true;
    1787             : }
    1788             : 
    1789             : void
    1790      395420 : Assembly::reinitAtPhysical(const Elem * elem, const std::vector<Point> & physical_points)
    1791             : {
    1792      395420 :   _current_elem = elem;
    1793      395420 :   _current_neighbor_elem = nullptr;
    1794             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1795             :               "current subdomain has been set incorrectly");
    1796      395420 :   _current_elem_volume_computed = false;
    1797             : 
    1798      395420 :   FEMap::inverse_map(elem->dim(), elem, physical_points, _temp_reference_points);
    1799             : 
    1800      395420 :   reinit(elem, _temp_reference_points);
    1801             : 
    1802             :   // Save off the physical points
    1803      395420 :   _current_physical_points = physical_points;
    1804      395420 : }
    1805             : 
    1806             : void
    1807   440600335 : Assembly::setVolumeQRule(const Elem * const elem)
    1808             : {
    1809   440600335 :   unsigned int elem_dimension = elem->dim();
    1810   440600335 :   _current_qrule_volume = qrules(elem_dimension).vol.get();
    1811             :   // Make sure the qrule is the right one
    1812   440600335 :   if (_current_qrule != _current_qrule_volume)
    1813      212595 :     setVolumeQRule(_current_qrule_volume, elem_dimension);
    1814   440600335 : }
    1815             : 
    1816             : void
    1817   440518940 : Assembly::reinit(const Elem * elem)
    1818             : {
    1819   440518940 :   _current_elem = elem;
    1820   440518940 :   _current_neighbor_elem = nullptr;
    1821             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1822             :               "current subdomain has been set incorrectly");
    1823   440518940 :   _current_elem_volume_computed = false;
    1824   440518940 :   setVolumeQRule(elem);
    1825   440518940 :   reinitFE(elem);
    1826             : 
    1827   440518912 :   computeCurrentElemVolume();
    1828   440518912 : }
    1829             : 
    1830             : void
    1831      395420 : Assembly::reinit(const Elem * elem, const std::vector<Point> & reference_points)
    1832             : {
    1833      395420 :   _current_elem = elem;
    1834      395420 :   _current_neighbor_elem = nullptr;
    1835             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1836             :               "current subdomain has been set incorrectly");
    1837      395420 :   _current_elem_volume_computed = false;
    1838             : 
    1839      395420 :   unsigned int elem_dimension = _current_elem->dim();
    1840             : 
    1841      395420 :   _current_qrule_arbitrary = qrules(elem_dimension).arbitrary_vol.get();
    1842             : 
    1843             :   // Make sure the qrule is the right one
    1844      395420 :   if (_current_qrule != _current_qrule_arbitrary)
    1845       33800 :     setVolumeQRule(_current_qrule_arbitrary, elem_dimension);
    1846             : 
    1847      395420 :   _current_qrule_arbitrary->setPoints(reference_points);
    1848             : 
    1849      395420 :   reinitFE(elem);
    1850             : 
    1851      395420 :   computeCurrentElemVolume();
    1852      395420 : }
    1853             : 
    1854             : void
    1855    26540752 : Assembly::reinitFVFace(const FaceInfo & fi)
    1856             : {
    1857    26540752 :   _current_elem = &fi.elem();
    1858    26540752 :   _current_neighbor_elem = fi.neighborPtr();
    1859    26540752 :   _current_side = fi.elemSideID();
    1860    26540752 :   _current_neighbor_side = fi.neighborSideID();
    1861             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1862             :               "current subdomain has been set incorrectly");
    1863             : 
    1864    26540752 :   _current_elem_volume_computed = false;
    1865    26540752 :   _current_side_volume_computed = false;
    1866             : 
    1867    26540752 :   prepareResidual();
    1868    26540752 :   prepareNeighbor();
    1869    26540752 :   prepareJacobianBlock();
    1870             : 
    1871    26540752 :   unsigned int dim = _current_elem->dim();
    1872    26540752 :   if (_current_qrule_face != qrules(dim).fv_face.get())
    1873             :   {
    1874        5587 :     setFaceQRule(qrules(dim).fv_face.get(), dim);
    1875             :     // The order of the element that is used for initing here doesn't matter since this will just
    1876             :     // be used for constant monomials (which only need a single integration point)
    1877        5587 :     if (dim == 3)
    1878          13 :       _current_qrule_face->init(QUAD4, /* p_level = */ 0, /* simple_type_only = */ true);
    1879             :     else
    1880        5574 :       _current_qrule_face->init(EDGE2, /* p_level = */ 0, /* simple_type_only = */ true);
    1881             :   }
    1882             : 
    1883    26540752 :   _current_side_elem = &_current_side_elem_builder(*_current_elem, _current_side);
    1884             : 
    1885             :   mooseAssert(_current_qrule_face->n_points() == 1,
    1886             :               "Our finite volume quadrature rule should always yield a single point");
    1887             : 
    1888             :   // We've initialized the reference points. Now we need to compute the physical location of the
    1889             :   // quadrature points. We do not do any FE initialization so we cannot simply copy over FE
    1890             :   // results like we do in reinitFEFace. Instead we handle the computation of the physical
    1891             :   // locations manually
    1892    26540752 :   _current_q_points_face.resize(1);
    1893    26540752 :   const auto & ref_points = _current_qrule_face->get_points();
    1894    26540752 :   const auto & ref_point = ref_points[0];
    1895    26540752 :   auto physical_point = FEMap::map(_current_side_elem->dim(), _current_side_elem, ref_point);
    1896    26540752 :   _current_q_points_face[0] = physical_point;
    1897             : 
    1898    26540752 :   if (_current_neighbor_elem)
    1899             :   {
    1900             :     mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
    1901             :                 "current neighbor subdomain has been set incorrectly");
    1902             :     // Now handle the neighbor qrule/qpoints
    1903             :     ArbitraryQuadrature * const neighbor_rule =
    1904    24506387 :         qrules(_current_neighbor_elem->dim(), _current_neighbor_subdomain_id).neighbor.get();
    1905             :     // Here we are setting a reference point that is correct for the neighbor *side* element. It
    1906             :     // would be wrong if this reference point is used for a volumetric FE reinit with the neighbor
    1907    24506387 :     neighbor_rule->setPoints(ref_points);
    1908    24506387 :     setNeighborQRule(neighbor_rule, _current_neighbor_elem->dim());
    1909    24506387 :     _current_q_points_face_neighbor.resize(1);
    1910    24506387 :     _current_q_points_face_neighbor[0] = std::move(physical_point);
    1911             :   }
    1912    26540752 : }
    1913             : 
    1914             : QBase *
    1915    12742770 : Assembly::qruleFace(const Elem * elem, unsigned int side)
    1916             : {
    1917    25707121 :   return qruleFaceHelper<QBase>(elem, side, [](QRules & q) { return q.face.get(); });
    1918             : }
    1919             : 
    1920             : ArbitraryQuadrature *
    1921      307159 : Assembly::qruleArbitraryFace(const Elem * elem, unsigned int side)
    1922             : {
    1923      614318 :   return qruleFaceHelper<ArbitraryQuadrature>(
    1924      921477 :       elem, side, [](QRules & q) { return q.arbitrary_face.get(); });
    1925             : }
    1926             : 
    1927             : void
    1928    12742770 : Assembly::setFaceQRule(const Elem * const elem, const unsigned int side)
    1929             : {
    1930    12742770 :   const auto elem_dimension = elem->dim();
    1931             :   //// Make sure the qrule is the right one
    1932    12742770 :   auto rule = qruleFace(elem, side);
    1933    12742770 :   if (_current_qrule_face != rule)
    1934       12921 :     setFaceQRule(rule, elem_dimension);
    1935    12742770 : }
    1936             : 
    1937             : void
    1938    12742770 : Assembly::reinit(const Elem * const elem, const unsigned int side)
    1939             : {
    1940    12742770 :   _current_elem = elem;
    1941    12742770 :   _current_neighbor_elem = nullptr;
    1942             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1943             :               "current subdomain has been set incorrectly");
    1944    12742770 :   _current_side = side;
    1945    12742770 :   _current_elem_volume_computed = false;
    1946    12742770 :   _current_side_volume_computed = false;
    1947             : 
    1948    12742770 :   _current_side_elem = &_current_side_elem_builder(*elem, side);
    1949             : 
    1950    12742770 :   setFaceQRule(elem, side);
    1951    12742770 :   reinitFEFace(elem, side);
    1952             : 
    1953    12742770 :   computeCurrentFaceVolume();
    1954    12742770 : }
    1955             : 
    1956             : void
    1957           0 : Assembly::reinit(const Elem * elem, unsigned int side, const std::vector<Point> & reference_points)
    1958             : {
    1959           0 :   _current_elem = elem;
    1960           0 :   _current_neighbor_elem = nullptr;
    1961             :   mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
    1962             :               "current subdomain has been set incorrectly");
    1963           0 :   _current_side = side;
    1964           0 :   _current_elem_volume_computed = false;
    1965           0 :   _current_side_volume_computed = false;
    1966             : 
    1967           0 :   unsigned int elem_dimension = _current_elem->dim();
    1968             : 
    1969           0 :   _current_qrule_arbitrary_face = qruleArbitraryFace(elem, side);
    1970             : 
    1971             :   // Make sure the qrule is the right one
    1972           0 :   if (_current_qrule_face != _current_qrule_arbitrary_face)
    1973           0 :     setFaceQRule(_current_qrule_arbitrary_face, elem_dimension);
    1974             : 
    1975           0 :   _current_qrule_arbitrary->setPoints(reference_points);
    1976             : 
    1977           0 :   _current_side_elem = &_current_side_elem_builder(*elem, side);
    1978             : 
    1979           0 :   reinitFEFace(elem, side);
    1980             : 
    1981           0 :   computeCurrentFaceVolume();
    1982           0 : }
    1983             : 
    1984             : void
    1985   119753019 : Assembly::reinit(const Node * node)
    1986             : {
    1987   119753019 :   _current_node = node;
    1988   119753019 :   _current_neighbor_node = NULL;
    1989   119753019 : }
    1990             : 
    1991             : void
    1992     4128321 : Assembly::reinitElemAndNeighbor(const Elem * elem,
    1993             :                                 unsigned int side,
    1994             :                                 const Elem * neighbor,
    1995             :                                 unsigned int neighbor_side,
    1996             :                                 const std::vector<Point> * neighbor_reference_points)
    1997             : {
    1998     4128321 :   _current_neighbor_side = neighbor_side;
    1999             : 
    2000     4128321 :   reinit(elem, side);
    2001             : 
    2002     4128321 :   unsigned int neighbor_dim = neighbor->dim();
    2003             : 
    2004     4128321 :   if (neighbor_reference_points)
    2005       72006 :     _current_neighbor_ref_points = *neighbor_reference_points;
    2006             :   else
    2007     4056315 :     FEMap::inverse_map(
    2008     8112630 :         neighbor_dim, neighbor, _current_q_points_face.stdVector(), _current_neighbor_ref_points);
    2009             : 
    2010     4128321 :   _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
    2011             : 
    2012     4128321 :   reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
    2013     4128321 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2014     4128321 : }
    2015             : 
    2016             : void
    2017      307159 : Assembly::reinitElemFaceRef(const Elem * elem,
    2018             :                             unsigned int elem_side,
    2019             :                             Real tolerance,
    2020             :                             const std::vector<Point> * const pts,
    2021             :                             const std::vector<Real> * const weights)
    2022             : {
    2023      307159 :   _current_elem = elem;
    2024             : 
    2025      307159 :   unsigned int elem_dim = elem->dim();
    2026             : 
    2027             :   // Attach the quadrature rules
    2028      307159 :   if (pts)
    2029             :   {
    2030      307159 :     auto face_rule = qruleArbitraryFace(elem, elem_side);
    2031      307159 :     face_rule->setPoints(*pts);
    2032      307159 :     setFaceQRule(face_rule, elem_dim);
    2033             :   }
    2034             :   else
    2035             :   {
    2036           0 :     auto rule = qruleFace(elem, elem_side);
    2037           0 :     if (_current_qrule_face != rule)
    2038           0 :       setFaceQRule(rule, elem_dim);
    2039             :   }
    2040             : 
    2041             :   // reinit face
    2042      723668 :   for (const auto & it : _fe_face[elem_dim])
    2043             :   {
    2044      416509 :     FEBase & fe_face = *it.second;
    2045      416509 :     FEType fe_type = it.first;
    2046      416509 :     FEShapeData & fesd = *_fe_shape_data_face[fe_type];
    2047             : 
    2048      416509 :     fe_face.reinit(elem, elem_side, tolerance, pts, weights);
    2049             : 
    2050      416509 :     _current_fe_face[fe_type] = &fe_face;
    2051             : 
    2052      416509 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
    2053      416509 :     fesd._grad_phi.shallowCopy(
    2054      416509 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face.get_dphi()));
    2055      416509 :     if (_need_second_derivative_neighbor.count(fe_type))
    2056           0 :       fesd._second_phi.shallowCopy(
    2057           0 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
    2058             :   }
    2059      307159 :   for (const auto & it : _vector_fe_face[elem_dim])
    2060             :   {
    2061           0 :     FEVectorBase & fe_face = *it.second;
    2062           0 :     const FEType & fe_type = it.first;
    2063             : 
    2064           0 :     _current_vector_fe_face[fe_type] = &fe_face;
    2065             : 
    2066           0 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
    2067             : 
    2068           0 :     fe_face.reinit(elem, elem_side, tolerance, pts, weights);
    2069             : 
    2070           0 :     fesd._phi.shallowCopy(
    2071           0 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
    2072           0 :     fesd._grad_phi.shallowCopy(
    2073           0 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
    2074           0 :     if (_need_second_derivative.count(fe_type))
    2075           0 :       fesd._second_phi.shallowCopy(
    2076           0 :           const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
    2077           0 :     if (_need_curl.count(fe_type))
    2078           0 :       fesd._curl_phi.shallowCopy(
    2079           0 :           const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
    2080           0 :     if (_need_face_div.count(fe_type))
    2081           0 :       fesd._div_phi.shallowCopy(
    2082           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
    2083             :   }
    2084      307159 :   if (!_unique_fe_face_helper.empty())
    2085             :   {
    2086             :     mooseAssert(elem_dim < _unique_fe_face_helper.size(), "We should be in bounds here");
    2087           0 :     _unique_fe_face_helper[elem_dim]->reinit(elem, elem_side, tolerance, pts, weights);
    2088             :   }
    2089             : 
    2090             :   // During that last loop the helper objects will have been reinitialized
    2091      307159 :   _current_q_points_face.shallowCopy(
    2092      307159 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_xyz()));
    2093      307159 :   _current_normals.shallowCopy(
    2094      307159 :       const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_normals()));
    2095      307159 :   _current_tangents.shallowCopy(const_cast<std::vector<std::vector<Point>> &>(
    2096      307159 :       _holder_fe_face_helper[elem_dim]->get_tangents()));
    2097             :   // Note that if the user did pass in points and not weights to this method, JxW will be garbage
    2098             :   // and should not be used
    2099      307159 :   _current_JxW_face.shallowCopy(
    2100      307159 :       const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_JxW()));
    2101      307159 :   if (_calculate_curvatures)
    2102           0 :     _curvatures.shallowCopy(
    2103           0 :         const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_curvatures()));
    2104             : 
    2105      307159 :   computeADFace(*elem, elem_side);
    2106      307159 : }
    2107             : 
    2108             : void
    2109    13049929 : Assembly::computeADFace(const Elem & elem, const unsigned int side)
    2110             : {
    2111    13049929 :   const auto dim = elem.dim();
    2112             : 
    2113    13049929 :   if (_subproblem.haveADObjects())
    2114             :   {
    2115     4181933 :     auto n_qp = _current_qrule_face->n_points();
    2116     4181933 :     resizeADMappingObjects(n_qp, dim);
    2117     4181933 :     _ad_normals.resize(n_qp);
    2118     4181933 :     _ad_JxW_face.resize(n_qp);
    2119     4181933 :     if (_calculate_face_xyz)
    2120     3711158 :       _ad_q_points_face.resize(n_qp);
    2121     4181933 :     if (_calculate_curvatures)
    2122         468 :       _ad_curvatures.resize(n_qp);
    2123             : 
    2124     4181933 :     if (_displaced)
    2125             :     {
    2126       60238 :       const auto & qw = _current_qrule_face->get_weights();
    2127       60238 :       computeFaceMap(elem, side, qw);
    2128       60238 :       const std::vector<Real> dummy_qw(n_qp, 1.);
    2129             : 
    2130      180554 :       for (unsigned int qp = 0; qp != n_qp; qp++)
    2131      120316 :         computeSinglePointMapAD(&elem, dummy_qw, qp, _holder_fe_face_helper[dim]);
    2132       60238 :     }
    2133             :     else
    2134             :     {
    2135    13119578 :       for (unsigned qp = 0; qp < n_qp; ++qp)
    2136             :       {
    2137     8997883 :         _ad_JxW_face[qp] = _current_JxW_face[qp];
    2138     8997883 :         _ad_normals[qp] = _current_normals[qp];
    2139             :       }
    2140     4121695 :       if (_calculate_face_xyz)
    2141    11311708 :         for (unsigned qp = 0; qp < n_qp; ++qp)
    2142     7638118 :           _ad_q_points_face[qp] = _current_q_points_face[qp];
    2143     4121695 :       if (_calculate_curvatures)
    2144         936 :         for (unsigned qp = 0; qp < n_qp; ++qp)
    2145         468 :           _ad_curvatures[qp] = _curvatures[qp];
    2146             :     }
    2147             : 
    2148    13300652 :     for (const auto & it : _fe_face[dim])
    2149             :     {
    2150     9118719 :       FEBase & fe = *it.second;
    2151     9118719 :       auto fe_type = it.first;
    2152     9118719 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
    2153     9118719 :       auto & grad_phi = _ad_grad_phi_data_face[fe_type];
    2154             : 
    2155     9118719 :       grad_phi.resize(num_shapes);
    2156    67505849 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2157    58387130 :         grad_phi[i].resize(n_qp);
    2158             : 
    2159     9118719 :       const auto & regular_grad_phi = _fe_shape_data_face[fe_type]->_grad_phi;
    2160             : 
    2161     9118719 :       if (_displaced)
    2162      147348 :         computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
    2163             :       else
    2164    66586471 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2165   191261773 :           for (unsigned qp = 0; qp < n_qp; ++qp)
    2166   133646673 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
    2167             :     }
    2168     4681459 :     for (const auto & it : _vector_fe_face[dim])
    2169             :     {
    2170      499526 :       FEVectorBase & fe = *it.second;
    2171      499526 :       auto fe_type = it.first;
    2172      499526 :       auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
    2173      499526 :       auto & grad_phi = _ad_vector_grad_phi_data_face[fe_type];
    2174             : 
    2175      499526 :       grad_phi.resize(num_shapes);
    2176     2628696 :       for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2177     2129170 :         grad_phi[i].resize(n_qp);
    2178             : 
    2179      499526 :       const auto & regular_grad_phi = _vector_fe_shape_data_face[fe_type]->_grad_phi;
    2180             : 
    2181      499526 :       if (_displaced)
    2182           0 :         computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
    2183             :       else
    2184     2628696 :         for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
    2185     6511452 :           for (unsigned qp = 0; qp < n_qp; ++qp)
    2186     4382282 :             grad_phi[i][qp] = regular_grad_phi[i][qp];
    2187             :     }
    2188             :   }
    2189    13049929 : }
    2190             : 
    2191             : void
    2192      307159 : Assembly::reinitNeighborFaceRef(const Elem * neighbor,
    2193             :                                 unsigned int neighbor_side,
    2194             :                                 Real tolerance,
    2195             :                                 const std::vector<Point> * const pts,
    2196             :                                 const std::vector<Real> * const weights)
    2197             : {
    2198      307159 :   _current_neighbor_elem = neighbor;
    2199             : 
    2200      307159 :   unsigned int neighbor_dim = neighbor->dim();
    2201             : 
    2202             :   ArbitraryQuadrature * neighbor_rule =
    2203      307159 :       qrules(neighbor_dim, neighbor->subdomain_id()).neighbor.get();
    2204      307159 :   neighbor_rule->setPoints(*pts);
    2205             : 
    2206             :   // Attach this quadrature rule to all the _fe_face_neighbor FE objects. This
    2207             :   // has to have garbage quadrature weights but that's ok because we never
    2208             :   // actually use the JxW coming from these FE reinit'd objects, e.g. we use the
    2209             :   // JxW coming from the element face reinit for DGKernels or we use the JxW
    2210             :   // coming from reinit of the mortar segment element in the case of mortar
    2211      307159 :   setNeighborQRule(neighbor_rule, neighbor_dim);
    2212             : 
    2213             :   // reinit neighbor face
    2214      723668 :   for (const auto & it : _fe_face_neighbor[neighbor_dim])
    2215             :   {
    2216      416509 :     FEBase & fe_face_neighbor = *it.second;
    2217      416509 :     FEType fe_type = it.first;
    2218      416509 :     FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
    2219             : 
    2220      416509 :     fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
    2221             : 
    2222      416509 :     _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    2223             : 
    2224      416509 :     fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
    2225      416509 :     fesd._grad_phi.shallowCopy(
    2226      416509 :         const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
    2227      416509 :     if (_need_second_derivative_neighbor.count(fe_type))
    2228           0 :       fesd._second_phi.shallowCopy(
    2229           0 :           const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
    2230             :   }
    2231      307159 :   for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
    2232             :   {
    2233           0 :     FEVectorBase & fe_face_neighbor = *it.second;
    2234           0 :     const FEType & fe_type = it.first;
    2235             : 
    2236           0 :     _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
    2237             : 
    2238           0 :     VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
    2239             : 
    2240           0 :     fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
    2241             : 
    2242           0 :     fesd._phi.shallowCopy(
    2243           0 :         const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
    2244           0 :     fesd._grad_phi.shallowCopy(
    2245           0 :         const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
    2246           0 :     if (_need_second_derivative.count(fe_type))
    2247           0 :       fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
    2248           0 :           fe_face_neighbor.get_d2phi()));
    2249           0 :     if (_need_curl.count(fe_type))
    2250           0 :       fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
    2251           0 :           fe_face_neighbor.get_curl_phi()));
    2252           0 :     if (_need_face_neighbor_div.count(fe_type))
    2253           0 :       fesd._div_phi.shallowCopy(
    2254           0 :           const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
    2255             :   }
    2256      307159 :   if (!_unique_fe_face_neighbor_helper.empty())
    2257             :   {
    2258             :     mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
    2259             :                 "We should be in bounds here");
    2260           0 :     _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(
    2261             :         neighbor, neighbor_side, tolerance, pts, weights);
    2262             :   }
    2263             :   // During that last loop the helper objects will have been reinitialized as well
    2264             :   // We need to dig out the q_points from it
    2265      307159 :   _current_q_points_face_neighbor.shallowCopy(
    2266      307159 :       const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
    2267      307159 : }
    2268             : 
    2269             : void
    2270        4587 : Assembly::reinitDual(const Elem * elem,
    2271             :                      const std::vector<Point> & pts,
    2272             :                      const std::vector<Real> & JxW)
    2273             : {
    2274        4587 :   const unsigned int elem_dim = elem->dim();
    2275             :   mooseAssert(elem_dim == _mesh_dimension - 1,
    2276             :               "Dual shape functions should only be computed on lower dimensional face elements");
    2277             : 
    2278        9489 :   for (const auto & it : _fe_lower[elem_dim])
    2279             :   {
    2280        4902 :     FEBase & fe_lower = *it.second;
    2281             :     // We use customized quadrature rule for integration along the mortar segment elements
    2282        4902 :     fe_lower.set_calculate_default_dual_coeff(false);
    2283        4902 :     fe_lower.reinit_dual_shape_coeffs(elem, pts, JxW);
    2284             :   }
    2285        4587 : }
    2286             : 
    2287             : void
    2288      326016 : Assembly::reinitLowerDElem(const Elem * elem,
    2289             :                            const std::vector<Point> * const pts,
    2290             :                            const std::vector<Real> * const weights)
    2291             : {
    2292      326016 :   _current_lower_d_elem = elem;
    2293             : 
    2294      326016 :   const unsigned int elem_dim = elem->dim();
    2295             :   mooseAssert(elem_dim < _mesh_dimension,
    2296             :               "The lower dimensional element should truly be a lower dimensional element");
    2297             : 
    2298      326016 :   if (pts)
    2299             :   {
    2300             :     // Lower rule matches the face rule for the higher dimensional element
    2301      284381 :     ArbitraryQuadrature * lower_rule = qrules(elem_dim + 1).arbitrary_face.get();
    2302             : 
    2303             :     // This also sets the quadrature weights to unity
    2304      284381 :     lower_rule->setPoints(*pts);
    2305             : 
    2306      284381 :     if (weights)
    2307           0 :       lower_rule->setWeights(*weights);
    2308             : 
    2309      284381 :     setLowerQRule(lower_rule, elem_dim);
    2310             :   }
    2311       41635 :   else if (_current_qrule_lower != qrules(elem_dim + 1).face.get())
    2312         471 :     setLowerQRule(qrules(elem_dim + 1).face.get(), elem_dim);
    2313             : 
    2314      802404 :   for (const auto & it : _fe_lower[elem_dim])
    2315             :   {
    2316      476388 :     FEBase & fe_lower = *it.second;
    2317      476388 :     FEType fe_type = it.first;
    2318             : 
    2319      476388 :     fe_lower.reinit(elem);
    2320             : 
    2321      476388 :     if (FEShapeData * fesd = _fe_shape_data_lower[fe_type].get())
    2322             :     {
    2323      476388 :       fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_phi()));
    2324      476388 :       fesd->_grad_phi.shallowCopy(
    2325      476388 :           const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dphi()));
    2326      476388 :       if (_need_second_derivative_neighbor.count(fe_type))
    2327           0 :         fesd->_second_phi.shallowCopy(
    2328           0 :             const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_d2phi()));
    2329             :     }
    2330             : 
    2331             :     // Dual shape functions need to be computed after primal basis being initialized
    2332      476388 :     if (FEShapeData * fesd = _fe_shape_data_dual_lower[fe_type].get())
    2333             :     {
    2334       13688 :       fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_dual_phi()));
    2335       13688 :       fesd->_grad_phi.shallowCopy(
    2336       13688 :           const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dual_dphi()));
    2337       13688 :       if (_need_second_derivative_neighbor.count(fe_type))
    2338           0 :         fesd->_second_phi.shallowCopy(
    2339           0 :             const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_dual_d2phi()));
    2340             :     }
    2341             :   }
    2342      326016 :   if (!_unique_fe_lower_helper.empty())
    2343             :   {
    2344             :     mooseAssert(elem_dim < _unique_fe_lower_helper.size(), "We should be in bounds here");
    2345           0 :     _unique_fe_lower_helper[elem_dim]->reinit(elem);
    2346             :   }
    2347             : 
    2348      326016 :   if (!_need_lower_d_elem_volume)
    2349      219485 :     return;
    2350             : 
    2351      106531 :   if (pts && !weights)
    2352             :   {
    2353             :     // We only have dummy weights so the JxWs computed during our FE reinits are meaningless and
    2354             :     // we cannot use them
    2355             : 
    2356      205934 :     if (_subproblem.getCoordSystem(elem->subdomain_id()) == Moose::CoordinateSystemType::COORD_XYZ)
    2357             :       // We are in a Cartesian coordinate system and we can just use the element volume method
    2358             :       // which has fast computation for certain element types
    2359      102967 :       _current_lower_d_elem_volume = elem->volume();
    2360             :     else
    2361             :       // We manually compute the volume taking the curvilinear coordinate transformations into
    2362             :       // account
    2363           0 :       _current_lower_d_elem_volume = elementVolume(elem);
    2364             :   }
    2365             :   else
    2366             :   {
    2367             :     // During that last loop the helper objects will have been reinitialized as well
    2368        3564 :     FEBase & helper_fe = *_holder_fe_lower_helper[elem_dim];
    2369        3564 :     const auto & physical_q_points = helper_fe.get_xyz();
    2370        3564 :     const auto & JxW = helper_fe.get_JxW();
    2371        3564 :     MooseArray<Real> coord;
    2372        3564 :     setCoordinateTransformation(
    2373        3564 :         _current_qrule_lower, physical_q_points, coord, elem->subdomain_id());
    2374        3564 :     _current_lower_d_elem_volume = 0;
    2375       52812 :     for (const auto qp : make_range(_current_qrule_lower->n_points()))
    2376       49248 :       _current_lower_d_elem_volume += JxW[qp] * coord[qp];
    2377        3564 :   }
    2378             : }
    2379             : 
    2380             : void
    2381      284381 : Assembly::reinitNeighborLowerDElem(const Elem * elem)
    2382             : {
    2383             :   mooseAssert(elem->dim() < _mesh_dimension,
    2384             :               "You should be calling reinitNeighborLowerDElem on a lower dimensional element");
    2385             : 
    2386      284381 :   _current_neighbor_lower_d_elem = elem;
    2387             : 
    2388      284381 :   if (!_need_neighbor_lower_d_elem_volume)
    2389      181414 :     return;
    2390             : 
    2391      102967 :   if (_subproblem.getCoordSystem(elem->subdomain_id()) == Moose::CoordinateSystemType::COORD_XYZ)
    2392             :     // We are in a Cartesian coordinate system and we can just use the element volume method which
    2393             :     // has fast computation for certain element types
    2394      102967 :     _current_neighbor_lower_d_elem_volume = elem->volume();
    2395             :   else
    2396             :     // We manually compute the volume taking the curvilinear coordinate transformations into
    2397             :     // account
    2398           0 :     _current_neighbor_lower_d_elem_volume = elementVolume(elem);
    2399             : }
    2400             : 
    2401             : void
    2402      568762 : Assembly::reinitMortarElem(const Elem * elem)
    2403             : {
    2404             :   mooseAssert(elem->dim() == _mesh_dimension - 1,
    2405             :               "You should be calling reinitMortarElem on a lower dimensional element");
    2406             : 
    2407      568762 :   _fe_msm->reinit(elem);
    2408      568762 :   _msm_elem = elem;
    2409             : 
    2410      568762 :   MooseArray<Point> array_q_points;
    2411      568762 :   array_q_points.shallowCopy(const_cast<std::vector<Point> &>(_fe_msm->get_xyz()));
    2412      568762 :   setCoordinateTransformation(_qrule_msm, array_q_points, _coord_msm, elem->subdomain_id());
    2413      568762 : }
    2414             : 
    2415             : void
    2416      165882 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
    2417             :                                    unsigned int neighbor_side,
    2418             :                                    const std::vector<Point> & physical_points)
    2419             : {
    2420      165882 :   unsigned int neighbor_dim = neighbor->dim();
    2421      165882 :   FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
    2422             : 
    2423      165882 :   if (_need_JxW_neighbor)
    2424             :   {
    2425             :     mooseAssert(
    2426             :         physical_points.size() == 1,
    2427             :         "If reinitializing with more than one point, then I am dubious of your use case. Perhaps "
    2428             :         "you are performing a DG type method and you are reinitializing using points from the "
    2429             :         "element face. In such a case your neighbor JxW must have its index order 'match' the "
    2430             :         "element JxW index order, e.g. imagining a vertical 1D face with two quadrature points, "
    2431             :         "if "
    2432             :         "index 0 for elem JxW corresponds to the 'top' quadrature point, then index 0 for "
    2433             :         "neighbor "
    2434             :         "JxW must also correspond to the 'top' quadrature point. And libMesh/MOOSE has no way to "
    2435             :         "guarantee that with multiple quadrature points.");
    2436             : 
    2437      108178 :     _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
    2438             : 
    2439             :     // With a single point our size-1 JxW should just be the element volume
    2440      108178 :     _current_JxW_neighbor.resize(1);
    2441      108178 :     _current_JxW_neighbor[0] = _current_neighbor_side_elem->volume();
    2442             :   }
    2443             : 
    2444      165882 :   reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
    2445      165882 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2446             : 
    2447             :   // Save off the physical points
    2448      165882 :   _current_physical_points = physical_points;
    2449      165882 : }
    2450             : 
    2451             : void
    2452       22720 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
    2453             :                                    const std::vector<Point> & physical_points)
    2454             : {
    2455       22720 :   unsigned int neighbor_dim = neighbor->dim();
    2456       22720 :   FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
    2457             : 
    2458       22720 :   reinitFENeighbor(neighbor, _current_neighbor_ref_points);
    2459       22720 :   reinitNeighbor(neighbor, _current_neighbor_ref_points);
    2460             :   // Save off the physical points
    2461       22720 :   _current_physical_points = physical_points;
    2462       22720 : }
    2463             : 
    2464             : void
    2465       68518 : Assembly::init(const CouplingMatrix * cm)
    2466             : {
    2467       68518 :   _cm = cm;
    2468             : 
    2469       68518 :   unsigned int n_vars = _sys.nVariables();
    2470             : 
    2471       68518 :   _cm_ss_entry.clear();
    2472       68518 :   _cm_sf_entry.clear();
    2473       68518 :   _cm_fs_entry.clear();
    2474       68518 :   _cm_ff_entry.clear();
    2475             : 
    2476       68518 :   auto & vars = _sys.getVariables(_tid);
    2477             : 
    2478       68518 :   _block_diagonal_matrix = true;
    2479      137785 :   for (auto & ivar : vars)
    2480             :   {
    2481       69267 :     auto i = ivar->number();
    2482       69267 :     if (i >= _component_block_diagonal.size())
    2483       69267 :       _component_block_diagonal.resize(i + 1, true);
    2484             : 
    2485       69267 :     auto ivar_start = _cm_ff_entry.size();
    2486      140260 :     for (unsigned int k = 0; k < ivar->count(); ++k)
    2487             :     {
    2488       70993 :       unsigned int iv = i + k;
    2489      166127 :       for (const auto & j : ConstCouplingRow(iv, *_cm))
    2490             :       {
    2491       95134 :         if (_sys.isScalarVariable(j))
    2492             :         {
    2493        1174 :           auto & jvar = _sys.getScalarVariable(_tid, j);
    2494        1174 :           _cm_fs_entry.push_back(std::make_pair(ivar, &jvar));
    2495        1174 :           _block_diagonal_matrix = false;
    2496             :         }
    2497             :         else
    2498             :         {
    2499       93960 :           auto & jvar = _sys.getVariable(_tid, j);
    2500       93960 :           auto pair = std::make_pair(ivar, &jvar);
    2501       93960 :           auto c = ivar_start;
    2502             :           // check if the pair has been pushed or not
    2503       93960 :           bool has_pair = false;
    2504      122610 :           for (; c < _cm_ff_entry.size(); ++c)
    2505       34722 :             if (_cm_ff_entry[c] == pair)
    2506             :             {
    2507        6072 :               has_pair = true;
    2508        6072 :               break;
    2509             :             }
    2510       93960 :           if (!has_pair)
    2511       87888 :             _cm_ff_entry.push_back(pair);
    2512             :           // only set having diagonal matrix to false when ivar and jvar numbers are different
    2513             :           // Note: for array variables, since we save the entire local Jacobian of all components,
    2514             :           //       even there are couplings among components of the same array variable, we still
    2515             :           //       do not set the flag to false.
    2516       93960 :           if (i != jvar.number())
    2517       21249 :             _block_diagonal_matrix = false;
    2518       72711 :           else if (iv != j)
    2519        1718 :             _component_block_diagonal[i] = false;
    2520             :         }
    2521             :       }
    2522             :     }
    2523             :   }
    2524             : 
    2525       68518 :   auto & scalar_vars = _sys.getScalarVariables(_tid);
    2526             : 
    2527       70056 :   for (auto & ivar : scalar_vars)
    2528             :   {
    2529        1538 :     auto i = ivar->number();
    2530        1538 :     if (i >= _component_block_diagonal.size())
    2531        1460 :       _component_block_diagonal.resize(i + 1, true);
    2532             : 
    2533        4394 :     for (const auto & j : ConstCouplingRow(i, *_cm))
    2534        2856 :       if (_sys.isScalarVariable(j))
    2535             :       {
    2536        1682 :         auto & jvar = _sys.getScalarVariable(_tid, j);
    2537        1682 :         _cm_ss_entry.push_back(std::make_pair(ivar, &jvar));
    2538             :       }
    2539             :       else
    2540             :       {
    2541        1174 :         auto & jvar = _sys.getVariable(_tid, j);
    2542        1174 :         _cm_sf_entry.push_back(std::make_pair(ivar, &jvar));
    2543             :       }
    2544             :   }
    2545             : 
    2546       68518 :   if (_block_diagonal_matrix && scalar_vars.size() != 0)
    2547         476 :     _block_diagonal_matrix = false;
    2548             : 
    2549       68518 :   auto num_vector_tags = _residual_vector_tags.size();
    2550             : 
    2551       68518 :   _sub_Re.resize(num_vector_tags);
    2552       68518 :   _sub_Rn.resize(num_vector_tags);
    2553       68518 :   _sub_Rl.resize(num_vector_tags);
    2554      243698 :   for (MooseIndex(_sub_Re) i = 0; i < _sub_Re.size(); i++)
    2555             :   {
    2556      175180 :     _sub_Re[i].resize(n_vars);
    2557      175180 :     _sub_Rn[i].resize(n_vars);
    2558      175180 :     _sub_Rl[i].resize(n_vars);
    2559             :   }
    2560             : 
    2561       68518 :   _cached_residual_values.resize(num_vector_tags);
    2562       68518 :   _cached_residual_rows.resize(num_vector_tags);
    2563             : 
    2564       68518 :   auto num_matrix_tags = _subproblem.numMatrixTags();
    2565             : 
    2566       68518 :   _cached_jacobian_values.resize(num_matrix_tags);
    2567       68518 :   _cached_jacobian_rows.resize(num_matrix_tags);
    2568       68518 :   _cached_jacobian_cols.resize(num_matrix_tags);
    2569             : 
    2570             :   // Element matrices
    2571       68518 :   _sub_Kee.resize(num_matrix_tags);
    2572       68518 :   _sub_Keg.resize(num_matrix_tags);
    2573       68518 :   _sub_Ken.resize(num_matrix_tags);
    2574       68518 :   _sub_Kne.resize(num_matrix_tags);
    2575       68518 :   _sub_Knn.resize(num_matrix_tags);
    2576       68518 :   _sub_Kll.resize(num_matrix_tags);
    2577       68518 :   _sub_Kle.resize(num_matrix_tags);
    2578       68518 :   _sub_Kln.resize(num_matrix_tags);
    2579       68518 :   _sub_Kel.resize(num_matrix_tags);
    2580       68518 :   _sub_Knl.resize(num_matrix_tags);
    2581             : 
    2582       68518 :   _jacobian_block_used.resize(num_matrix_tags);
    2583       68518 :   _jacobian_block_neighbor_used.resize(num_matrix_tags);
    2584       68518 :   _jacobian_block_lower_used.resize(num_matrix_tags);
    2585       68518 :   _jacobian_block_nonlocal_used.resize(num_matrix_tags);
    2586             : 
    2587      207954 :   for (MooseIndex(num_matrix_tags) tag = 0; tag < num_matrix_tags; tag++)
    2588             :   {
    2589      139436 :     _sub_Keg[tag].resize(n_vars);
    2590      139436 :     _sub_Ken[tag].resize(n_vars);
    2591      139436 :     _sub_Kne[tag].resize(n_vars);
    2592      139436 :     _sub_Knn[tag].resize(n_vars);
    2593      139436 :     _sub_Kee[tag].resize(n_vars);
    2594      139436 :     _sub_Kll[tag].resize(n_vars);
    2595      139436 :     _sub_Kle[tag].resize(n_vars);
    2596      139436 :     _sub_Kln[tag].resize(n_vars);
    2597      139436 :     _sub_Kel[tag].resize(n_vars);
    2598      139436 :     _sub_Knl[tag].resize(n_vars);
    2599             : 
    2600      139436 :     _jacobian_block_used[tag].resize(n_vars);
    2601      139436 :     _jacobian_block_neighbor_used[tag].resize(n_vars);
    2602      139436 :     _jacobian_block_lower_used[tag].resize(n_vars);
    2603      139436 :     _jacobian_block_nonlocal_used[tag].resize(n_vars);
    2604      288234 :     for (MooseIndex(n_vars) i = 0; i < n_vars; ++i)
    2605             :     {
    2606      148798 :       if (!_block_diagonal_matrix)
    2607             :       {
    2608       34480 :         _sub_Kee[tag][i].resize(n_vars);
    2609       34480 :         _sub_Keg[tag][i].resize(n_vars);
    2610       34480 :         _sub_Ken[tag][i].resize(n_vars);
    2611       34480 :         _sub_Kne[tag][i].resize(n_vars);
    2612       34480 :         _sub_Knn[tag][i].resize(n_vars);
    2613       34480 :         _sub_Kll[tag][i].resize(n_vars);
    2614       34480 :         _sub_Kle[tag][i].resize(n_vars);
    2615       34480 :         _sub_Kln[tag][i].resize(n_vars);
    2616       34480 :         _sub_Kel[tag][i].resize(n_vars);
    2617       34480 :         _sub_Knl[tag][i].resize(n_vars);
    2618             : 
    2619       34480 :         _jacobian_block_used[tag][i].resize(n_vars);
    2620       34480 :         _jacobian_block_neighbor_used[tag][i].resize(n_vars);
    2621       34480 :         _jacobian_block_lower_used[tag][i].resize(n_vars);
    2622       34480 :         _jacobian_block_nonlocal_used[tag][i].resize(n_vars);
    2623             :       }
    2624             :       else
    2625             :       {
    2626      114318 :         _sub_Kee[tag][i].resize(1);
    2627      114318 :         _sub_Keg[tag][i].resize(1);
    2628      114318 :         _sub_Ken[tag][i].resize(1);
    2629      114318 :         _sub_Kne[tag][i].resize(1);
    2630      114318 :         _sub_Knn[tag][i].resize(1);
    2631      114318 :         _sub_Kll[tag][i].resize(1);
    2632      114318 :         _sub_Kle[tag][i].resize(1);
    2633      114318 :         _sub_Kln[tag][i].resize(1);
    2634      114318 :         _sub_Kel[tag][i].resize(1);
    2635      114318 :         _sub_Knl[tag][i].resize(1);
    2636             : 
    2637      114318 :         _jacobian_block_used[tag][i].resize(1);
    2638      114318 :         _jacobian_block_neighbor_used[tag][i].resize(1);
    2639      114318 :         _jacobian_block_lower_used[tag][i].resize(1);
    2640      114318 :         _jacobian_block_nonlocal_used[tag][i].resize(1);
    2641             :       }
    2642             :     }
    2643             :   }
    2644       68518 : }
    2645             : 
    2646             : void
    2647          81 : Assembly::initNonlocalCoupling()
    2648             : {
    2649          81 :   _cm_nonlocal_entry.clear();
    2650             : 
    2651          81 :   auto & vars = _sys.getVariables(_tid);
    2652             : 
    2653         243 :   for (auto & ivar : vars)
    2654             :   {
    2655         162 :     auto i = ivar->number();
    2656         162 :     auto ivar_start = _cm_nonlocal_entry.size();
    2657         324 :     for (unsigned int k = 0; k < ivar->count(); ++k)
    2658             :     {
    2659         162 :       unsigned int iv = i + k;
    2660         278 :       for (const auto & j : ConstCouplingRow(iv, _nonlocal_cm))
    2661         116 :         if (!_sys.isScalarVariable(j))
    2662             :         {
    2663         116 :           auto & jvar = _sys.getVariable(_tid, j);
    2664         116 :           auto pair = std::make_pair(ivar, &jvar);
    2665         116 :           auto c = ivar_start;
    2666             :           // check if the pair has been pushed or not
    2667         116 :           bool has_pair = false;
    2668         151 :           for (; c < _cm_nonlocal_entry.size(); ++c)
    2669          35 :             if (_cm_nonlocal_entry[c] == pair)
    2670             :             {
    2671           0 :               has_pair = true;
    2672           0 :               break;
    2673             :             }
    2674         116 :           if (!has_pair)
    2675         116 :             _cm_nonlocal_entry.push_back(pair);
    2676             :         }
    2677             :     }
    2678             :   }
    2679          81 : }
    2680             : 
    2681             : void
    2682    91661592 : Assembly::prepareJacobianBlock()
    2683             : {
    2684   239148319 :   for (const auto & it : _cm_ff_entry)
    2685             :   {
    2686   147486727 :     MooseVariableFEBase & ivar = *(it.first);
    2687   147486727 :     MooseVariableFEBase & jvar = *(it.second);
    2688             : 
    2689   147486727 :     unsigned int vi = ivar.number();
    2690   147486727 :     unsigned int vj = jvar.number();
    2691             : 
    2692   147486727 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2693             : 
    2694   445424206 :     for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2695             :     {
    2696   297937479 :       jacobianBlock(vi, vj, LocalDataKey{}, tag)
    2697   297937479 :           .resize(ivar.dofIndices().size() * ivar.count(), jvar.dofIndices().size() * jcount);
    2698   297937479 :       jacobianBlockUsed(tag, vi, vj, false);
    2699             :     }
    2700             :   }
    2701    91661592 : }
    2702             : 
    2703             : void
    2704   467198850 : Assembly::prepareResidual()
    2705             : {
    2706   467198850 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2707   986680944 :   for (const auto & var : vars)
    2708  1946914478 :     for (auto & tag_Re : _sub_Re)
    2709  1427432384 :       tag_Re[var->number()].resize(var->dofIndices().size() * var->count());
    2710   467198850 : }
    2711             : 
    2712             : void
    2713      611878 : Assembly::prepare()
    2714             : {
    2715      611878 :   prepareJacobianBlock();
    2716      611878 :   prepareResidual();
    2717      611878 : }
    2718             : 
    2719             : void
    2720       11792 : Assembly::prepareNonlocal()
    2721             : {
    2722       23876 :   for (const auto & it : _cm_nonlocal_entry)
    2723             :   {
    2724       12084 :     MooseVariableFEBase & ivar = *(it.first);
    2725       12084 :     MooseVariableFEBase & jvar = *(it.second);
    2726             : 
    2727       12084 :     unsigned int vi = ivar.number();
    2728       12084 :     unsigned int vj = jvar.number();
    2729             : 
    2730       12084 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2731             : 
    2732       36252 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2733       36252 :          tag < _jacobian_block_nonlocal_used.size();
    2734             :          tag++)
    2735             :     {
    2736       24168 :       jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
    2737       24168 :           .resize(ivar.dofIndices().size() * ivar.count(), jvar.allDofIndices().size() * jcount);
    2738       24168 :       jacobianBlockNonlocalUsed(tag, vi, vj, false);
    2739             :     }
    2740             :   }
    2741       11792 : }
    2742             : 
    2743             : void
    2744        1625 : Assembly::prepareVariable(MooseVariableFEBase * var)
    2745             : {
    2746        6222 :   for (const auto & it : _cm_ff_entry)
    2747             :   {
    2748        4597 :     MooseVariableFEBase & ivar = *(it.first);
    2749        4597 :     MooseVariableFEBase & jvar = *(it.second);
    2750             : 
    2751        4597 :     unsigned int vi = ivar.number();
    2752        4597 :     unsigned int vj = jvar.number();
    2753             : 
    2754        4597 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2755             : 
    2756        4597 :     if (vi == var->number() || vj == var->number())
    2757             :     {
    2758        9699 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2759             :       {
    2760        6466 :         jacobianBlock(vi, vj, LocalDataKey{}, tag)
    2761        6466 :             .resize(ivar.dofIndices().size() * ivar.count(), jvar.dofIndices().size() * jcount);
    2762        6466 :         jacobianBlockUsed(tag, vi, vj, false);
    2763             :       }
    2764             :     }
    2765             :   }
    2766             : 
    2767        5679 :   for (auto & tag_Re : _sub_Re)
    2768        4054 :     tag_Re[var->number()].resize(var->dofIndices().size() * var->count());
    2769        1625 : }
    2770             : 
    2771             : void
    2772           0 : Assembly::prepareVariableNonlocal(MooseVariableFEBase * var)
    2773             : {
    2774           0 :   for (const auto & it : _cm_nonlocal_entry)
    2775             :   {
    2776           0 :     MooseVariableFEBase & ivar = *(it.first);
    2777           0 :     MooseVariableFEBase & jvar = *(it.second);
    2778             : 
    2779           0 :     unsigned int vi = ivar.number();
    2780           0 :     unsigned int vj = jvar.number();
    2781             : 
    2782           0 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2783             : 
    2784           0 :     if (vi == var->number() || vj == var->number())
    2785             :     {
    2786           0 :       for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2787           0 :            tag < _jacobian_block_nonlocal_used.size();
    2788             :            tag++)
    2789             :       {
    2790           0 :         jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
    2791           0 :             .resize(ivar.dofIndices().size() * ivar.count(), jvar.allDofIndices().size() * jcount);
    2792           0 :         jacobianBlockNonlocalUsed(tag, vi, vj);
    2793             :       }
    2794             :     }
    2795             :   }
    2796           0 : }
    2797             : 
    2798             : void
    2799    31164834 : Assembly::prepareNeighbor()
    2800             : {
    2801    93679704 :   for (const auto & it : _cm_ff_entry)
    2802             :   {
    2803    62514870 :     MooseVariableFEBase & ivar = *(it.first);
    2804    62514870 :     MooseVariableFEBase & jvar = *(it.second);
    2805             : 
    2806    62514870 :     unsigned int vi = ivar.number();
    2807    62514870 :     unsigned int vj = jvar.number();
    2808             : 
    2809    62514870 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2810             : 
    2811   187553034 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    2812   187553034 :          tag < _jacobian_block_neighbor_used.size();
    2813             :          tag++)
    2814             :     {
    2815   125038164 :       jacobianBlockNeighbor(Moose::ElementNeighbor, vi, vj, LocalDataKey{}, tag)
    2816   125038164 :           .resize(ivar.dofIndices().size() * ivar.count(),
    2817   125038164 :                   jvar.dofIndicesNeighbor().size() * jcount);
    2818             : 
    2819   125038164 :       jacobianBlockNeighbor(Moose::NeighborElement, vi, vj, LocalDataKey{}, tag)
    2820   125038164 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2821   125038164 :                   jvar.dofIndices().size() * jcount);
    2822             : 
    2823   125038164 :       jacobianBlockNeighbor(Moose::NeighborNeighbor, vi, vj, LocalDataKey{}, tag)
    2824   125038164 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2825   125038164 :                   jvar.dofIndicesNeighbor().size() * jcount);
    2826             : 
    2827   125038164 :       jacobianBlockNeighborUsed(tag, vi, vj, false);
    2828             :     }
    2829             :   }
    2830             : 
    2831    31164834 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2832    72071598 :   for (const auto & var : vars)
    2833   145811396 :     for (auto & tag_Rn : _sub_Rn)
    2834   104904632 :       tag_Rn[var->number()].resize(var->dofIndicesNeighbor().size() * var->count());
    2835    31164834 : }
    2836             : 
    2837             : void
    2838      326016 : Assembly::prepareLowerD()
    2839             : {
    2840     1387908 :   for (const auto & it : _cm_ff_entry)
    2841             :   {
    2842     1061892 :     MooseVariableFEBase & ivar = *(it.first);
    2843     1061892 :     MooseVariableFEBase & jvar = *(it.second);
    2844             : 
    2845     1061892 :     unsigned int vi = ivar.number();
    2846     1061892 :     unsigned int vj = jvar.number();
    2847             : 
    2848     1061892 :     unsigned int jcount = (vi == vj && _component_block_diagonal[vi]) ? 1 : jvar.count();
    2849             : 
    2850     3185676 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    2851             :          tag++)
    2852             :     {
    2853             :       // To cover all possible cases we should have 9 combinations below for every 2-permutation
    2854             :       // of Lower,Secondary,Primary. However, 4 cases will in general be covered by calls to
    2855             :       // prepare() and prepareNeighbor(). These calls will cover SecondarySecondary
    2856             :       // (ElementElement), SecondaryPrimary (ElementNeighbor), PrimarySecondary (NeighborElement),
    2857             :       // and PrimaryPrimary (NeighborNeighbor). With these covered we only need to prepare the 5
    2858             :       // remaining below
    2859             : 
    2860             :       // derivatives w.r.t. lower dimensional residuals
    2861     2123784 :       jacobianBlockMortar(Moose::LowerLower, vi, vj, LocalDataKey{}, tag)
    2862     2123784 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2863     2123784 :                   jvar.dofIndicesLower().size() * jcount);
    2864             : 
    2865     2123784 :       jacobianBlockMortar(Moose::LowerSecondary, vi, vj, LocalDataKey{}, tag)
    2866     2123784 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2867     2123784 :                   jvar.dofIndices().size() * jvar.count());
    2868             : 
    2869     2123784 :       jacobianBlockMortar(Moose::LowerPrimary, vi, vj, LocalDataKey{}, tag)
    2870     2123784 :           .resize(ivar.dofIndicesLower().size() * ivar.count(),
    2871     2123784 :                   jvar.dofIndicesNeighbor().size() * jvar.count());
    2872             : 
    2873             :       // derivatives w.r.t. interior secondary residuals
    2874     2123784 :       jacobianBlockMortar(Moose::SecondaryLower, vi, vj, LocalDataKey{}, tag)
    2875     2123784 :           .resize(ivar.dofIndices().size() * ivar.count(),
    2876     2123784 :                   jvar.dofIndicesLower().size() * jvar.count());
    2877             : 
    2878             :       // derivatives w.r.t. interior primary residuals
    2879     2123784 :       jacobianBlockMortar(Moose::PrimaryLower, vi, vj, LocalDataKey{}, tag)
    2880     2123784 :           .resize(ivar.dofIndicesNeighbor().size() * ivar.count(),
    2881     2123784 :                   jvar.dofIndicesLower().size() * jvar.count());
    2882             : 
    2883     2123784 :       jacobianBlockLowerUsed(tag, vi, vj, false);
    2884             :     }
    2885             :   }
    2886             : 
    2887      326016 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2888      873818 :   for (const auto & var : vars)
    2889     1726714 :     for (auto & tag_Rl : _sub_Rl)
    2890     1178912 :       tag_Rl[var->number()].resize(var->dofIndicesLower().size() * var->count());
    2891      326016 : }
    2892             : 
    2893             : void
    2894           0 : Assembly::prepareBlock(unsigned int ivar,
    2895             :                        unsigned int jvar,
    2896             :                        const std::vector<dof_id_type> & dof_indices)
    2897             : {
    2898           0 :   const auto & iv = _sys.getVariable(_tid, ivar);
    2899           0 :   const auto & jv = _sys.getVariable(_tid, jvar);
    2900           0 :   const unsigned int ivn = iv.number();
    2901           0 :   const unsigned int jvn = jv.number();
    2902           0 :   const unsigned int icount = iv.count();
    2903           0 :   unsigned int jcount = jv.count();
    2904           0 :   if (ivn == jvn && _component_block_diagonal[ivn])
    2905           0 :     jcount = 1;
    2906             : 
    2907           0 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2908             :   {
    2909           0 :     jacobianBlock(ivn, jvn, LocalDataKey{}, tag)
    2910           0 :         .resize(dof_indices.size() * icount, dof_indices.size() * jcount);
    2911           0 :     jacobianBlockUsed(tag, ivn, jvn, false);
    2912             :   }
    2913             : 
    2914           0 :   for (auto & tag_Re : _sub_Re)
    2915           0 :     tag_Re[ivn].resize(dof_indices.size() * icount);
    2916           0 : }
    2917             : 
    2918             : void
    2919           0 : Assembly::prepareBlockNonlocal(unsigned int ivar,
    2920             :                                unsigned int jvar,
    2921             :                                const std::vector<dof_id_type> & idof_indices,
    2922             :                                const std::vector<dof_id_type> & jdof_indices)
    2923             : {
    2924           0 :   const auto & iv = _sys.getVariable(_tid, ivar);
    2925           0 :   const auto & jv = _sys.getVariable(_tid, jvar);
    2926           0 :   const unsigned int ivn = iv.number();
    2927           0 :   const unsigned int jvn = jv.number();
    2928           0 :   const unsigned int icount = iv.count();
    2929           0 :   unsigned int jcount = jv.count();
    2930           0 :   if (ivn == jvn && _component_block_diagonal[ivn])
    2931           0 :     jcount = 1;
    2932             : 
    2933           0 :   for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    2934           0 :        tag < _jacobian_block_nonlocal_used.size();
    2935             :        tag++)
    2936             :   {
    2937           0 :     jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag)
    2938           0 :         .resize(idof_indices.size() * icount, jdof_indices.size() * jcount);
    2939             : 
    2940           0 :     jacobianBlockNonlocalUsed(tag, ivn, jvn, false);
    2941             :   }
    2942           0 : }
    2943             : 
    2944             : void
    2945     9268171 : Assembly::prepareScalar()
    2946             : {
    2947     9268171 :   const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
    2948     9586334 :   for (const auto & ivar : vars)
    2949             :   {
    2950      318163 :     auto idofs = ivar->dofIndices().size();
    2951             : 
    2952     1261997 :     for (auto & tag_Re : _sub_Re)
    2953      943834 :       tag_Re[ivar->number()].resize(idofs);
    2954             : 
    2955      797326 :     for (const auto & jvar : vars)
    2956             :     {
    2957      479163 :       auto jdofs = jvar->dofIndices().size();
    2958             : 
    2959     1441859 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2960             :       {
    2961      962696 :         jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
    2962      962696 :         jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
    2963             :       }
    2964             :     }
    2965             :   }
    2966     9268171 : }
    2967             : 
    2968             : void
    2969      210721 : Assembly::prepareOffDiagScalar()
    2970             : {
    2971      210721 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    2972      210721 :   const std::vector<MooseVariableScalar *> & scalar_vars = _sys.getScalarVariables(_tid);
    2973             : 
    2974      427326 :   for (const auto & ivar : scalar_vars)
    2975             :   {
    2976      216605 :     auto idofs = ivar->dofIndices().size();
    2977             : 
    2978      533541 :     for (const auto & jvar : vars)
    2979             :     {
    2980      316936 :       auto jdofs = jvar->dofIndices().size() * jvar->count();
    2981      950808 :       for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    2982             :       {
    2983      633872 :         jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
    2984      633872 :         jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
    2985             : 
    2986      633872 :         jacobianBlock(jvar->number(), ivar->number(), LocalDataKey{}, tag).resize(jdofs, idofs);
    2987      633872 :         jacobianBlockUsed(tag, jvar->number(), ivar->number(), false);
    2988             :       }
    2989             :     }
    2990             :   }
    2991      210721 : }
    2992             : 
    2993             : template <typename T>
    2994             : void
    2995   146122035 : Assembly::copyShapes(MooseVariableField<T> & v)
    2996             : {
    2997   146122035 :   phi(v).shallowCopy(v.phi());
    2998   146122035 :   gradPhi(v).shallowCopy(v.gradPhi());
    2999   146122035 :   if (v.computingSecond())
    3000       28970 :     secondPhi(v).shallowCopy(v.secondPhi());
    3001   146122035 : }
    3002             : 
    3003             : void
    3004   146122035 : Assembly::copyShapes(unsigned int var)
    3005             : {
    3006   146122035 :   auto & v = _sys.getVariable(_tid, var);
    3007   146122035 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3008             :   {
    3009   142736076 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3010   142736076 :     copyShapes(v);
    3011             :   }
    3012     3385959 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3013             :   {
    3014     1272769 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3015     1272769 :     copyShapes(v);
    3016             :   }
    3017     2113190 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3018             :   {
    3019     2113190 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3020     2113190 :     copyShapes(v);
    3021     2113190 :     if (v.computingCurl())
    3022       56824 :       curlPhi(v).shallowCopy(v.curlPhi());
    3023     2113190 :     if (v.computingDiv())
    3024      505440 :       divPhi(v).shallowCopy(v.divPhi());
    3025             :   }
    3026             :   else
    3027           0 :     mooseError("Unsupported variable field type!");
    3028   146122035 : }
    3029             : 
    3030             : template <typename T>
    3031             : void
    3032      718881 : Assembly::copyFaceShapes(MooseVariableField<T> & v)
    3033             : {
    3034      718881 :   phiFace(v).shallowCopy(v.phiFace());
    3035      718881 :   gradPhiFace(v).shallowCopy(v.gradPhiFace());
    3036      718881 :   if (v.computingSecond())
    3037        6089 :     secondPhiFace(v).shallowCopy(v.secondPhiFace());
    3038      718881 : }
    3039             : 
    3040             : void
    3041      718881 : Assembly::copyFaceShapes(unsigned int var)
    3042             : {
    3043      718881 :   auto & v = _sys.getVariable(_tid, var);
    3044      718881 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3045             :   {
    3046      637785 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3047      637785 :     copyFaceShapes(v);
    3048             :   }
    3049       81096 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3050             :   {
    3051       14570 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3052       14570 :     copyFaceShapes(v);
    3053             :   }
    3054       66526 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3055             :   {
    3056       66526 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3057       66526 :     copyFaceShapes(v);
    3058       66526 :     if (v.computingCurl())
    3059        7180 :       _vector_curl_phi_face.shallowCopy(v.curlPhi());
    3060       66526 :     if (v.computingDiv())
    3061       21168 :       _vector_div_phi_face.shallowCopy(v.divPhi());
    3062             :   }
    3063             :   else
    3064           0 :     mooseError("Unsupported variable field type!");
    3065      718881 : }
    3066             : 
    3067             : template <typename T>
    3068             : void
    3069      212349 : Assembly::copyNeighborShapes(MooseVariableField<T> & v)
    3070             : {
    3071      212349 :   if (v.usesPhiNeighbor())
    3072             :   {
    3073      212349 :     phiFaceNeighbor(v).shallowCopy(v.phiFaceNeighbor());
    3074      212349 :     phiNeighbor(v).shallowCopy(v.phiNeighbor());
    3075             :   }
    3076      212349 :   if (v.usesGradPhiNeighbor())
    3077             :   {
    3078      212349 :     gradPhiFaceNeighbor(v).shallowCopy(v.gradPhiFaceNeighbor());
    3079      212349 :     gradPhiNeighbor(v).shallowCopy(v.gradPhiNeighbor());
    3080             :   }
    3081      212349 :   if (v.usesSecondPhiNeighbor())
    3082             :   {
    3083           0 :     secondPhiFaceNeighbor(v).shallowCopy(v.secondPhiFaceNeighbor());
    3084           0 :     secondPhiNeighbor(v).shallowCopy(v.secondPhiNeighbor());
    3085             :   }
    3086      212349 : }
    3087             : 
    3088             : void
    3089      212349 : Assembly::copyNeighborShapes(unsigned int var)
    3090             : {
    3091      212349 :   auto & v = _sys.getVariable(_tid, var);
    3092      212349 :   if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
    3093             :   {
    3094      208037 :     auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
    3095      208037 :     copyNeighborShapes(v);
    3096             :   }
    3097        4312 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
    3098             :   {
    3099        4008 :     auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
    3100        4008 :     copyNeighborShapes(v);
    3101             :   }
    3102         304 :   else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
    3103             :   {
    3104         304 :     auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
    3105         304 :     copyNeighborShapes(v);
    3106             :   }
    3107             :   else
    3108           0 :     mooseError("Unsupported variable field type!");
    3109      212349 : }
    3110             : 
    3111             : DenseMatrix<Number> &
    3112   375969046 : Assembly::jacobianBlockNeighbor(
    3113             :     Moose::DGJacobianType type, unsigned int ivar, unsigned int jvar, LocalDataKey, TagID tag)
    3114             : {
    3115   375969046 :   if (type == Moose::ElementElement)
    3116           0 :     jacobianBlockUsed(tag, ivar, jvar, true);
    3117             :   else
    3118   375969046 :     jacobianBlockNeighborUsed(tag, ivar, jvar, true);
    3119             : 
    3120   375969046 :   if (_block_diagonal_matrix)
    3121             :   {
    3122   145249208 :     switch (type)
    3123             :     {
    3124           0 :       default:
    3125             :       case Moose::ElementElement:
    3126           0 :         return _sub_Kee[tag][ivar][0];
    3127    48417780 :       case Moose::ElementNeighbor:
    3128    48417780 :         return _sub_Ken[tag][ivar][0];
    3129    48410708 :       case Moose::NeighborElement:
    3130    48410708 :         return _sub_Kne[tag][ivar][0];
    3131    48420720 :       case Moose::NeighborNeighbor:
    3132    48420720 :         return _sub_Knn[tag][ivar][0];
    3133             :     }
    3134             :   }
    3135             :   else
    3136             :   {
    3137   230719838 :     switch (type)
    3138             :     {
    3139           0 :       default:
    3140             :       case Moose::ElementElement:
    3141           0 :         return _sub_Kee[tag][ivar][jvar];
    3142    76906874 :       case Moose::ElementNeighbor:
    3143    76906874 :         return _sub_Ken[tag][ivar][jvar];
    3144    76906090 :       case Moose::NeighborElement:
    3145    76906090 :         return _sub_Kne[tag][ivar][jvar];
    3146    76906874 :       case Moose::NeighborNeighbor:
    3147    76906874 :         return _sub_Knn[tag][ivar][jvar];
    3148             :     }
    3149             :   }
    3150             : }
    3151             : 
    3152             : DenseMatrix<Number> &
    3153    11423555 : Assembly::jacobianBlockMortar(Moose::ConstraintJacobianType type,
    3154             :                               unsigned int ivar,
    3155             :                               unsigned int jvar,
    3156             :                               LocalDataKey,
    3157             :                               TagID tag)
    3158             : {
    3159    11423555 :   jacobianBlockLowerUsed(tag, ivar, jvar, true);
    3160    11423555 :   if (_block_diagonal_matrix)
    3161             :   {
    3162     2134825 :     switch (type)
    3163             :     {
    3164      364343 :       default:
    3165             :       case Moose::LowerLower:
    3166      364343 :         return _sub_Kll[tag][ivar][0];
    3167      363911 :       case Moose::LowerSecondary:
    3168      363911 :         return _sub_Kle[tag][ivar][0];
    3169      363695 :       case Moose::LowerPrimary:
    3170      363695 :         return _sub_Kln[tag][ivar][0];
    3171      395438 :       case Moose::SecondaryLower:
    3172      395438 :         return _sub_Kel[tag][ivar][0];
    3173       63054 :       case Moose::SecondarySecondary:
    3174       63054 :         return _sub_Kee[tag][ivar][0];
    3175       63054 :       case Moose::SecondaryPrimary:
    3176       63054 :         return _sub_Ken[tag][ivar][0];
    3177      395222 :       case Moose::PrimaryLower:
    3178      395222 :         return _sub_Knl[tag][ivar][0];
    3179       63054 :       case Moose::PrimarySecondary:
    3180       63054 :         return _sub_Kne[tag][ivar][0];
    3181       63054 :       case Moose::PrimaryPrimary:
    3182       63054 :         return _sub_Knn[tag][ivar][0];
    3183             :     }
    3184             :   }
    3185             :   else
    3186             :   {
    3187     9288730 :     switch (type)
    3188             :     {
    3189     1839350 :       default:
    3190             :       case Moose::LowerLower:
    3191     1839350 :         return _sub_Kll[tag][ivar][jvar];
    3192     1838360 :       case Moose::LowerSecondary:
    3193     1838360 :         return _sub_Kle[tag][ivar][jvar];
    3194     1829846 :       case Moose::LowerPrimary:
    3195     1829846 :         return _sub_Kln[tag][ivar][jvar];
    3196     1840628 :       case Moose::SecondaryLower:
    3197     1840628 :         return _sub_Kel[tag][ivar][jvar];
    3198       27108 :       case Moose::SecondarySecondary:
    3199       27108 :         return _sub_Kee[tag][ivar][jvar];
    3200       27108 :       case Moose::SecondaryPrimary:
    3201       27108 :         return _sub_Ken[tag][ivar][jvar];
    3202     1832114 :       case Moose::PrimaryLower:
    3203     1832114 :         return _sub_Knl[tag][ivar][jvar];
    3204       27108 :       case Moose::PrimarySecondary:
    3205       27108 :         return _sub_Kne[tag][ivar][jvar];
    3206       27108 :       case Moose::PrimaryPrimary:
    3207       27108 :         return _sub_Knn[tag][ivar][jvar];
    3208             :     }
    3209             :   }
    3210             : }
    3211             : 
    3212             : void
    3213  1209237545 : Assembly::processLocalResidual(DenseVector<Number> & res_block,
    3214             :                                std::vector<dof_id_type> & dof_indices,
    3215             :                                const std::vector<Real> & scaling_factor,
    3216             :                                bool is_nodal)
    3217             : {
    3218             :   // For an array variable, ndof is the number of dofs of the zero-th component and
    3219             :   // ntdof is the number of dofs of all components.
    3220             :   // For standard or vector variables, ndof will be the same as ntdof.
    3221  1209237545 :   auto ndof = dof_indices.size();
    3222  1209237545 :   auto ntdof = res_block.size();
    3223  1209237545 :   auto count = ntdof / ndof;
    3224             :   mooseAssert(count == scaling_factor.size(), "Inconsistent of number of components");
    3225             :   mooseAssert(count * ndof == ntdof, "Inconsistent of number of components");
    3226  1209237545 :   if (count > 1)
    3227             :   {
    3228             :     // expanding dof indices
    3229     5526913 :     dof_indices.resize(ntdof);
    3230     5526913 :     unsigned int p = 0;
    3231    19243119 :     for (MooseIndex(count) j = 0; j < count; ++j)
    3232    75393490 :       for (MooseIndex(ndof) i = 0; i < ndof; ++i)
    3233             :       {
    3234    61677284 :         dof_indices[p] = dof_indices[i] + (is_nodal ? j : j * ndof);
    3235    61677284 :         res_block(p) *= scaling_factor[j];
    3236    61677284 :         ++p;
    3237             :       }
    3238             :   }
    3239             :   else
    3240             :   {
    3241  1203710632 :     if (scaling_factor[0] != 1.0)
    3242     4991931 :       res_block *= scaling_factor[0];
    3243             :   }
    3244             : 
    3245  1209237545 :   _dof_map.constrain_element_vector(res_block, dof_indices, false);
    3246  1209237545 : }
    3247             : 
    3248             : void
    3249    15247024 : Assembly::addResidualBlock(NumericVector<Number> & residual,
    3250             :                            DenseVector<Number> & res_block,
    3251             :                            const std::vector<dof_id_type> & dof_indices,
    3252             :                            const std::vector<Real> & scaling_factor,
    3253             :                            bool is_nodal)
    3254             : {
    3255    15247024 :   if (dof_indices.size() > 0 && res_block.size())
    3256             :   {
    3257     7826562 :     _temp_dof_indices = dof_indices;
    3258     7826562 :     _tmp_Re = res_block;
    3259     7826562 :     processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor, is_nodal);
    3260     7826562 :     residual.add_vector(_tmp_Re, _temp_dof_indices);
    3261             :   }
    3262    15247024 : }
    3263             : 
    3264             : void
    3265  1284755789 : Assembly::cacheResidualBlock(std::vector<Real> & cached_residual_values,
    3266             :                              std::vector<dof_id_type> & cached_residual_rows,
    3267             :                              DenseVector<Number> & res_block,
    3268             :                              const std::vector<dof_id_type> & dof_indices,
    3269             :                              const std::vector<Real> & scaling_factor,
    3270             :                              bool is_nodal)
    3271             : {
    3272  1284755789 :   if (dof_indices.size() > 0 && res_block.size())
    3273             :   {
    3274  1201410983 :     _temp_dof_indices = dof_indices;
    3275  1201410983 :     _tmp_Re = res_block;
    3276  1201410983 :     processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor, is_nodal);
    3277             : 
    3278  5763221606 :     for (MooseIndex(_tmp_Re) i = 0; i < _tmp_Re.size(); i++)
    3279             :     {
    3280  4561810623 :       cached_residual_values.push_back(_tmp_Re(i));
    3281  4561810623 :       cached_residual_rows.push_back(_temp_dof_indices[i]);
    3282             :     }
    3283             :   }
    3284             : 
    3285  1284755789 :   res_block.zero();
    3286  1284755789 : }
    3287             : 
    3288             : void
    3289           0 : Assembly::setResidualBlock(NumericVector<Number> & residual,
    3290             :                            DenseVector<Number> & res_block,
    3291             :                            const std::vector<dof_id_type> & dof_indices,
    3292             :                            const std::vector<Real> & scaling_factor,
    3293             :                            bool is_nodal)
    3294             : {
    3295           0 :   if (dof_indices.size() > 0)
    3296             :   {
    3297           0 :     std::vector<dof_id_type> di(dof_indices);
    3298           0 :     _tmp_Re = res_block;
    3299           0 :     processLocalResidual(_tmp_Re, di, scaling_factor, is_nodal);
    3300           0 :     residual.insert(_tmp_Re, di);
    3301           0 :   }
    3302           0 : }
    3303             : 
    3304             : void
    3305      883666 : Assembly::addResidual(const VectorTag & vector_tag)
    3306             : {
    3307             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3308             :               "Non-residual tag in Assembly::addResidual");
    3309             : 
    3310      883666 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3311      883666 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3312      883666 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3313     2546396 :   for (const auto & var : vars)
    3314     1662730 :     addResidualBlock(residual,
    3315     1662730 :                      tag_Re[var->number()],
    3316     1662730 :                      var->dofIndices(),
    3317     1662730 :                      var->arrayScalingFactor(),
    3318     1662730 :                      var->isNodal());
    3319      883666 : }
    3320             : 
    3321             : void
    3322      305189 : Assembly::addResidual(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3323             : {
    3324     1188855 :   for (const auto & vector_tag : vector_tags)
    3325      883666 :     if (_sys.hasVector(vector_tag._id))
    3326      883666 :       addResidual(vector_tag);
    3327      305189 : }
    3328             : 
    3329             : void
    3330     5386690 : Assembly::addResidualNeighbor(const VectorTag & vector_tag)
    3331             : {
    3332             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3333             :               "Non-residual tag in Assembly::addResidualNeighbor");
    3334             : 
    3335     5386690 :   auto & tag_Rn = _sub_Rn[vector_tag._type_id];
    3336     5386690 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3337     5386690 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3338    12080020 :   for (const auto & var : vars)
    3339     6693330 :     addResidualBlock(residual,
    3340     6693330 :                      tag_Rn[var->number()],
    3341     6693330 :                      var->dofIndicesNeighbor(),
    3342     6693330 :                      var->arrayScalingFactor(),
    3343     6693330 :                      var->isNodal());
    3344     5386690 : }
    3345             : 
    3346             : void
    3347     2168119 : Assembly::addResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3348             : {
    3349     7554809 :   for (const auto & vector_tag : vector_tags)
    3350     5386690 :     if (_sys.hasVector(vector_tag._id))
    3351     5386690 :       addResidualNeighbor(vector_tag);
    3352     2168119 : }
    3353             : 
    3354             : void
    3355     5348820 : Assembly::addResidualLower(const VectorTag & vector_tag)
    3356             : {
    3357             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3358             :               "Non-residual tag in Assembly::addResidualLower");
    3359             : 
    3360     5348820 :   auto & tag_Rl = _sub_Rl[vector_tag._type_id];
    3361     5348820 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3362     5348820 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3363    11986714 :   for (const auto & var : vars)
    3364     6637894 :     addResidualBlock(residual,
    3365     6637894 :                      tag_Rl[var->number()],
    3366     6637894 :                      var->dofIndicesLower(),
    3367     6637894 :                      var->arrayScalingFactor(),
    3368     6637894 :                      var->isNodal());
    3369     5348820 : }
    3370             : 
    3371             : void
    3372     2144175 : Assembly::addResidualLower(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3373             : {
    3374     7492995 :   for (const auto & vector_tag : vector_tags)
    3375     5348820 :     if (_sys.hasVector(vector_tag._id))
    3376     5348820 :       addResidualLower(vector_tag);
    3377     2144175 : }
    3378             : 
    3379             : // private method, so no key required
    3380             : void
    3381      193649 : Assembly::addResidualScalar(const VectorTag & vector_tag)
    3382             : {
    3383             :   mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
    3384             :               "Non-residual tag in Assembly::addResidualScalar");
    3385             : 
    3386             :   // add the scalar variables residuals
    3387      193649 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3388      193649 :   NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
    3389      193649 :   const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
    3390      446719 :   for (const auto & var : vars)
    3391      253070 :     addResidualBlock(
    3392      253070 :         residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor(), false);
    3393      193649 : }
    3394             : 
    3395             : void
    3396       64576 : Assembly::addResidualScalar(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
    3397             : {
    3398      258225 :   for (const auto & vector_tag : vector_tags)
    3399      193649 :     if (_sys.hasVector(vector_tag._id))
    3400      193649 :       addResidualScalar(vector_tag);
    3401       64576 : }
    3402             : 
    3403             : void
    3404   375216860 : Assembly::cacheResidual(GlobalDataKey, const std::vector<VectorTag> & tags)
    3405             : {
    3406   375216860 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3407   798374885 :   for (const auto & var : vars)
    3408  1576872556 :     for (const auto & vector_tag : tags)
    3409  1153714531 :       if (_sys.hasVector(vector_tag._id))
    3410  1153714531 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3411  1153714531 :                            _cached_residual_rows[vector_tag._type_id],
    3412  1153714531 :                            _sub_Re[vector_tag._type_id][var->number()],
    3413  1153714531 :                            var->dofIndices(),
    3414  1153714531 :                            var->arrayScalingFactor(),
    3415  1153714531 :                            var->isNodal());
    3416   375216860 : }
    3417             : 
    3418             : // private method, so no key required
    3419             : void
    3420   120868769 : Assembly::cacheResidual(dof_id_type dof, Real value, TagID tag_id)
    3421             : {
    3422   120868769 :   const VectorTag & tag = _subproblem.getVectorTag(tag_id);
    3423             : 
    3424   120868769 :   _cached_residual_values[tag._type_id].push_back(value);
    3425   120868769 :   _cached_residual_rows[tag._type_id].push_back(dof);
    3426   120868769 : }
    3427             : 
    3428             : // private method, so no key required
    3429             : void
    3430   120385616 : Assembly::cacheResidual(dof_id_type dof, Real value, const std::set<TagID> & tags)
    3431             : {
    3432   241254385 :   for (auto & tag : tags)
    3433   120868769 :     cacheResidual(dof, value, tag);
    3434   120385616 : }
    3435             : 
    3436             : void
    3437           0 : Assembly::cacheResidualNodes(const DenseVector<Number> & res,
    3438             :                              const std::vector<dof_id_type> & dof_index,
    3439             :                              LocalDataKey,
    3440             :                              TagID tag)
    3441             : {
    3442             :   // Add the residual value and dof_index to cached_residual_values and cached_residual_rows
    3443             :   // respectively.
    3444             :   // This is used by NodalConstraint.C to cache the residual calculated for primary and secondary
    3445             :   // node.
    3446           0 :   const VectorTag & vector_tag = _subproblem.getVectorTag(tag);
    3447           0 :   for (MooseIndex(dof_index) i = 0; i < dof_index.size(); ++i)
    3448             :   {
    3449           0 :     _cached_residual_values[vector_tag._type_id].push_back(res(i));
    3450           0 :     _cached_residual_rows[vector_tag._type_id].push_back(dof_index[i]);
    3451             :   }
    3452           0 : }
    3453             : 
    3454             : void
    3455    38636274 : Assembly::cacheResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & tags)
    3456             : {
    3457    38636274 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3458    89717650 :   for (const auto & var : vars)
    3459   181492814 :     for (const auto & vector_tag : tags)
    3460   130411438 :       if (_sys.hasVector(vector_tag._id))
    3461   130411438 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3462   130411438 :                            _cached_residual_rows[vector_tag._type_id],
    3463   130411438 :                            _sub_Rn[vector_tag._type_id][var->number()],
    3464   130411438 :                            var->dofIndicesNeighbor(),
    3465   130411438 :                            var->arrayScalingFactor(),
    3466   130411438 :                            var->isNodal());
    3467    38636274 : }
    3468             : 
    3469             : void
    3470      194624 : Assembly::cacheResidualLower(GlobalDataKey, const std::vector<VectorTag> & tags)
    3471             : {
    3472      194624 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3473      491896 :   for (const auto & var : vars)
    3474      927092 :     for (const auto & vector_tag : tags)
    3475      629820 :       if (_sys.hasVector(vector_tag._id))
    3476      629820 :         cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
    3477      629820 :                            _cached_residual_rows[vector_tag._type_id],
    3478      629820 :                            _sub_Rl[vector_tag._type_id][var->number()],
    3479      629820 :                            var->dofIndicesLower(),
    3480      629820 :                            var->arrayScalingFactor(),
    3481      629820 :                            var->isNodal());
    3482      194624 : }
    3483             : 
    3484             : void
    3485    57737162 : Assembly::addCachedResiduals(GlobalDataKey, const std::vector<VectorTag> & tags)
    3486             : {
    3487   209091947 :   for (const auto & vector_tag : tags)
    3488             :   {
    3489   151354785 :     if (!_sys.hasVector(vector_tag._id))
    3490             :     {
    3491           0 :       _cached_residual_values[vector_tag._type_id].clear();
    3492           0 :       _cached_residual_rows[vector_tag._type_id].clear();
    3493           0 :       continue;
    3494             :     }
    3495   151354785 :     addCachedResidualDirectly(_sys.getVector(vector_tag._id), GlobalDataKey{}, vector_tag);
    3496             :   }
    3497    57737162 : }
    3498             : 
    3499             : void
    3500       11874 : Assembly::clearCachedResiduals(GlobalDataKey)
    3501             : {
    3502       46473 :   for (const auto & vector_tag : _residual_vector_tags)
    3503       34599 :     clearCachedResiduals(vector_tag);
    3504       11874 : }
    3505             : 
    3506             : // private method, so no key required
    3507             : void
    3508   142770522 : Assembly::clearCachedResiduals(const VectorTag & vector_tag)
    3509             : {
    3510   142770522 :   auto & values = _cached_residual_values[vector_tag._type_id];
    3511   142770522 :   auto & rows = _cached_residual_rows[vector_tag._type_id];
    3512             : 
    3513             :   mooseAssert(values.size() == rows.size(),
    3514             :               "Number of cached residuals and number of rows must match!");
    3515             : 
    3516             :   // Keep track of the largest size so we can use it to reserve and avoid
    3517             :   // as much dynamic allocation as possible
    3518   142770522 :   if (_max_cached_residuals < values.size())
    3519       49107 :     _max_cached_residuals = values.size();
    3520             : 
    3521             :   // Clear both vectors (keeps the capacity the same)
    3522   142770522 :   values.clear();
    3523   142770522 :   rows.clear();
    3524             :   // And then reserve: use 2 as a fudge factor to *really* avoid dynamic allocation!
    3525   142770522 :   values.reserve(_max_cached_residuals * 2);
    3526   142770522 :   rows.reserve(_max_cached_residuals * 2);
    3527   142770522 : }
    3528             : 
    3529             : void
    3530   151377510 : Assembly::addCachedResidualDirectly(NumericVector<Number> & residual,
    3531             :                                     GlobalDataKey,
    3532             :                                     const VectorTag & vector_tag)
    3533             : {
    3534   151377510 :   const auto & values = _cached_residual_values[vector_tag._type_id];
    3535   151377510 :   const auto & rows = _cached_residual_rows[vector_tag._type_id];
    3536             : 
    3537             :   mooseAssert(values.size() == rows.size(),
    3538             :               "Number of cached residuals and number of rows must match!");
    3539             : 
    3540   151377510 :   if (!values.empty())
    3541             :   {
    3542   142735923 :     residual.add_vector(values, rows);
    3543   142735923 :     clearCachedResiduals(vector_tag);
    3544             :   }
    3545   151377510 : }
    3546             : 
    3547             : void
    3548           0 : Assembly::setResidual(NumericVector<Number> & residual, GlobalDataKey, const VectorTag & vector_tag)
    3549             : {
    3550           0 :   auto & tag_Re = _sub_Re[vector_tag._type_id];
    3551           0 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3552           0 :   for (const auto & var : vars)
    3553           0 :     setResidualBlock(residual,
    3554           0 :                      tag_Re[var->number()],
    3555           0 :                      var->dofIndices(),
    3556           0 :                      var->arrayScalingFactor(),
    3557           0 :                      var->isNodal());
    3558           0 : }
    3559             : 
    3560             : void
    3561           0 : Assembly::setResidualNeighbor(NumericVector<Number> & residual,
    3562             :                               GlobalDataKey,
    3563             :                               const VectorTag & vector_tag)
    3564             : {
    3565           0 :   auto & tag_Rn = _sub_Rn[vector_tag._type_id];
    3566           0 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    3567           0 :   for (const auto & var : vars)
    3568           0 :     setResidualBlock(residual,
    3569           0 :                      tag_Rn[var->number()],
    3570           0 :                      var->dofIndicesNeighbor(),
    3571           0 :                      var->arrayScalingFactor(),
    3572           0 :                      var->isNodal());
    3573           0 : }
    3574             : 
    3575             : // private method, so no key required
    3576             : void
    3577      506271 : Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
    3578             :                            DenseMatrix<Number> & jac_block,
    3579             :                            const MooseVariableBase & ivar,
    3580             :                            const MooseVariableBase & jvar,
    3581             :                            const std::vector<dof_id_type> & idof_indices,
    3582             :                            const std::vector<dof_id_type> & jdof_indices)
    3583             : {
    3584      506271 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3585       97516 :     return;
    3586      408755 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3587           0 :     return;
    3588             : 
    3589      408755 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3590             : 
    3591      832954 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3592             :   {
    3593      424199 :     unsigned int iv = ivar.number();
    3594     1025937 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3595             :     {
    3596      601738 :       unsigned int jv = jvar.number();
    3597      601738 :       if (jt < jv || jt >= jv + jvar.count())
    3598      148811 :         continue;
    3599      452927 :       unsigned int j = jt - jv;
    3600             : 
    3601      452927 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3602      452927 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3603      452927 :       auto indof = di.size();
    3604      452927 :       auto jndof = dj.size();
    3605             : 
    3606      452927 :       unsigned int jj = j;
    3607      452927 :       if (iv == jv && _component_block_diagonal[iv])
    3608             :         // here i must be equal to j
    3609      366074 :         jj = 0;
    3610             : 
    3611      452927 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3612      452927 :       if (scaling_factor[i] != 1.0)
    3613        6130 :         sub *= scaling_factor[i];
    3614             : 
    3615             :       // If we're computing the jacobian for automatically scaling variables we do not want
    3616             :       // to constrain the element matrix because it introduces 1s on the diagonal for the
    3617             :       // constrained dofs
    3618      452927 :       if (!_sys.computingScalingJacobian())
    3619      452857 :         _dof_map.constrain_element_matrix(sub, di, dj, false);
    3620             : 
    3621      452927 :       jacobian.add_matrix(sub, di, dj);
    3622      452927 :     }
    3623             :   }
    3624             : }
    3625             : 
    3626             : // private method, so no key required
    3627             : void
    3628    67531561 : Assembly::cacheJacobianBlock(DenseMatrix<Number> & jac_block,
    3629             :                              const MooseVariableBase & ivar,
    3630             :                              const MooseVariableBase & jvar,
    3631             :                              const std::vector<dof_id_type> & idof_indices,
    3632             :                              const std::vector<dof_id_type> & jdof_indices,
    3633             :                              TagID tag)
    3634             : {
    3635    67531561 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3636      432121 :     return;
    3637    67099440 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3638           0 :     return;
    3639    67099440 :   if (!_sys.hasMatrix(tag))
    3640           0 :     return;
    3641             : 
    3642    67099440 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3643             : 
    3644   135148089 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3645             :   {
    3646    68048649 :     unsigned int iv = ivar.number();
    3647   170928844 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3648             :     {
    3649   102880195 :       unsigned int jv = jvar.number();
    3650   102880195 :       if (jt < jv || jt >= jv + jvar.count())
    3651    32000734 :         continue;
    3652    70879461 :       unsigned int j = jt - jv;
    3653             : 
    3654    70879461 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3655    70879461 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3656    70879461 :       auto indof = di.size();
    3657    70879461 :       auto jndof = dj.size();
    3658             : 
    3659    70879461 :       unsigned int jj = j;
    3660    70879461 :       if (iv == jv && _component_block_diagonal[iv])
    3661             :         // here i must be equal to j
    3662    56110487 :         jj = 0;
    3663             : 
    3664    70879461 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3665    70879461 :       if (scaling_factor[i] != 1.0)
    3666     1805486 :         sub *= scaling_factor[i];
    3667             : 
    3668             :       // If we're computing the jacobian for automatically scaling variables we do not want
    3669             :       // to constrain the element matrix because it introduces 1s on the diagonal for the
    3670             :       // constrained dofs
    3671    70879461 :       if (!_sys.computingScalingJacobian())
    3672    70656104 :         _dof_map.constrain_element_matrix(sub, di, dj, false);
    3673             : 
    3674   384243830 :       for (MooseIndex(di) i = 0; i < di.size(); i++)
    3675  1893434911 :         for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3676             :         {
    3677  1580070542 :           _cached_jacobian_values[tag].push_back(sub(i, j));
    3678  1580070542 :           _cached_jacobian_rows[tag].push_back(di[i]);
    3679  1580070542 :           _cached_jacobian_cols[tag].push_back(dj[j]);
    3680             :         }
    3681    70879461 :     }
    3682             :   }
    3683             : 
    3684    67099440 :   jac_block.zero();
    3685             : }
    3686             : 
    3687             : // private method, so no key required
    3688             : void
    3689         854 : Assembly::cacheJacobianBlockNonzero(DenseMatrix<Number> & jac_block,
    3690             :                                     const MooseVariableBase & ivar,
    3691             :                                     const MooseVariableBase & jvar,
    3692             :                                     const std::vector<dof_id_type> & idof_indices,
    3693             :                                     const std::vector<dof_id_type> & jdof_indices,
    3694             :                                     TagID tag)
    3695             : {
    3696         854 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    3697           0 :     return;
    3698         854 :   if (jac_block.n() == 0 || jac_block.m() == 0)
    3699           0 :     return;
    3700         854 :   if (!_sys.hasMatrix(tag))
    3701           0 :     return;
    3702             : 
    3703         854 :   auto & scaling_factor = ivar.arrayScalingFactor();
    3704             : 
    3705        1708 :   for (unsigned int i = 0; i < ivar.count(); ++i)
    3706             :   {
    3707         854 :     unsigned int iv = ivar.number();
    3708        2506 :     for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
    3709             :     {
    3710        1652 :       unsigned int jv = jvar.number();
    3711        1652 :       if (jt < jv || jt >= jv + jvar.count())
    3712         798 :         continue;
    3713         854 :       unsigned int j = jt - jv;
    3714             : 
    3715         854 :       auto di = ivar.componentDofIndices(idof_indices, i);
    3716         854 :       auto dj = jvar.componentDofIndices(jdof_indices, j);
    3717         854 :       auto indof = di.size();
    3718         854 :       auto jndof = dj.size();
    3719             : 
    3720         854 :       unsigned int jj = j;
    3721         854 :       if (iv == jv && _component_block_diagonal[iv])
    3722             :         // here i must be equal to j
    3723         208 :         jj = 0;
    3724             : 
    3725         854 :       auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
    3726         854 :       if (scaling_factor[i] != 1.0)
    3727         376 :         sub *= scaling_factor[i];
    3728             : 
    3729         854 :       _dof_map.constrain_element_matrix(sub, di, dj, false);
    3730             : 
    3731        4222 :       for (MooseIndex(di) i = 0; i < di.size(); i++)
    3732      261872 :         for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3733      258504 :           if (sub(i, j) != 0.0) // no storage allocated for unimplemented jacobian terms,
    3734             :                                 // maintaining maximum sparsity possible
    3735             :           {
    3736       34856 :             _cached_jacobian_values[tag].push_back(sub(i, j));
    3737       34856 :             _cached_jacobian_rows[tag].push_back(di[i]);
    3738       34856 :             _cached_jacobian_cols[tag].push_back(dj[j]);
    3739             :           }
    3740         854 :     }
    3741             :   }
    3742             : 
    3743         854 :   jac_block.zero();
    3744             : }
    3745             : 
    3746             : void
    3747     6719819 : Assembly::cacheJacobianBlock(DenseMatrix<Number> & jac_block,
    3748             :                              const std::vector<dof_id_type> & idof_indices,
    3749             :                              const std::vector<dof_id_type> & jdof_indices,
    3750             :                              Real scaling_factor,
    3751             :                              LocalDataKey,
    3752             :                              TagID tag)
    3753             : {
    3754             :   // Only cache data when the matrix exists
    3755    13417991 :   if ((idof_indices.size() > 0) && (jdof_indices.size() > 0) && jac_block.n() && jac_block.m() &&
    3756     6698172 :       _sys.hasMatrix(tag))
    3757             :   {
    3758     6698172 :     std::vector<dof_id_type> di(idof_indices);
    3759     6698172 :     std::vector<dof_id_type> dj(jdof_indices);
    3760             : 
    3761             :     // If we're computing the jacobian for automatically scaling variables we do not want to
    3762             :     // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    3763             :     // dofs
    3764     6698172 :     if (!_sys.computingScalingJacobian())
    3765     6698172 :       _dof_map.constrain_element_matrix(jac_block, di, dj, false);
    3766             : 
    3767     6698172 :     if (scaling_factor != 1.0)
    3768        8473 :       jac_block *= scaling_factor;
    3769             : 
    3770    39628885 :     for (MooseIndex(di) i = 0; i < di.size(); i++)
    3771   217803943 :       for (MooseIndex(dj) j = 0; j < dj.size(); j++)
    3772             :       {
    3773   184873230 :         _cached_jacobian_values[tag].push_back(jac_block(i, j));
    3774   184873230 :         _cached_jacobian_rows[tag].push_back(di[i]);
    3775   184873230 :         _cached_jacobian_cols[tag].push_back(dj[j]);
    3776             :       }
    3777     6698172 :   }
    3778     6719819 :   jac_block.zero();
    3779     6719819 : }
    3780             : 
    3781             : Real
    3782           0 : Assembly::elementVolume(const Elem * elem) const
    3783             : {
    3784           0 :   FEType fe_type(elem->default_order(), LAGRANGE);
    3785           0 :   std::unique_ptr<FEBase> fe(FEBase::build(elem->dim(), fe_type));
    3786             : 
    3787             :   // references to the quadrature points and weights
    3788           0 :   const std::vector<Real> & JxW = fe->get_JxW();
    3789           0 :   const std::vector<Point> & q_points = fe->get_xyz();
    3790             : 
    3791             :   // The default quadrature rule should integrate the mass matrix,
    3792             :   // thus it should be plenty to compute the volume
    3793           0 :   QGauss qrule(elem->dim(), fe_type.default_quadrature_order());
    3794           0 :   fe->attach_quadrature_rule(&qrule);
    3795           0 :   fe->reinit(elem);
    3796             : 
    3797             :   // perform a sanity check to ensure that size of quad rule and size of q_points is
    3798             :   // identical
    3799             :   mooseAssert(qrule.n_points() == q_points.size(),
    3800             :               "The number of points in the quadrature rule doesn't match the number of passed-in "
    3801             :               "points in Assembly::setCoordinateTransformation");
    3802             : 
    3803             :   // compute the coordinate transformation
    3804           0 :   Real vol = 0;
    3805           0 :   for (unsigned int qp = 0; qp < qrule.n_points(); ++qp)
    3806             :   {
    3807             :     Real coord;
    3808           0 :     coordTransformFactor(_subproblem, elem->subdomain_id(), q_points[qp], coord);
    3809           0 :     vol += JxW[qp] * coord;
    3810             :   }
    3811           0 :   return vol;
    3812           0 : }
    3813             : 
    3814             : void
    3815     4232310 : Assembly::addCachedJacobian(GlobalDataKey)
    3816             : {
    3817             : #ifndef NDEBUG
    3818             :   if (!_subproblem.checkNonlocalCouplingRequirement())
    3819             :   {
    3820             :     mooseAssert(_cached_jacobian_rows.size() == _cached_jacobian_cols.size(),
    3821             :                 "Error: Cached data sizes MUST be the same!");
    3822             :     for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3823             :       mooseAssert(_cached_jacobian_rows[i].size() == _cached_jacobian_cols[i].size(),
    3824             :                   "Error: Cached data sizes MUST be the same for a given tag!");
    3825             :   }
    3826             : #endif
    3827             : 
    3828    12774073 :   for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3829     8541767 :     if (_sys.hasMatrix(i))
    3830  2010739146 :       for (MooseIndex(_cached_jacobian_rows[i]) j = 0; j < _cached_jacobian_rows[i].size(); j++)
    3831  4012979504 :         _sys.getMatrix(i).add(_cached_jacobian_rows[i][j],
    3832  2006489752 :                               _cached_jacobian_cols[i][j],
    3833  2006489752 :                               _cached_jacobian_values[i][j]);
    3834             : 
    3835    12774069 :   for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
    3836             :   {
    3837     8541763 :     if (!_sys.hasMatrix(i))
    3838     4292369 :       continue;
    3839             : 
    3840     4249394 :     if (_max_cached_jacobians < _cached_jacobian_values[i].size())
    3841       51079 :       _max_cached_jacobians = _cached_jacobian_values[i].size();
    3842             : 
    3843             :     // Try to be more efficient from now on
    3844             :     // The 2 is just a fudge factor to keep us from having to grow the vector during assembly
    3845     4249394 :     _cached_jacobian_values[i].clear();
    3846     4249394 :     _cached_jacobian_values[i].reserve(_max_cached_jacobians * 2);
    3847             : 
    3848     4249394 :     _cached_jacobian_rows[i].clear();
    3849     4249394 :     _cached_jacobian_rows[i].reserve(_max_cached_jacobians * 2);
    3850             : 
    3851     4249394 :     _cached_jacobian_cols[i].clear();
    3852     4249394 :     _cached_jacobian_cols[i].reserve(_max_cached_jacobians * 2);
    3853             :   }
    3854     4232306 : }
    3855             : 
    3856             : inline void
    3857      117000 : Assembly::addJacobianCoupledVarPair(const MooseVariableBase & ivar, const MooseVariableBase & jvar)
    3858             : {
    3859      117000 :   auto i = ivar.number();
    3860      117000 :   auto j = jvar.number();
    3861      352188 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    3862      235188 :     if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
    3863       62502 :       addJacobianBlock(_sys.getMatrix(tag),
    3864      125004 :                        jacobianBlock(i, j, LocalDataKey{}, tag),
    3865             :                        ivar,
    3866             :                        jvar,
    3867       62502 :                        ivar.dofIndices(),
    3868       62502 :                        jvar.dofIndices());
    3869      117000 : }
    3870             : 
    3871             : void
    3872       42272 : Assembly::addJacobian(GlobalDataKey)
    3873             : {
    3874      124590 :   for (const auto & it : _cm_ff_entry)
    3875       82318 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3876             : 
    3877       42272 :   for (const auto & it : _cm_sf_entry)
    3878           0 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3879             : 
    3880       42272 :   for (const auto & it : _cm_fs_entry)
    3881           0 :     addJacobianCoupledVarPair(*it.first, *it.second);
    3882       42272 : }
    3883             : 
    3884             : void
    3885           0 : Assembly::addJacobianNonlocal(GlobalDataKey)
    3886             : {
    3887           0 :   for (const auto & it : _cm_nonlocal_entry)
    3888             :   {
    3889           0 :     auto ivar = it.first;
    3890           0 :     auto jvar = it.second;
    3891           0 :     auto i = ivar->number();
    3892           0 :     auto j = jvar->number();
    3893           0 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    3894           0 :          tag < _jacobian_block_nonlocal_used.size();
    3895             :          tag++)
    3896           0 :       if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
    3897           0 :         addJacobianBlock(_sys.getMatrix(tag),
    3898           0 :                          jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
    3899             :                          *ivar,
    3900             :                          *jvar,
    3901           0 :                          ivar->dofIndices(),
    3902             :                          jvar->allDofIndices());
    3903             :   }
    3904           0 : }
    3905             : 
    3906             : void
    3907        9087 : Assembly::addJacobianNeighbor(GlobalDataKey)
    3908             : {
    3909       42579 :   for (const auto & it : _cm_ff_entry)
    3910             :   {
    3911       33492 :     auto ivar = it.first;
    3912       33492 :     auto jvar = it.second;
    3913       33492 :     auto i = ivar->number();
    3914       33492 :     auto j = jvar->number();
    3915      100908 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    3916      100908 :          tag < _jacobian_block_neighbor_used.size();
    3917             :          tag++)
    3918       67416 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    3919             :       {
    3920       25192 :         addJacobianBlock(_sys.getMatrix(tag),
    3921       25192 :                          jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    3922             :                          *ivar,
    3923             :                          *jvar,
    3924       25192 :                          ivar->dofIndices(),
    3925       25192 :                          jvar->dofIndicesNeighbor());
    3926             : 
    3927       25192 :         addJacobianBlock(_sys.getMatrix(tag),
    3928       25192 :                          jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    3929             :                          *ivar,
    3930             :                          *jvar,
    3931       25192 :                          ivar->dofIndicesNeighbor(),
    3932       25192 :                          jvar->dofIndices());
    3933             : 
    3934       25192 :         addJacobianBlock(_sys.getMatrix(tag),
    3935       50384 :                          jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    3936             :                          *ivar,
    3937             :                          *jvar,
    3938       25192 :                          ivar->dofIndicesNeighbor(),
    3939       25192 :                          jvar->dofIndicesNeighbor());
    3940             :       }
    3941             :   }
    3942        9087 : }
    3943             : 
    3944             : void
    3945      126338 : Assembly::addJacobianNeighborLowerD(GlobalDataKey)
    3946             : {
    3947      328513 :   for (const auto & it : _cm_ff_entry)
    3948             :   {
    3949      202175 :     auto ivar = it.first;
    3950      202175 :     auto jvar = it.second;
    3951      202175 :     auto i = ivar->number();
    3952      202175 :     auto j = jvar->number();
    3953      612249 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    3954             :          tag++)
    3955      410074 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    3956             :       {
    3957        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3958        8814 :                          jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    3959             :                          *ivar,
    3960             :                          *jvar,
    3961        8814 :                          ivar->dofIndicesLower(),
    3962        8814 :                          jvar->dofIndicesLower());
    3963             : 
    3964        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3965        8814 :                          jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    3966             :                          *ivar,
    3967             :                          *jvar,
    3968        8814 :                          ivar->dofIndicesLower(),
    3969        8814 :                          jvar->dofIndicesNeighbor());
    3970             : 
    3971        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3972        8814 :                          jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
    3973             :                          *ivar,
    3974             :                          *jvar,
    3975        8814 :                          ivar->dofIndicesLower(),
    3976        8814 :                          jvar->dofIndices());
    3977             : 
    3978        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3979        8814 :                          jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    3980             :                          *ivar,
    3981             :                          *jvar,
    3982        8814 :                          ivar->dofIndicesNeighbor(),
    3983        8814 :                          jvar->dofIndicesLower());
    3984             : 
    3985        8814 :         addJacobianBlock(_sys.getMatrix(tag),
    3986       17628 :                          jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
    3987             :                          *ivar,
    3988             :                          *jvar,
    3989        8814 :                          ivar->dofIndices(),
    3990        8814 :                          jvar->dofIndicesLower());
    3991             :       }
    3992             : 
    3993      612249 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    3994      612249 :          tag < _jacobian_block_neighbor_used.size();
    3995             :          tag++)
    3996      410074 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    3997             :       {
    3998      100499 :         addJacobianBlock(_sys.getMatrix(tag),
    3999      100499 :                          jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    4000             :                          *ivar,
    4001             :                          *jvar,
    4002      100499 :                          ivar->dofIndices(),
    4003      100499 :                          jvar->dofIndicesNeighbor());
    4004             : 
    4005      100499 :         addJacobianBlock(_sys.getMatrix(tag),
    4006      100499 :                          jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    4007             :                          *ivar,
    4008             :                          *jvar,
    4009      100499 :                          ivar->dofIndicesNeighbor(),
    4010      100499 :                          jvar->dofIndices());
    4011             : 
    4012      100499 :         addJacobianBlock(_sys.getMatrix(tag),
    4013      200998 :                          jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    4014             :                          *ivar,
    4015             :                          *jvar,
    4016      100499 :                          ivar->dofIndicesNeighbor(),
    4017      100499 :                          jvar->dofIndicesNeighbor());
    4018             :       }
    4019             :   }
    4020      126338 : }
    4021             : 
    4022             : void
    4023        5436 : Assembly::addJacobianLowerD(GlobalDataKey)
    4024             : {
    4025       47010 :   for (const auto & it : _cm_ff_entry)
    4026             :   {
    4027       41574 :     auto ivar = it.first;
    4028       41574 :     auto jvar = it.second;
    4029       41574 :     auto i = ivar->number();
    4030       41574 :     auto j = jvar->number();
    4031      124722 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    4032             :          tag++)
    4033       83148 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    4034             :       {
    4035        7542 :         addJacobianBlock(_sys.getMatrix(tag),
    4036        7542 :                          jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    4037             :                          *ivar,
    4038             :                          *jvar,
    4039        7542 :                          ivar->dofIndicesLower(),
    4040        7542 :                          jvar->dofIndicesLower());
    4041             : 
    4042        7542 :         addJacobianBlock(_sys.getMatrix(tag),
    4043        7542 :                          jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    4044             :                          *ivar,
    4045             :                          *jvar,
    4046        7542 :                          ivar->dofIndicesLower(),
    4047        7542 :                          jvar->dofIndices());
    4048             : 
    4049        7542 :         addJacobianBlock(_sys.getMatrix(tag),
    4050       15084 :                          jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    4051             :                          *ivar,
    4052             :                          *jvar,
    4053        7542 :                          ivar->dofIndices(),
    4054        7542 :                          jvar->dofIndicesLower());
    4055             :       }
    4056             :   }
    4057        5436 : }
    4058             : 
    4059             : void
    4060    57010405 : Assembly::cacheJacobian(GlobalDataKey)
    4061             : {
    4062   143146486 :   for (const auto & it : _cm_ff_entry)
    4063    86136081 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4064             : 
    4065    57292430 :   for (const auto & it : _cm_fs_entry)
    4066      282025 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4067             : 
    4068    57292430 :   for (const auto & it : _cm_sf_entry)
    4069      282025 :     cacheJacobianCoupledVarPair(*it.first, *it.second);
    4070    57010405 : }
    4071             : 
    4072             : // private method, so no key required
    4073             : void
    4074    86700131 : Assembly::cacheJacobianCoupledVarPair(const MooseVariableBase & ivar,
    4075             :                                       const MooseVariableBase & jvar)
    4076             : {
    4077    86700131 :   auto i = ivar.number();
    4078    86700131 :   auto j = jvar.number();
    4079   262326126 :   for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
    4080   175625995 :     if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
    4081    67069078 :       cacheJacobianBlock(jacobianBlock(i, j, LocalDataKey{}, tag),
    4082             :                          ivar,
    4083             :                          jvar,
    4084    67069078 :                          ivar.dofIndices(),
    4085    67069078 :                          jvar.dofIndices(),
    4086             :                          tag);
    4087    86700131 : }
    4088             : 
    4089             : void
    4090        5880 : Assembly::cacheJacobianNonlocal(GlobalDataKey)
    4091             : {
    4092       11900 :   for (const auto & it : _cm_nonlocal_entry)
    4093             :   {
    4094        6020 :     auto ivar = it.first;
    4095        6020 :     auto jvar = it.second;
    4096        6020 :     auto i = ivar->number();
    4097        6020 :     auto j = jvar->number();
    4098       18060 :     for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
    4099       18060 :          tag < _jacobian_block_nonlocal_used.size();
    4100             :          tag++)
    4101       12040 :       if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
    4102        1708 :         cacheJacobianBlockNonzero(jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
    4103             :                                   *ivar,
    4104             :                                   *jvar,
    4105         854 :                                   ivar->dofIndices(),
    4106             :                                   jvar->allDofIndices(),
    4107             :                                   tag);
    4108             :   }
    4109        5880 : }
    4110             : 
    4111             : void
    4112       10576 : Assembly::cacheJacobianNeighbor(GlobalDataKey)
    4113             : {
    4114       36944 :   for (const auto & it : _cm_ff_entry)
    4115             :   {
    4116       26368 :     auto ivar = it.first;
    4117       26368 :     auto jvar = it.second;
    4118       26368 :     auto i = ivar->number();
    4119       26368 :     auto j = jvar->number();
    4120             : 
    4121       79104 :     for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
    4122       79104 :          tag < _jacobian_block_neighbor_used.size();
    4123             :          tag++)
    4124       52736 :       if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
    4125             :       {
    4126        8784 :         cacheJacobianBlock(jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
    4127             :                            *ivar,
    4128             :                            *jvar,
    4129        8784 :                            ivar->dofIndices(),
    4130        8784 :                            jvar->dofIndicesNeighbor(),
    4131             :                            tag);
    4132        8784 :         cacheJacobianBlock(jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
    4133             :                            *ivar,
    4134             :                            *jvar,
    4135        8784 :                            ivar->dofIndicesNeighbor(),
    4136        8784 :                            jvar->dofIndices(),
    4137             :                            tag);
    4138        8784 :         cacheJacobianBlock(
    4139       17568 :             jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
    4140             :             *ivar,
    4141             :             *jvar,
    4142        8784 :             ivar->dofIndicesNeighbor(),
    4143        8784 :             jvar->dofIndicesNeighbor(),
    4144             :             tag);
    4145             :       }
    4146             :   }
    4147       10576 : }
    4148             : 
    4149             : void
    4150       91709 : Assembly::cacheJacobianMortar(GlobalDataKey)
    4151             : {
    4152      368683 :   for (const auto & it : _cm_ff_entry)
    4153             :   {
    4154      276974 :     auto ivar = it.first;
    4155      276974 :     auto jvar = it.second;
    4156      276974 :     auto i = ivar->number();
    4157      276974 :     auto j = jvar->number();
    4158      830922 :     for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
    4159             :          tag++)
    4160      553948 :       if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
    4161             :       {
    4162       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
    4163             :                            *ivar,
    4164             :                            *jvar,
    4165       48459 :                            ivar->dofIndicesLower(),
    4166       48459 :                            jvar->dofIndicesLower(),
    4167             :                            tag);
    4168             : 
    4169       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
    4170             :                            *ivar,
    4171             :                            *jvar,
    4172       48459 :                            ivar->dofIndicesLower(),
    4173       48459 :                            jvar->dofIndices(),
    4174             :                            tag);
    4175             : 
    4176       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
    4177             :                            *ivar,
    4178             :                            *jvar,
    4179       48459 :                            ivar->dofIndicesLower(),
    4180       48459 :                            jvar->dofIndicesNeighbor(),
    4181             :                            tag);
    4182             : 
    4183       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
    4184             :                            *ivar,
    4185             :                            *jvar,
    4186       48459 :                            ivar->dofIndices(),
    4187       48459 :                            jvar->dofIndicesLower(),
    4188             :                            tag);
    4189             : 
    4190       48459 :         cacheJacobianBlock(
    4191       48459 :             jacobianBlockMortar(Moose::SecondarySecondary, i, j, LocalDataKey{}, tag),
    4192             :             *ivar,
    4193             :             *jvar,
    4194       48459 :             ivar->dofIndices(),
    4195       48459 :             jvar->dofIndices(),
    4196             :             tag);
    4197             : 
    4198       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryPrimary, i, j, LocalDataKey{}, tag),
    4199             :                            *ivar,
    4200             :                            *jvar,
    4201       48459 :                            ivar->dofIndices(),
    4202       48459 :                            jvar->dofIndicesNeighbor(),
    4203             :                            tag);
    4204             : 
    4205       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
    4206             :                            *ivar,
    4207             :                            *jvar,
    4208       48459 :                            ivar->dofIndicesNeighbor(),
    4209       48459 :                            jvar->dofIndicesLower(),
    4210             :                            tag);
    4211             : 
    4212       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimarySecondary, i, j, LocalDataKey{}, tag),
    4213             :                            *ivar,
    4214             :                            *jvar,
    4215       48459 :                            ivar->dofIndicesNeighbor(),
    4216       48459 :                            jvar->dofIndices(),
    4217             :                            tag);
    4218             : 
    4219       48459 :         cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryPrimary, i, j, LocalDataKey{}, tag),
    4220             :                            *ivar,
    4221             :                            *jvar,
    4222       48459 :                            ivar->dofIndicesNeighbor(),
    4223       48459 :                            jvar->dofIndicesNeighbor(),
    4224             :                            tag);
    4225             :       }
    4226             :   }
    4227       91709 : }
    4228             : 
    4229             : void
    4230       69972 : Assembly::addJacobianBlockTags(SparseMatrix<Number> & jacobian,
    4231             :                                unsigned int ivar,
    4232             :                                unsigned int jvar,
    4233             :                                const DofMap & dof_map,
    4234             :                                std::vector<dof_id_type> & dof_indices,
    4235             :                                GlobalDataKey,
    4236             :                                const std::set<TagID> & tags)
    4237             : {
    4238      177660 :   for (auto tag : tags)
    4239      107688 :     addJacobianBlock(jacobian, ivar, jvar, dof_map, dof_indices, GlobalDataKey{}, tag);
    4240       69972 : }
    4241             : 
    4242             : void
    4243      107688 : Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
    4244             :                            unsigned int ivar,
    4245             :                            unsigned int jvar,
    4246             :                            const DofMap & dof_map,
    4247             :                            std::vector<dof_id_type> & dof_indices,
    4248             :                            GlobalDataKey,
    4249             :                            TagID tag)
    4250             : {
    4251      107688 :   if (dof_indices.size() == 0)
    4252           0 :     return;
    4253      107688 :   if (!(*_cm)(ivar, jvar))
    4254           0 :     return;
    4255             : 
    4256      107688 :   auto & iv = _sys.getVariable(_tid, ivar);
    4257      107688 :   auto & jv = _sys.getVariable(_tid, jvar);
    4258      107688 :   auto & scaling_factor = iv.arrayScalingFactor();
    4259             : 
    4260      107688 :   const unsigned int ivn = iv.number();
    4261      107688 :   const unsigned int jvn = jv.number();
    4262      107688 :   auto & ke = jacobianBlock(ivn, jvn, LocalDataKey{}, tag);
    4263             : 
    4264             :   // It is guaranteed by design iv.number <= ivar since iv is obtained
    4265             :   // through SystemBase::getVariable with ivar.
    4266             :   // Most of times ivar will just be equal to iv.number except for array variables,
    4267             :   // where ivar could be a number for a component of an array variable but calling
    4268             :   // getVariable will return the array variable that has the number of the 0th component.
    4269             :   // It is the same for jvar.
    4270      107688 :   const unsigned int i = ivar - ivn;
    4271      107688 :   const unsigned int j = jvar - jvn;
    4272             : 
    4273             :   // DoF indices are independently given
    4274      107688 :   auto di = dof_indices;
    4275      107688 :   auto dj = dof_indices;
    4276             : 
    4277      107688 :   auto indof = di.size();
    4278      107688 :   auto jndof = dj.size();
    4279             : 
    4280      107688 :   unsigned int jj = j;
    4281      107688 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4282      102608 :     jj = 0;
    4283             : 
    4284      107688 :   auto sub = ke.sub_matrix(i * indof, indof, jj * jndof, jndof);
    4285             :   // If we're computing the jacobian for automatically scaling variables we do not want to
    4286             :   // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    4287             :   // dofs
    4288      107688 :   if (!_sys.computingScalingJacobian())
    4289      107688 :     dof_map.constrain_element_matrix(sub, di, dj, false);
    4290             : 
    4291      107688 :   if (scaling_factor[i] != 1.0)
    4292           0 :     sub *= scaling_factor[i];
    4293             : 
    4294      107688 :   jacobian.add_matrix(sub, di, dj);
    4295      107688 : }
    4296             : 
    4297             : void
    4298           0 : Assembly::addJacobianBlockNonlocal(SparseMatrix<Number> & jacobian,
    4299             :                                    const unsigned int ivar,
    4300             :                                    const unsigned int jvar,
    4301             :                                    const DofMap & dof_map,
    4302             :                                    const std::vector<dof_id_type> & idof_indices,
    4303             :                                    const std::vector<dof_id_type> & jdof_indices,
    4304             :                                    GlobalDataKey,
    4305             :                                    const TagID tag)
    4306             : {
    4307           0 :   if (idof_indices.size() == 0 || jdof_indices.size() == 0)
    4308           0 :     return;
    4309           0 :   if (jacobian.n() == 0 || jacobian.m() == 0)
    4310           0 :     return;
    4311           0 :   if (!(*_cm)(ivar, jvar))
    4312           0 :     return;
    4313             : 
    4314           0 :   auto & iv = _sys.getVariable(_tid, ivar);
    4315           0 :   auto & jv = _sys.getVariable(_tid, jvar);
    4316           0 :   auto & scaling_factor = iv.arrayScalingFactor();
    4317             : 
    4318           0 :   const unsigned int ivn = iv.number();
    4319           0 :   const unsigned int jvn = jv.number();
    4320           0 :   auto & keg = jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag);
    4321             : 
    4322             :   // It is guaranteed by design iv.number <= ivar since iv is obtained
    4323             :   // through SystemBase::getVariable with ivar.
    4324             :   // Most of times ivar will just be equal to iv.number except for array variables,
    4325             :   // where ivar could be a number for a component of an array variable but calling
    4326             :   // getVariable will return the array variable that has the number of the 0th component.
    4327             :   // It is the same for jvar.
    4328           0 :   const unsigned int i = ivar - ivn;
    4329           0 :   const unsigned int j = jvar - jvn;
    4330             : 
    4331             :   // DoF indices are independently given
    4332           0 :   auto di = idof_indices;
    4333           0 :   auto dj = jdof_indices;
    4334             : 
    4335           0 :   auto indof = di.size();
    4336           0 :   auto jndof = dj.size();
    4337             : 
    4338           0 :   unsigned int jj = j;
    4339           0 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4340           0 :     jj = 0;
    4341             : 
    4342           0 :   auto sub = keg.sub_matrix(i * indof, indof, jj * jndof, jndof);
    4343             :   // If we're computing the jacobian for automatically scaling variables we do not want to
    4344             :   // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    4345             :   // dofs
    4346           0 :   if (!_sys.computingScalingJacobian())
    4347           0 :     dof_map.constrain_element_matrix(sub, di, dj, false);
    4348             : 
    4349           0 :   if (scaling_factor[i] != 1.0)
    4350           0 :     sub *= scaling_factor[i];
    4351             : 
    4352           0 :   jacobian.add_matrix(sub, di, dj);
    4353           0 : }
    4354             : 
    4355             : void
    4356           0 : Assembly::addJacobianBlockNonlocalTags(SparseMatrix<Number> & jacobian,
    4357             :                                        const unsigned int ivar,
    4358             :                                        const unsigned int jvar,
    4359             :                                        const DofMap & dof_map,
    4360             :                                        const std::vector<dof_id_type> & idof_indices,
    4361             :                                        const std::vector<dof_id_type> & jdof_indices,
    4362             :                                        GlobalDataKey,
    4363             :                                        const std::set<TagID> & tags)
    4364             : {
    4365           0 :   for (auto tag : tags)
    4366           0 :     addJacobianBlockNonlocal(
    4367           0 :         jacobian, ivar, jvar, dof_map, idof_indices, jdof_indices, GlobalDataKey{}, tag);
    4368           0 : }
    4369             : 
    4370             : void
    4371        2688 : Assembly::addJacobianNeighbor(SparseMatrix<Number> & jacobian,
    4372             :                               const unsigned int ivar,
    4373             :                               const unsigned int jvar,
    4374             :                               const DofMap & dof_map,
    4375             :                               std::vector<dof_id_type> & dof_indices,
    4376             :                               std::vector<dof_id_type> & neighbor_dof_indices,
    4377             :                               GlobalDataKey,
    4378             :                               const TagID tag)
    4379             : {
    4380        2688 :   if (dof_indices.size() == 0 && neighbor_dof_indices.size() == 0)
    4381           0 :     return;
    4382        2688 :   if (!(*_cm)(ivar, jvar))
    4383           0 :     return;
    4384             : 
    4385        2688 :   auto & iv = _sys.getVariable(_tid, ivar);
    4386        2688 :   auto & jv = _sys.getVariable(_tid, jvar);
    4387        2688 :   auto & scaling_factor = iv.arrayScalingFactor();
    4388             : 
    4389        2688 :   const unsigned int ivn = iv.number();
    4390        2688 :   const unsigned int jvn = jv.number();
    4391        2688 :   auto & ken = jacobianBlockNeighbor(Moose::ElementNeighbor, ivn, jvn, LocalDataKey{}, tag);
    4392        2688 :   auto & kne = jacobianBlockNeighbor(Moose::NeighborElement, ivn, jvn, LocalDataKey{}, tag);
    4393        2688 :   auto & knn = jacobianBlockNeighbor(Moose::NeighborNeighbor, ivn, jvn, LocalDataKey{}, tag);
    4394             : 
    4395             :   // It is guaranteed by design iv.number <= ivar since iv is obtained
    4396             :   // through SystemBase::getVariable with ivar.
    4397             :   // Most of times ivar will just be equal to iv.number except for array variables,
    4398             :   // where ivar could be a number for a component of an array variable but calling
    4399             :   // getVariable will return the array variable that has the number of the 0th component.
    4400             :   // It is the same for jvar.
    4401        2688 :   const unsigned int i = ivar - ivn;
    4402        2688 :   const unsigned int j = jvar - jvn;
    4403             :   // DoF indices are independently given
    4404        2688 :   auto dc = dof_indices;
    4405        2688 :   auto dn = neighbor_dof_indices;
    4406        2688 :   auto cndof = dc.size();
    4407        2688 :   auto nndof = dn.size();
    4408             : 
    4409        2688 :   unsigned int jj = j;
    4410        2688 :   if (ivar == jvar && _component_block_diagonal[ivn])
    4411        2688 :     jj = 0;
    4412             : 
    4413        2688 :   auto suben = ken.sub_matrix(i * cndof, cndof, jj * nndof, nndof);
    4414        2688 :   auto subne = kne.sub_matrix(i * nndof, nndof, jj * cndof, cndof);
    4415        2688 :   auto subnn = knn.sub_matrix(i * nndof, nndof, jj * nndof, nndof);
    4416             : 
    4417             :   // If we're computing the jacobian for automatically scaling variables we do not want to
    4418             :   // constrain the element matrix because it introduces 1s on the diagonal for the constrained
    4419             :   // dofs
    4420        2688 :   if (!_sys.computingScalingJacobian())
    4421             :   {
    4422        2688 :     dof_map.constrain_element_matrix(suben, dc, dn, false);
    4423        2688 :     dof_map.constrain_element_matrix(subne, dn, dc, false);
    4424        2688 :     dof_map.constrain_element_matrix(subnn, dn, dn, false);
    4425             :   }
    4426             : 
    4427        2688 :   if (scaling_factor[i] != 1.0)
    4428             :   {
    4429           0 :     suben *= scaling_factor[i];
    4430           0 :     subne *= scaling_factor[i];
    4431           0 :     subnn *= scaling_factor[i];
    4432             :   }
    4433             : 
    4434        2688 :   jacobian.add_matrix(suben, dc, dn);
    4435        2688 :   jacobian.add_matrix(subne, dn, dc);
    4436        2688 :   jacobian.add_matrix(subnn, dn, dn);
    4437        2688 : }
    4438             : 
    4439             : void
    4440        1344 : Assembly::addJacobianNeighborTags(SparseMatrix<Number> & jacobian,
    4441             :                                   const unsigned int ivar,
    4442             :                                   const unsigned int jvar,
    4443             :                                   const DofMap & dof_map,
    4444             :                                   std::vector<dof_id_type> & dof_indices,
    4445             :                                   std::vector<dof_id_type> & neighbor_dof_indices,
    4446             :                                   GlobalDataKey,
    4447             :                                   const std::set<TagID> & tags)
    4448             : {
    4449        4032 :   for (const auto tag : tags)
    4450        2688 :     addJacobianNeighbor(
    4451        5376 :         jacobian, ivar, jvar, dof_map, dof_indices, neighbor_dof_indices, GlobalDataKey{}, tag);
    4452        1344 : }
    4453             : 
    4454             : void
    4455       15622 : Assembly::addJacobianScalar(GlobalDataKey)
    4456             : {
    4457       35635 :   for (const auto & it : _cm_ss_entry)
    4458       20013 :     addJacobianCoupledVarPair(*it.first, *it.second);
    4459       15622 : }
    4460             : 
    4461             : void
    4462       39233 : Assembly::addJacobianOffDiagScalar(unsigned int ivar, GlobalDataKey)
    4463             : {
    4464       39233 :   const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
    4465       39233 :   MooseVariableScalar & var_i = _sys.getScalarVariable(_tid, ivar);
    4466       53902 :   for (const auto & var_j : vars)
    4467       14669 :     addJacobianCoupledVarPair(var_i, *var_j);
    4468       39233 : }
    4469             : 
    4470             : void
    4471   250793023 : Assembly::cacheJacobian(
    4472             :     numeric_index_type i, numeric_index_type j, Real value, LocalDataKey, TagID tag)
    4473             : {
    4474   250793023 :   _cached_jacobian_rows[tag].push_back(i);
    4475   250793023 :   _cached_jacobian_cols[tag].push_back(j);
    4476   250793023 :   _cached_jacobian_values[tag].push_back(value);
    4477   250793023 : }
    4478             : 
    4479             : void
    4480   250732714 : Assembly::cacheJacobian(numeric_index_type i,
    4481             :                         numeric_index_type j,
    4482             :                         Real value,
    4483             :                         LocalDataKey,
    4484             :                         const std::set<TagID> & tags)
    4485             : {
    4486   518365421 :   for (auto tag : tags)
    4487   267632707 :     if (_sys.hasMatrix(tag))
    4488   250793023 :       cacheJacobian(i, j, value, LocalDataKey{}, tag);
    4489   250732714 : }
    4490             : 
    4491             : void
    4492      430481 : Assembly::setCachedJacobian(GlobalDataKey)
    4493             : {
    4494     1304117 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4495      873636 :     if (_sys.hasMatrix(tag))
    4496             :     {
    4497             :       // First zero the rows (including the diagonals) to prepare for
    4498             :       // setting the cached values.
    4499      431993 :       _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
    4500             : 
    4501             :       // TODO: Use SparseMatrix::set_values() for efficiency
    4502     9703348 :       for (MooseIndex(_cached_jacobian_values) i = 0; i < _cached_jacobian_values[tag].size(); ++i)
    4503    18542710 :         _sys.getMatrix(tag).set(_cached_jacobian_rows[tag][i],
    4504     9271355 :                                 _cached_jacobian_cols[tag][i],
    4505     9271355 :                                 _cached_jacobian_values[tag][i]);
    4506             :     }
    4507             : 
    4508      430481 :   clearCachedJacobian();
    4509      430481 : }
    4510             : 
    4511             : void
    4512           0 : Assembly::zeroCachedJacobian(GlobalDataKey)
    4513             : {
    4514           0 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4515           0 :     if (_sys.hasMatrix(tag))
    4516           0 :       _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
    4517             : 
    4518           0 :   clearCachedJacobian();
    4519           0 : }
    4520             : 
    4521             : void
    4522      430481 : Assembly::clearCachedJacobian()
    4523             : {
    4524     1304117 :   for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
    4525             :   {
    4526      873636 :     _cached_jacobian_rows[tag].clear();
    4527      873636 :     _cached_jacobian_cols[tag].clear();
    4528      873636 :     _cached_jacobian_values[tag].clear();
    4529             :   }
    4530      430481 : }
    4531             : 
    4532             : void
    4533           0 : Assembly::modifyWeightsDueToXFEM(const Elem * elem)
    4534             : {
    4535             :   mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
    4536             : 
    4537           0 :   if (_current_qrule == _current_qrule_arbitrary)
    4538           0 :     return;
    4539             : 
    4540           0 :   MooseArray<Real> xfem_weight_multipliers;
    4541           0 :   if (_xfem->getXFEMWeights(xfem_weight_multipliers, elem, _current_qrule, _current_q_points))
    4542             :   {
    4543             :     mooseAssert(xfem_weight_multipliers.size() == _current_JxW.size(),
    4544             :                 "Size of weight multipliers in xfem doesn't match number of quadrature points");
    4545           0 :     for (unsigned i = 0; i < xfem_weight_multipliers.size(); i++)
    4546           0 :       _current_JxW[i] = _current_JxW[i] * xfem_weight_multipliers[i];
    4547             : 
    4548           0 :     xfem_weight_multipliers.release();
    4549             :   }
    4550           0 : }
    4551             : 
    4552             : void
    4553           0 : Assembly::modifyFaceWeightsDueToXFEM(const Elem * elem, unsigned int side)
    4554             : {
    4555             :   mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
    4556             : 
    4557           0 :   if (_current_qrule_face == _current_qrule_arbitrary)
    4558           0 :     return;
    4559             : 
    4560           0 :   MooseArray<Real> xfem_face_weight_multipliers;
    4561           0 :   if (_xfem->getXFEMFaceWeights(
    4562           0 :           xfem_face_weight_multipliers, elem, _current_qrule_face, _current_q_points_face, side))
    4563             :   {
    4564             :     mooseAssert(xfem_face_weight_multipliers.size() == _current_JxW_face.size(),
    4565             :                 "Size of weight multipliers in xfem doesn't match number of quadrature points");
    4566           0 :     for (unsigned i = 0; i < xfem_face_weight_multipliers.size(); i++)
    4567           0 :       _current_JxW_face[i] = _current_JxW_face[i] * xfem_face_weight_multipliers[i];
    4568             : 
    4569           0 :     xfem_face_weight_multipliers.release();
    4570             :   }
    4571           0 : }
    4572             : 
    4573             : void
    4574         423 : Assembly::hasScalingVector()
    4575             : {
    4576         846 :   _scaling_vector = &_sys.getVector("scaling_factors");
    4577         423 : }
    4578             : 
    4579             : void
    4580           0 : Assembly::modifyArbitraryWeights(const std::vector<Real> & weights)
    4581             : {
    4582             :   mooseAssert(_current_qrule == _current_qrule_arbitrary, "Rule should be arbitrary");
    4583             :   mooseAssert(weights.size() == _current_physical_points.size(), "Size mismatch");
    4584             : 
    4585           0 :   for (MooseIndex(weights.size()) i = 0; i < weights.size(); ++i)
    4586           0 :     _current_JxW[i] = weights[i];
    4587           0 : }
    4588             : 
    4589             : template <>
    4590             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4591        1666 : Assembly::fePhi<VectorValue<Real>>(FEType type) const
    4592             : {
    4593        1666 :   buildVectorFE(type);
    4594        1666 :   return _vector_fe_shape_data[type]->_phi;
    4595             : }
    4596             : 
    4597             : template <>
    4598             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4599        1666 : Assembly::feGradPhi<VectorValue<Real>>(FEType type) const
    4600             : {
    4601        1666 :   buildVectorFE(type);
    4602        1666 :   return _vector_fe_shape_data[type]->_grad_phi;
    4603             : }
    4604             : 
    4605             : template <>
    4606             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4607           0 : Assembly::feSecondPhi<VectorValue<Real>>(FEType type) const
    4608             : {
    4609           0 :   _need_second_derivative.insert(type);
    4610           0 :   buildVectorFE(type);
    4611           0 :   return _vector_fe_shape_data[type]->_second_phi;
    4612             : }
    4613             : 
    4614             : template <>
    4615             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4616        3332 : Assembly::fePhiLower<VectorValue<Real>>(FEType type) const
    4617             : {
    4618        3332 :   buildVectorLowerDFE(type);
    4619        3332 :   return _vector_fe_shape_data_lower[type]->_phi;
    4620             : }
    4621             : 
    4622             : template <>
    4623             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4624           0 : Assembly::feDualPhiLower<VectorValue<Real>>(FEType type) const
    4625             : {
    4626           0 :   buildVectorDualLowerDFE(type);
    4627           0 :   return _vector_fe_shape_data_dual_lower[type]->_phi;
    4628             : }
    4629             : 
    4630             : template <>
    4631             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4632        3332 : Assembly::feGradPhiLower<VectorValue<Real>>(FEType type) const
    4633             : {
    4634        3332 :   buildVectorLowerDFE(type);
    4635        3332 :   return _vector_fe_shape_data_lower[type]->_grad_phi;
    4636             : }
    4637             : 
    4638             : template <>
    4639             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4640           0 : Assembly::feGradDualPhiLower<VectorValue<Real>>(FEType type) const
    4641             : {
    4642           0 :   buildVectorDualLowerDFE(type);
    4643           0 :   return _vector_fe_shape_data_dual_lower[type]->_grad_phi;
    4644             : }
    4645             : 
    4646             : template <>
    4647             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4648        1666 : Assembly::fePhiFace<VectorValue<Real>>(FEType type) const
    4649             : {
    4650        1666 :   buildVectorFaceFE(type);
    4651        1666 :   return _vector_fe_shape_data_face[type]->_phi;
    4652             : }
    4653             : 
    4654             : template <>
    4655             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4656        1666 : Assembly::feGradPhiFace<VectorValue<Real>>(FEType type) const
    4657             : {
    4658        1666 :   buildVectorFaceFE(type);
    4659        1666 :   return _vector_fe_shape_data_face[type]->_grad_phi;
    4660             : }
    4661             : 
    4662             : template <>
    4663             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4664           0 : Assembly::feSecondPhiFace<VectorValue<Real>>(FEType type) const
    4665             : {
    4666           0 :   _need_second_derivative.insert(type);
    4667           0 :   buildVectorFaceFE(type);
    4668             : 
    4669             :   // If we're building for a face we probably need to build for a
    4670             :   // neighbor while _need_second_derivative is set;
    4671             :   // onInterface/reinitNeighbor/etc don't distinguish
    4672           0 :   buildVectorFaceNeighborFE(type);
    4673             : 
    4674           0 :   return _vector_fe_shape_data_face[type]->_second_phi;
    4675             : }
    4676             : 
    4677             : template <>
    4678             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4679        1666 : Assembly::fePhiNeighbor<VectorValue<Real>>(FEType type) const
    4680             : {
    4681        1666 :   buildVectorNeighborFE(type);
    4682        1666 :   return _vector_fe_shape_data_neighbor[type]->_phi;
    4683             : }
    4684             : 
    4685             : template <>
    4686             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4687        1666 : Assembly::feGradPhiNeighbor<VectorValue<Real>>(FEType type) const
    4688             : {
    4689        1666 :   buildVectorNeighborFE(type);
    4690        1666 :   return _vector_fe_shape_data_neighbor[type]->_grad_phi;
    4691             : }
    4692             : 
    4693             : template <>
    4694             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4695           0 : Assembly::feSecondPhiNeighbor<VectorValue<Real>>(FEType type) const
    4696             : {
    4697           0 :   _need_second_derivative_neighbor.insert(type);
    4698           0 :   buildVectorNeighborFE(type);
    4699           0 :   return _vector_fe_shape_data_neighbor[type]->_second_phi;
    4700             : }
    4701             : 
    4702             : template <>
    4703             : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
    4704        1666 : Assembly::fePhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4705             : {
    4706        1666 :   buildVectorFaceNeighborFE(type);
    4707        1666 :   return _vector_fe_shape_data_face_neighbor[type]->_phi;
    4708             : }
    4709             : 
    4710             : template <>
    4711             : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
    4712        1666 : Assembly::feGradPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4713             : {
    4714        1666 :   buildVectorFaceNeighborFE(type);
    4715        1666 :   return _vector_fe_shape_data_face_neighbor[type]->_grad_phi;
    4716             : }
    4717             : 
    4718             : template <>
    4719             : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
    4720           0 : Assembly::feSecondPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4721             : {
    4722           0 :   _need_second_derivative_neighbor.insert(type);
    4723           0 :   buildVectorFaceNeighborFE(type);
    4724           0 :   return _vector_fe_shape_data_face_neighbor[type]->_second_phi;
    4725             : }
    4726             : 
    4727             : template <>
    4728             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4729       64382 : Assembly::feCurlPhi<VectorValue<Real>>(FEType type) const
    4730             : {
    4731       64382 :   _need_curl.insert(type);
    4732       64382 :   buildVectorFE(type);
    4733       64382 :   return _vector_fe_shape_data[type]->_curl_phi;
    4734             : }
    4735             : 
    4736             : template <>
    4737             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4738         224 : Assembly::feCurlPhiFace<VectorValue<Real>>(FEType type) const
    4739             : {
    4740         224 :   _need_curl.insert(type);
    4741         224 :   buildVectorFaceFE(type);
    4742             : 
    4743             :   // If we're building for a face we probably need to build for a
    4744             :   // neighbor while _need_curl is set;
    4745             :   // onInterface/reinitNeighbor/etc don't distinguish
    4746         224 :   buildVectorFaceNeighborFE(type);
    4747             : 
    4748         224 :   return _vector_fe_shape_data_face[type]->_curl_phi;
    4749             : }
    4750             : 
    4751             : template <>
    4752             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4753           0 : Assembly::feCurlPhiNeighbor<VectorValue<Real>>(FEType type) const
    4754             : {
    4755           0 :   _need_curl.insert(type);
    4756           0 :   buildVectorNeighborFE(type);
    4757           0 :   return _vector_fe_shape_data_neighbor[type]->_curl_phi;
    4758             : }
    4759             : 
    4760             : template <>
    4761             : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
    4762           0 : Assembly::feCurlPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4763             : {
    4764           0 :   _need_curl.insert(type);
    4765           0 :   buildVectorFaceNeighborFE(type);
    4766             : 
    4767           0 :   return _vector_fe_shape_data_face_neighbor[type]->_curl_phi;
    4768             : }
    4769             : 
    4770             : template <>
    4771             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4772      527632 : Assembly::feDivPhi<VectorValue<Real>>(FEType type) const
    4773             : {
    4774      527632 :   _need_div.insert(type);
    4775      527632 :   buildVectorFE(type);
    4776      527632 :   return _vector_fe_shape_data[type]->_div_phi;
    4777             : }
    4778             : 
    4779             : template <>
    4780             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4781         336 : Assembly::feDivPhiFace<VectorValue<Real>>(FEType type) const
    4782             : {
    4783         336 :   _need_face_div.insert(type);
    4784         336 :   buildVectorFaceFE(type);
    4785             : 
    4786             :   // If we're building for a face we probably need to build for a
    4787             :   // neighbor while _need_face_div is set;
    4788             :   // onInterface/reinitNeighbor/etc don't distinguish
    4789         336 :   buildVectorFaceNeighborFE(type);
    4790             : 
    4791         336 :   return _vector_fe_shape_data_face[type]->_div_phi;
    4792             : }
    4793             : 
    4794             : template <>
    4795             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4796           0 : Assembly::feDivPhiNeighbor<VectorValue<Real>>(FEType type) const
    4797             : {
    4798           0 :   _need_neighbor_div.insert(type);
    4799           0 :   buildVectorNeighborFE(type);
    4800           0 :   return _vector_fe_shape_data_neighbor[type]->_div_phi;
    4801             : }
    4802             : 
    4803             : template <>
    4804             : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
    4805           0 : Assembly::feDivPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
    4806             : {
    4807           0 :   _need_face_neighbor_div.insert(type);
    4808           0 :   buildVectorFaceNeighborFE(type);
    4809           0 :   return _vector_fe_shape_data_face_neighbor[type]->_div_phi;
    4810             : }
    4811             : 
    4812             : const MooseArray<ADReal> &
    4813          28 : Assembly::adCurvatures() const
    4814             : {
    4815          28 :   _calculate_curvatures = true;
    4816          28 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
    4817          28 :   const FEType helper_type(helper_order, LAGRANGE);
    4818             :   // Must prerequest the second derivatives. Sadly because there is only one
    4819             :   // _need_second_derivative map for both volumetric and face FE objects we must request both here
    4820          28 :   feSecondPhi<Real>(helper_type);
    4821          28 :   feSecondPhiFace<Real>(helper_type);
    4822          28 :   return _ad_curvatures;
    4823             : }
    4824             : 
    4825             : void
    4826       72442 : Assembly::helpersRequestData()
    4827             : {
    4828      281603 :   for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
    4829             :   {
    4830      209161 :     _holder_fe_helper[dim]->get_phi();
    4831      209161 :     _holder_fe_helper[dim]->get_dphi();
    4832      209161 :     _holder_fe_helper[dim]->get_xyz();
    4833      209161 :     _holder_fe_helper[dim]->get_JxW();
    4834             : 
    4835      209161 :     _holder_fe_face_helper[dim]->get_phi();
    4836      209161 :     _holder_fe_face_helper[dim]->get_dphi();
    4837      209161 :     _holder_fe_face_helper[dim]->get_xyz();
    4838      209161 :     _holder_fe_face_helper[dim]->get_JxW();
    4839      209161 :     _holder_fe_face_helper[dim]->get_normals();
    4840             : 
    4841      209161 :     _holder_fe_face_neighbor_helper[dim]->get_xyz();
    4842      209161 :     _holder_fe_face_neighbor_helper[dim]->get_JxW();
    4843      209161 :     _holder_fe_face_neighbor_helper[dim]->get_normals();
    4844             : 
    4845      209161 :     _holder_fe_neighbor_helper[dim]->get_xyz();
    4846      209161 :     _holder_fe_neighbor_helper[dim]->get_JxW();
    4847             :   }
    4848             : 
    4849      209161 :   for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
    4850             :   {
    4851             :     // We need these computations in order to compute correct lower-d element volumes in
    4852             :     // curvilinear coordinates
    4853      136719 :     _holder_fe_lower_helper[dim]->get_xyz();
    4854      136719 :     _holder_fe_lower_helper[dim]->get_JxW();
    4855             :   }
    4856       72442 : }
    4857             : 
    4858             : void
    4859         252 : Assembly::havePRefinement(const std::unordered_set<FEFamily> & disable_families)
    4860             : {
    4861         252 :   if (_have_p_refinement)
    4862             :     // Already performed tasks for p-refinement
    4863           0 :     return;
    4864             : 
    4865         252 :   const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
    4866         252 :   const FEType helper_type(helper_order, LAGRANGE);
    4867             :   auto process_fe =
    4868        2520 :       [&disable_families](const unsigned int num_dimensionalities, auto & fe_container)
    4869             :   {
    4870        2520 :     if (!disable_families.empty())
    4871        8120 :       for (const auto dim : make_range(num_dimensionalities))
    4872             :       {
    4873        6020 :         auto fe_container_it = fe_container.find(dim);
    4874        6020 :         if (fe_container_it != fe_container.end())
    4875       12222 :           for (auto & [fe_type, fe_ptr] : fe_container_it->second)
    4876        8232 :             if (disable_families.count(fe_type.family))
    4877        2870 :               fe_ptr->add_p_level_in_reinit(false);
    4878             :       }
    4879        2772 :   };
    4880        1260 :   auto process_fe_and_helpers = [process_fe, &helper_type](auto & unique_helper_container,
    4881             :                                                            auto & helper_container,
    4882             :                                                            const unsigned int num_dimensionalities,
    4883             :                                                            const bool user_added_helper_type,
    4884             :                                                            auto & fe_container)
    4885             :   {
    4886        1260 :     unique_helper_container.resize(num_dimensionalities);
    4887        4858 :     for (const auto dim : make_range(num_dimensionalities))
    4888             :     {
    4889        3598 :       auto & unique_helper = unique_helper_container[dim];
    4890        3598 :       unique_helper = FEGenericBase<Real>::build(dim, helper_type);
    4891             :       // don't participate in p-refinement
    4892        3598 :       unique_helper->add_p_level_in_reinit(false);
    4893        3598 :       helper_container[dim] = unique_helper.get();
    4894             : 
    4895             :       // If the user did not request the helper type then we should erase it from our FE container
    4896             :       // so that they're not penalized (in the "we should be able to do p-refinement sense") for
    4897             :       // our perhaps silly helpers
    4898        3598 :       if (!user_added_helper_type)
    4899             :       {
    4900        2548 :         auto & fe_container_dim = libmesh_map_find(fe_container, dim);
    4901        2548 :         auto fe_it = fe_container_dim.find(helper_type);
    4902             :         mooseAssert(fe_it != fe_container_dim.end(), "We should have the helper type");
    4903        2548 :         delete fe_it->second;
    4904        2548 :         fe_container_dim.erase(fe_it);
    4905             :       }
    4906             :     }
    4907             : 
    4908        1260 :     process_fe(num_dimensionalities, fe_container);
    4909        1260 :   };
    4910             : 
    4911             :   // Handle scalar field families
    4912         252 :   process_fe_and_helpers(_unique_fe_helper,
    4913         252 :                          _holder_fe_helper,
    4914         252 :                          _mesh_dimension + 1,
    4915         252 :                          _user_added_fe_of_helper_type,
    4916         252 :                          _fe);
    4917         252 :   process_fe_and_helpers(_unique_fe_face_helper,
    4918         252 :                          _holder_fe_face_helper,
    4919         252 :                          _mesh_dimension + 1,
    4920         252 :                          _user_added_fe_face_of_helper_type,
    4921         252 :                          _fe_face);
    4922         252 :   process_fe_and_helpers(_unique_fe_face_neighbor_helper,
    4923         252 :                          _holder_fe_face_neighbor_helper,
    4924         252 :                          _mesh_dimension + 1,
    4925         252 :                          _user_added_fe_face_neighbor_of_helper_type,
    4926         252 :                          _fe_face_neighbor);
    4927         252 :   process_fe_and_helpers(_unique_fe_neighbor_helper,
    4928         252 :                          _holder_fe_neighbor_helper,
    4929         252 :                          _mesh_dimension + 1,
    4930         252 :                          _user_added_fe_neighbor_of_helper_type,
    4931         252 :                          _fe_neighbor);
    4932         252 :   process_fe_and_helpers(_unique_fe_lower_helper,
    4933         252 :                          _holder_fe_lower_helper,
    4934             :                          _mesh_dimension,
    4935         252 :                          _user_added_fe_lower_of_helper_type,
    4936         252 :                          _fe_lower);
    4937             :   // Handle vector field families
    4938         252 :   process_fe(_mesh_dimension + 1, _vector_fe);
    4939         252 :   process_fe(_mesh_dimension + 1, _vector_fe_face);
    4940         252 :   process_fe(_mesh_dimension + 1, _vector_fe_neighbor);
    4941         252 :   process_fe(_mesh_dimension + 1, _vector_fe_face_neighbor);
    4942         252 :   process_fe(_mesh_dimension, _vector_fe_lower);
    4943             : 
    4944         252 :   helpersRequestData();
    4945             : 
    4946         252 :   _have_p_refinement = true;
    4947             : }
    4948             : 
    4949             : template void coordTransformFactor<Point, Real>(const SubProblem & s,
    4950             :                                                 SubdomainID sub_id,
    4951             :                                                 const Point & point,
    4952             :                                                 Real & factor,
    4953             :                                                 SubdomainID neighbor_sub_id);
    4954             : template void coordTransformFactor<ADPoint, ADReal>(const SubProblem & s,
    4955             :                                                     SubdomainID sub_id,
    4956             :                                                     const ADPoint & point,
    4957             :                                                     ADReal & factor,
    4958             :                                                     SubdomainID neighbor_sub_id);
    4959             : template void coordTransformFactor<Point, Real>(const MooseMesh & mesh,
    4960             :                                                 SubdomainID sub_id,
    4961             :                                                 const Point & point,
    4962             :                                                 Real & factor,
    4963             :                                                 SubdomainID neighbor_sub_id);
    4964             : template void coordTransformFactor<ADPoint, ADReal>(const MooseMesh & mesh,
    4965             :                                                     SubdomainID sub_id,
    4966             :                                                     const ADPoint & point,
    4967             :                                                     ADReal & factor,
    4968             :                                                     SubdomainID neighbor_sub_id);
    4969             : 
    4970             : template <>
    4971             : const MooseArray<Moose::GenericType<Point, false>> &
    4972          39 : Assembly::genericQPoints<false>() const
    4973             : {
    4974          39 :   return qPoints();
    4975             : }
    4976             : 
    4977             : template <>
    4978             : const MooseArray<Moose::GenericType<Point, true>> &
    4979          11 : Assembly::genericQPoints<true>() const
    4980             : {
    4981          11 :   return adQPoints();
    4982             : }

Generated by: LCOV version 1.14