LCOV - code coverage report
Current view: top level - src/systems - NonlinearSystemBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31730 (e8b711) with base e0c998 Lines: 1944 2184 89.0 %
Date: 2025-10-29 16:49:47 Functions: 81 97 83.5 %
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 "NonlinearSystemBase.h"
      11             : #include "AuxiliarySystem.h"
      12             : #include "Problem.h"
      13             : #include "FEProblem.h"
      14             : #include "MooseVariableFE.h"
      15             : #include "MooseVariableScalar.h"
      16             : #include "PetscSupport.h"
      17             : #include "Factory.h"
      18             : #include "ParallelUniqueId.h"
      19             : #include "ThreadedElementLoop.h"
      20             : #include "MaterialData.h"
      21             : #include "ComputeResidualThread.h"
      22             : #include "ComputeResidualAndJacobianThread.h"
      23             : #include "ComputeFVFluxThread.h"
      24             : #include "ComputeJacobianThread.h"
      25             : #include "ComputeJacobianForScalingThread.h"
      26             : #include "ComputeFullJacobianThread.h"
      27             : #include "ComputeJacobianBlocksThread.h"
      28             : #include "ComputeDiracThread.h"
      29             : #include "ComputeElemDampingThread.h"
      30             : #include "ComputeNodalDampingThread.h"
      31             : #include "ComputeNodalKernelsThread.h"
      32             : #include "ComputeNodalKernelBcsThread.h"
      33             : #include "ComputeNodalKernelJacobiansThread.h"
      34             : #include "ComputeNodalKernelBCJacobiansThread.h"
      35             : #include "TimeKernel.h"
      36             : #include "BoundaryCondition.h"
      37             : #include "DirichletBCBase.h"
      38             : #include "NodalBCBase.h"
      39             : #include "IntegratedBCBase.h"
      40             : #include "DGKernel.h"
      41             : #include "InterfaceKernelBase.h"
      42             : #include "ElementDamper.h"
      43             : #include "NodalDamper.h"
      44             : #include "GeneralDamper.h"
      45             : #include "DisplacedProblem.h"
      46             : #include "NearestNodeLocator.h"
      47             : #include "PenetrationLocator.h"
      48             : #include "NodalConstraint.h"
      49             : #include "NodeFaceConstraint.h"
      50             : #include "NodeElemConstraintBase.h"
      51             : #include "MortarConstraint.h"
      52             : #include "ElemElemConstraint.h"
      53             : #include "ScalarKernelBase.h"
      54             : #include "Parser.h"
      55             : #include "Split.h"
      56             : #include "FieldSplitPreconditioner.h"
      57             : #include "MooseMesh.h"
      58             : #include "MooseUtils.h"
      59             : #include "MooseApp.h"
      60             : #include "NodalKernelBase.h"
      61             : #include "DiracKernelBase.h"
      62             : #include "TimeIntegrator.h"
      63             : #include "Predictor.h"
      64             : #include "Assembly.h"
      65             : #include "ElementPairLocator.h"
      66             : #include "ODETimeKernel.h"
      67             : #include "AllLocalDofIndicesThread.h"
      68             : #include "FloatingPointExceptionGuard.h"
      69             : #include "ADKernel.h"
      70             : #include "ADDirichletBCBase.h"
      71             : #include "Moose.h"
      72             : #include "ConsoleStream.h"
      73             : #include "MooseError.h"
      74             : #include "FVElementalKernel.h"
      75             : #include "FVScalarLagrangeMultiplierConstraint.h"
      76             : #include "FVBoundaryScalarLagrangeMultiplierConstraint.h"
      77             : #include "FVFluxKernel.h"
      78             : #include "FVScalarLagrangeMultiplierInterface.h"
      79             : #include "UserObject.h"
      80             : #include "OffDiagonalScalingMatrix.h"
      81             : #include "HDGKernel.h"
      82             : #include "AutomaticMortarGeneration.h"
      83             : 
      84             : // libMesh
      85             : #include "libmesh/nonlinear_solver.h"
      86             : #include "libmesh/quadrature_gauss.h"
      87             : #include "libmesh/dense_vector.h"
      88             : #include "libmesh/boundary_info.h"
      89             : #include "libmesh/petsc_matrix.h"
      90             : #include "libmesh/petsc_vector.h"
      91             : #include "libmesh/petsc_nonlinear_solver.h"
      92             : #include "libmesh/numeric_vector.h"
      93             : #include "libmesh/mesh.h"
      94             : #include "libmesh/dense_subvector.h"
      95             : #include "libmesh/dense_submatrix.h"
      96             : #include "libmesh/dof_map.h"
      97             : #include "libmesh/sparse_matrix.h"
      98             : #include "libmesh/petsc_matrix.h"
      99             : #include "libmesh/default_coupling.h"
     100             : #include "libmesh/diagonal_matrix.h"
     101             : #include "libmesh/fe_interface.h"
     102             : #include "libmesh/petsc_solver_exception.h"
     103             : 
     104             : #include <ios>
     105             : 
     106             : #include "petscsnes.h"
     107             : #include <PetscDMMoose.h>
     108             : EXTERN_C_BEGIN
     109             : extern PetscErrorCode DMCreate_Moose(DM);
     110             : EXTERN_C_END
     111             : 
     112             : using namespace libMesh;
     113             : 
     114       63562 : NonlinearSystemBase::NonlinearSystemBase(FEProblemBase & fe_problem,
     115             :                                          System & sys,
     116       63562 :                                          const std::string & name)
     117             :   : SolverSystem(fe_problem, fe_problem, name, Moose::VAR_SOLVER),
     118       63562 :     PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "NonlinearSystemBase"),
     119       63562 :     _sys(sys),
     120       63562 :     _last_nl_rnorm(0.),
     121       63562 :     _current_nl_its(0),
     122       63562 :     _residual_ghosted(NULL),
     123       63562 :     _Re_time_tag(-1),
     124       63562 :     _Re_time(NULL),
     125       63562 :     _Re_non_time_tag(-1),
     126       63562 :     _Re_non_time(NULL),
     127       63562 :     _scalar_kernels(/*threaded=*/false),
     128       63562 :     _nodal_bcs(/*threaded=*/false),
     129       63562 :     _preset_nodal_bcs(/*threaded=*/false),
     130       63562 :     _ad_preset_nodal_bcs(/*threaded=*/false),
     131             : #ifdef MOOSE_KOKKOS_ENABLED
     132       42482 :     _kokkos_kernels(/*threaded=*/false),
     133       42482 :     _kokkos_integrated_bcs(/*threaded=*/false),
     134       42482 :     _kokkos_nodal_bcs(/*threaded=*/false),
     135       42482 :     _kokkos_preset_nodal_bcs(/*threaded=*/false),
     136       42482 :     _kokkos_nodal_kernels(/*threaded=*/false),
     137             : #endif
     138       63562 :     _general_dampers(/*threaded=*/false),
     139       63562 :     _splits(/*threaded=*/false),
     140       63562 :     _increment_vec(NULL),
     141       63562 :     _use_finite_differenced_preconditioner(false),
     142       63562 :     _fdcoloring(nullptr),
     143       63562 :     _fsp(nullptr),
     144       63562 :     _add_implicit_geometric_coupling_entries_to_jacobian(false),
     145       63562 :     _assemble_constraints_separately(false),
     146       63562 :     _need_residual_ghosted(false),
     147       63562 :     _debugging_residuals(false),
     148       63562 :     _doing_dg(false),
     149       63562 :     _n_iters(0),
     150       63562 :     _n_linear_iters(0),
     151       63562 :     _n_residual_evaluations(0),
     152       63562 :     _final_residual(0.),
     153       63562 :     _computing_pre_smo_residual(false),
     154       63562 :     _pre_smo_residual(0),
     155       63562 :     _initial_residual(0),
     156       63562 :     _use_pre_smo_residual(false),
     157       63562 :     _print_all_var_norms(false),
     158       63562 :     _has_save_in(false),
     159       63562 :     _has_diag_save_in(false),
     160       63562 :     _has_nodalbc_save_in(false),
     161       63562 :     _has_nodalbc_diag_save_in(false),
     162       63562 :     _computed_scaling(false),
     163       63562 :     _compute_scaling_once(true),
     164       63562 :     _resid_vs_jac_scaling_param(0),
     165       63562 :     _off_diagonals_in_auto_scaling(false),
     166      508496 :     _auto_scaling_initd(false)
     167             : {
     168       63562 :   getResidualNonTimeVector();
     169             :   // Don't need to add the matrix - it already exists (for now)
     170       63562 :   _Ke_system_tag = _fe_problem.addMatrixTag("SYSTEM");
     171             : 
     172             :   // The time matrix tag is not normally used - but must be added to the system
     173             :   // in case it is so that objects can have 'time' in their matrix tags by default
     174       63562 :   _fe_problem.addMatrixTag("TIME");
     175             : 
     176       63562 :   _Re_tag = _fe_problem.addVectorTag("RESIDUAL");
     177             : 
     178       63562 :   _sys.identify_variable_groups(_fe_problem.identifyVariableGroupsInNL());
     179             : 
     180       63562 :   if (!_fe_problem.defaultGhosting())
     181             :   {
     182       63480 :     auto & dof_map = _sys.get_dof_map();
     183       63480 :     dof_map.remove_algebraic_ghosting_functor(dof_map.default_algebraic_ghosting());
     184       63480 :     dof_map.set_implicit_neighbor_dofs(false);
     185             :   }
     186       63562 : }
     187             : 
     188       59118 : NonlinearSystemBase::~NonlinearSystemBase() = default;
     189             : 
     190             : void
     191       61509 : NonlinearSystemBase::preInit()
     192             : {
     193       61509 :   SolverSystem::preInit();
     194             : 
     195       61509 :   if (_fe_problem.hasDampers())
     196         159 :     setupDampers();
     197             : 
     198       61509 :   if (_residual_copy.get())
     199           0 :     _residual_copy->init(_sys.n_dofs(), false, SERIAL);
     200             : 
     201             : #ifdef MOOSE_KOKKOS_ENABLED
     202       41287 :   if (_fe_problem.hasKokkosObjects())
     203         741 :     _sys.get_dof_map().full_sparsity_pattern_needed();
     204             : #endif
     205       61509 : }
     206             : 
     207             : void
     208        7575 : NonlinearSystemBase::reinitMortarFunctors()
     209             : {
     210             :   // reinit is called on meshChanged() in FEProblemBase. We could implement meshChanged() instead.
     211             :   // Subdomains might have changed
     212        7651 :   for (auto & functor : _displaced_mortar_functors)
     213          76 :     functor.second.setupMortarMaterials();
     214        7691 :   for (auto & functor : _undisplaced_mortar_functors)
     215         116 :     functor.second.setupMortarMaterials();
     216        7575 : }
     217             : 
     218             : void
     219          89 : NonlinearSystemBase::turnOffJacobian()
     220             : {
     221          89 :   system().set_basic_system_only();
     222          89 :   nonlinearSolver()->jacobian = NULL;
     223          89 : }
     224             : 
     225             : void
     226       60583 : NonlinearSystemBase::initialSetup()
     227             : {
     228      302915 :   TIME_SECTION("nlInitialSetup", 2, "Setting Up Nonlinear System");
     229             : 
     230       60583 :   SolverSystem::initialSetup();
     231             : 
     232             :   {
     233      302915 :     TIME_SECTION("kernelsInitialSetup", 2, "Setting Up Kernels/BCs/Constraints");
     234             : 
     235      126811 :     for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     236             :     {
     237       66228 :       _kernels.initialSetup(tid);
     238       66228 :       _nodal_kernels.initialSetup(tid);
     239       66228 :       _dirac_kernels.initialSetup(tid);
     240       66228 :       if (_doing_dg)
     241        1225 :         _dg_kernels.initialSetup(tid);
     242       66228 :       _interface_kernels.initialSetup(tid);
     243             : 
     244       66228 :       _element_dampers.initialSetup(tid);
     245       66228 :       _nodal_dampers.initialSetup(tid);
     246       66228 :       _integrated_bcs.initialSetup(tid);
     247             : 
     248       66228 :       if (_fe_problem.haveFV())
     249             :       {
     250        4338 :         std::vector<FVElementalKernel *> fv_elemental_kernels;
     251        4338 :         _fe_problem.theWarehouse()
     252        8676 :             .query()
     253        4338 :             .template condition<AttribSystem>("FVElementalKernel")
     254        4338 :             .template condition<AttribThread>(tid)
     255        4338 :             .queryInto(fv_elemental_kernels);
     256             : 
     257        8340 :         for (auto * fv_kernel : fv_elemental_kernels)
     258        4002 :           fv_kernel->initialSetup();
     259             : 
     260        4338 :         std::vector<FVFluxKernel *> fv_flux_kernels;
     261        4338 :         _fe_problem.theWarehouse()
     262        8676 :             .query()
     263        4338 :             .template condition<AttribSystem>("FVFluxKernel")
     264        4338 :             .template condition<AttribThread>(tid)
     265        4338 :             .queryInto(fv_flux_kernels);
     266             : 
     267        9795 :         for (auto * fv_kernel : fv_flux_kernels)
     268        5457 :           fv_kernel->initialSetup();
     269        4338 :       }
     270             :     }
     271             : 
     272       60583 :     _scalar_kernels.initialSetup();
     273       60583 :     _constraints.initialSetup();
     274       60583 :     _general_dampers.initialSetup();
     275       60583 :     _nodal_bcs.initialSetup();
     276       60583 :     _preset_nodal_bcs.residualSetup();
     277       60583 :     _ad_preset_nodal_bcs.residualSetup();
     278             : 
     279             : #ifdef MOOSE_KOKKOS_ENABLED
     280       40804 :     _kokkos_kernels.initialSetup();
     281       40804 :     _kokkos_nodal_kernels.initialSetup();
     282       40804 :     _kokkos_integrated_bcs.initialSetup();
     283       40804 :     _kokkos_nodal_bcs.initialSetup();
     284             : #endif
     285       60583 :   }
     286             : 
     287             :   {
     288      302915 :     TIME_SECTION("mortarSetup", 2, "Initializing Mortar Interfaces");
     289             : 
     290      121166 :     auto create_mortar_functors = [this](const bool displaced)
     291             :     {
     292             :       // go over mortar interfaces and construct functors
     293      121166 :       const auto & mortar_interfaces = _fe_problem.getMortarInterfaces(displaced);
     294      122186 :       for (const auto & [primary_secondary_boundary_pair, mortar_generation_ptr] :
     295      243352 :            mortar_interfaces)
     296             :       {
     297        1020 :         if (!_constraints.hasActiveMortarConstraints(primary_secondary_boundary_pair, displaced))
     298          39 :           continue;
     299             : 
     300             :         auto & mortar_constraints =
     301         981 :             _constraints.getActiveMortarConstraints(primary_secondary_boundary_pair, displaced);
     302             : 
     303             :         auto & subproblem = displaced
     304         222 :                                 ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
     305        1092 :                                 : static_cast<SubProblem &>(_fe_problem);
     306             : 
     307         981 :         auto & mortar_functors =
     308         981 :             displaced ? _displaced_mortar_functors : _undisplaced_mortar_functors;
     309             : 
     310         981 :         mortar_functors.emplace(primary_secondary_boundary_pair,
     311        2943 :                                 ComputeMortarFunctor(mortar_constraints,
     312         981 :                                                      *mortar_generation_ptr,
     313             :                                                      subproblem,
     314             :                                                      _fe_problem,
     315             :                                                      displaced,
     316         981 :                                                      subproblem.assembly(0, number())));
     317             :       }
     318      121166 :     };
     319             : 
     320       60583 :     create_mortar_functors(false);
     321       60583 :     create_mortar_functors(true);
     322       60583 :   }
     323             : 
     324       60583 :   if (_automatic_scaling)
     325             :   {
     326         445 :     if (_off_diagonals_in_auto_scaling)
     327          69 :       _scaling_matrix = std::make_unique<OffDiagonalScalingMatrix<Number>>(_communicator);
     328             :     else
     329         376 :       _scaling_matrix = std::make_unique<DiagonalMatrix<Number>>(_communicator);
     330             :   }
     331             : 
     332       60583 :   if (_preconditioner)
     333       14670 :     _preconditioner->initialSetup();
     334       60583 : }
     335             : 
     336             : void
     337      291721 : NonlinearSystemBase::timestepSetup()
     338             : {
     339      291721 :   SolverSystem::timestepSetup();
     340             : 
     341      609378 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     342             :   {
     343      317657 :     _kernels.timestepSetup(tid);
     344      317657 :     _nodal_kernels.timestepSetup(tid);
     345      317657 :     _dirac_kernels.timestepSetup(tid);
     346      317657 :     if (_doing_dg)
     347        1799 :       _dg_kernels.timestepSetup(tid);
     348      317657 :     _interface_kernels.timestepSetup(tid);
     349      317657 :     _element_dampers.timestepSetup(tid);
     350      317657 :     _nodal_dampers.timestepSetup(tid);
     351      317657 :     _integrated_bcs.timestepSetup(tid);
     352             : 
     353      317657 :     if (_fe_problem.haveFV())
     354             :     {
     355       17448 :       std::vector<FVFluxBC *> bcs;
     356       17448 :       _fe_problem.theWarehouse()
     357       34896 :           .query()
     358       17448 :           .template condition<AttribSystem>("FVFluxBC")
     359       17448 :           .template condition<AttribThread>(tid)
     360       17448 :           .queryInto(bcs);
     361             : 
     362       17448 :       std::vector<FVInterfaceKernel *> iks;
     363       17448 :       _fe_problem.theWarehouse()
     364       34896 :           .query()
     365       17448 :           .template condition<AttribSystem>("FVInterfaceKernel")
     366       17448 :           .template condition<AttribThread>(tid)
     367       17448 :           .queryInto(iks);
     368             : 
     369       17448 :       std::vector<FVFluxKernel *> kernels;
     370       17448 :       _fe_problem.theWarehouse()
     371       34896 :           .query()
     372       17448 :           .template condition<AttribSystem>("FVFluxKernel")
     373       17448 :           .template condition<AttribThread>(tid)
     374       17448 :           .queryInto(kernels);
     375             : 
     376       34465 :       for (auto * bc : bcs)
     377       17017 :         bc->timestepSetup();
     378       17846 :       for (auto * ik : iks)
     379         398 :         ik->timestepSetup();
     380       38624 :       for (auto * kernel : kernels)
     381       21176 :         kernel->timestepSetup();
     382       17448 :     }
     383             :   }
     384      291721 :   _scalar_kernels.timestepSetup();
     385      291721 :   _constraints.timestepSetup();
     386      291721 :   _general_dampers.timestepSetup();
     387      291721 :   _nodal_bcs.timestepSetup();
     388      291721 :   _preset_nodal_bcs.timestepSetup();
     389      291721 :   _ad_preset_nodal_bcs.timestepSetup();
     390             : 
     391             : #ifdef MOOSE_KOKKOS_ENABLED
     392      192261 :   _kokkos_kernels.timestepSetup();
     393      192261 :   _kokkos_nodal_kernels.timestepSetup();
     394      192261 :   _kokkos_integrated_bcs.timestepSetup();
     395      192261 :   _kokkos_nodal_bcs.timestepSetup();
     396             : #endif
     397      291721 : }
     398             : 
     399             : void
     400     1950014 : NonlinearSystemBase::customSetup(const ExecFlagType & exec_type)
     401             : {
     402     1950014 :   SolverSystem::customSetup(exec_type);
     403             : 
     404     4074975 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     405             :   {
     406     2124961 :     _kernels.customSetup(exec_type, tid);
     407     2124961 :     _nodal_kernels.customSetup(exec_type, tid);
     408     2124961 :     _dirac_kernels.customSetup(exec_type, tid);
     409     2124961 :     if (_doing_dg)
     410       12322 :       _dg_kernels.customSetup(exec_type, tid);
     411     2124961 :     _interface_kernels.customSetup(exec_type, tid);
     412     2124961 :     _element_dampers.customSetup(exec_type, tid);
     413     2124961 :     _nodal_dampers.customSetup(exec_type, tid);
     414     2124961 :     _integrated_bcs.customSetup(exec_type, tid);
     415             : 
     416     2124961 :     if (_fe_problem.haveFV())
     417             :     {
     418      128935 :       std::vector<FVFluxBC *> bcs;
     419      128935 :       _fe_problem.theWarehouse()
     420      257870 :           .query()
     421      128935 :           .template condition<AttribSystem>("FVFluxBC")
     422      128935 :           .template condition<AttribThread>(tid)
     423      128935 :           .queryInto(bcs);
     424             : 
     425      128935 :       std::vector<FVInterfaceKernel *> iks;
     426      128935 :       _fe_problem.theWarehouse()
     427      257870 :           .query()
     428      128935 :           .template condition<AttribSystem>("FVInterfaceKernel")
     429      128935 :           .template condition<AttribThread>(tid)
     430      128935 :           .queryInto(iks);
     431             : 
     432      128935 :       std::vector<FVFluxKernel *> kernels;
     433      128935 :       _fe_problem.theWarehouse()
     434      257870 :           .query()
     435      128935 :           .template condition<AttribSystem>("FVFluxKernel")
     436      128935 :           .template condition<AttribThread>(tid)
     437      128935 :           .queryInto(kernels);
     438             : 
     439      232415 :       for (auto * bc : bcs)
     440      103480 :         bc->customSetup(exec_type);
     441      173154 :       for (auto * ik : iks)
     442       44219 :         ik->customSetup(exec_type);
     443      306653 :       for (auto * kernel : kernels)
     444      177718 :         kernel->customSetup(exec_type);
     445      128935 :     }
     446             :   }
     447     1950014 :   _scalar_kernels.customSetup(exec_type);
     448     1950014 :   _constraints.customSetup(exec_type);
     449     1950014 :   _general_dampers.customSetup(exec_type);
     450     1950014 :   _nodal_bcs.customSetup(exec_type);
     451     1950014 :   _preset_nodal_bcs.customSetup(exec_type);
     452     1950014 :   _ad_preset_nodal_bcs.customSetup(exec_type);
     453             : 
     454             : #ifdef MOOSE_KOKKOS_ENABLED
     455     1284455 :   _kokkos_kernels.customSetup(exec_type);
     456     1284455 :   _kokkos_nodal_kernels.customSetup(exec_type);
     457     1284455 :   _kokkos_integrated_bcs.customSetup(exec_type);
     458     1284455 :   _kokkos_nodal_bcs.customSetup(exec_type);
     459             : #endif
     460     1950014 : }
     461             : 
     462             : void
     463      347920 : NonlinearSystemBase::setupDM()
     464             : {
     465      347920 :   if (_fsp)
     466         129 :     _fsp->setupDM();
     467      347920 : }
     468             : 
     469             : void
     470       83233 : NonlinearSystemBase::addKernel(const std::string & kernel_name,
     471             :                                const std::string & name,
     472             :                                InputParameters & parameters)
     473             : {
     474      174007 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     475             :   {
     476             :     // Create the kernel object via the factory and add to warehouse
     477             :     std::shared_ptr<KernelBase> kernel =
     478       90978 :         _factory.create<KernelBase>(kernel_name, name, parameters, tid);
     479       90798 :     _kernels.addObject(kernel, tid);
     480       90778 :     postAddResidualObject(*kernel);
     481             :     // Add to theWarehouse, a centralized storage for all moose objects
     482       90774 :     _fe_problem.theWarehouse().add(kernel);
     483       90774 :   }
     484             : 
     485       83029 :   if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     486         130 :     _has_save_in = true;
     487       83029 :   if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     488         104 :     _has_diag_save_in = true;
     489       83029 : }
     490             : 
     491             : void
     492         808 : NonlinearSystemBase::addHDGKernel(const std::string & kernel_name,
     493             :                                   const std::string & name,
     494             :                                   InputParameters & parameters)
     495             : {
     496        1621 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     497             :   {
     498             :     // Create the kernel object via the factory and add to warehouse
     499         813 :     auto kernel = _factory.create<HDGKernel>(kernel_name, name, parameters, tid);
     500         813 :     _kernels.addObject(kernel, tid);
     501         813 :     _hybridized_kernels.addObject(kernel, tid);
     502             :     // Add to theWarehouse, a centralized storage for all moose objects
     503         813 :     _fe_problem.theWarehouse().add(kernel);
     504         813 :     postAddResidualObject(*kernel);
     505         813 :   }
     506         808 : }
     507             : 
     508             : void
     509         570 : NonlinearSystemBase::addNodalKernel(const std::string & kernel_name,
     510             :                                     const std::string & name,
     511             :                                     InputParameters & parameters)
     512             : {
     513        1241 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     514             :   {
     515             :     // Create the kernel object via the factory and add to the warehouse
     516             :     std::shared_ptr<NodalKernelBase> kernel =
     517         671 :         _factory.create<NodalKernelBase>(kernel_name, name, parameters, tid);
     518         671 :     _nodal_kernels.addObject(kernel, tid);
     519             :     // Add to theWarehouse, a centralized storage for all moose objects
     520         671 :     _fe_problem.theWarehouse().add(kernel);
     521         671 :     postAddResidualObject(*kernel);
     522         671 :   }
     523             : 
     524         570 :   if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     525           0 :     _has_save_in = true;
     526         570 :   if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     527           0 :     _has_diag_save_in = true;
     528         570 : }
     529             : 
     530             : void
     531        1551 : NonlinearSystemBase::addScalarKernel(const std::string & kernel_name,
     532             :                                      const std::string & name,
     533             :                                      InputParameters & parameters)
     534             : {
     535             :   std::shared_ptr<ScalarKernelBase> kernel =
     536        1551 :       _factory.create<ScalarKernelBase>(kernel_name, name, parameters);
     537        1543 :   postAddResidualObject(*kernel);
     538             :   // Add to theWarehouse, a centralized storage for all moose objects
     539        1543 :   _fe_problem.theWarehouse().add(kernel);
     540        1543 :   _scalar_kernels.addObject(kernel);
     541        1543 : }
     542             : 
     543             : void
     544       82800 : NonlinearSystemBase::addBoundaryCondition(const std::string & bc_name,
     545             :                                           const std::string & name,
     546             :                                           InputParameters & parameters)
     547             : {
     548             :   // ThreadID
     549       82800 :   THREAD_ID tid = 0;
     550             : 
     551             :   // Create the object
     552             :   std::shared_ptr<BoundaryCondition> bc =
     553       82800 :       _factory.create<BoundaryCondition>(bc_name, name, parameters, tid);
     554       82746 :   postAddResidualObject(*bc);
     555             : 
     556             :   // Active BoundaryIDs for the object
     557       82746 :   const std::set<BoundaryID> & boundary_ids = bc->boundaryIDs();
     558       82746 :   auto bc_var = dynamic_cast<const MooseVariableFieldBase *>(&bc->variable());
     559       82746 :   _vars[tid].addBoundaryVar(boundary_ids, bc_var);
     560             : 
     561             :   // Cast to the various types of BCs
     562       82746 :   std::shared_ptr<NodalBCBase> nbc = std::dynamic_pointer_cast<NodalBCBase>(bc);
     563       82746 :   std::shared_ptr<IntegratedBCBase> ibc = std::dynamic_pointer_cast<IntegratedBCBase>(bc);
     564             : 
     565             :   // NodalBCBase
     566       82746 :   if (nbc)
     567             :   {
     568       73504 :     if (nbc->checkNodalVar() && !nbc->variable().isNodal())
     569           4 :       mooseError("Trying to use nodal boundary condition '",
     570           4 :                  nbc->name(),
     571             :                  "' on a non-nodal variable '",
     572           4 :                  nbc->variable().name(),
     573             :                  "'.");
     574             : 
     575       73500 :     _nodal_bcs.addObject(nbc);
     576             :     // Add to theWarehouse, a centralized storage for all moose objects
     577       73500 :     _fe_problem.theWarehouse().add(nbc);
     578       73500 :     _vars[tid].addBoundaryVars(boundary_ids, nbc->getCoupledVars());
     579             : 
     580       73500 :     if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     581          99 :       _has_nodalbc_save_in = true;
     582       73500 :     if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     583          21 :       _has_nodalbc_diag_save_in = true;
     584             : 
     585             :     // DirichletBCs that are preset
     586       73500 :     std::shared_ptr<DirichletBCBase> dbc = std::dynamic_pointer_cast<DirichletBCBase>(bc);
     587       73500 :     if (dbc && dbc->preset())
     588       63327 :       _preset_nodal_bcs.addObject(dbc);
     589             : 
     590       73500 :     std::shared_ptr<ADDirichletBCBase> addbc = std::dynamic_pointer_cast<ADDirichletBCBase>(bc);
     591       73500 :     if (addbc && addbc->preset())
     592        1636 :       _ad_preset_nodal_bcs.addObject(addbc);
     593       73500 :   }
     594             : 
     595             :   // IntegratedBCBase
     596        9242 :   else if (ibc)
     597             :   {
     598        9242 :     _integrated_bcs.addObject(ibc, tid);
     599             :     // Add to theWarehouse, a centralized storage for all moose objects
     600        9242 :     _fe_problem.theWarehouse().add(ibc);
     601        9242 :     _vars[tid].addBoundaryVars(boundary_ids, ibc->getCoupledVars());
     602             : 
     603        9242 :     if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     604          86 :       _has_save_in = true;
     605        9242 :     if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     606          60 :       _has_diag_save_in = true;
     607             : 
     608        9936 :     for (tid = 1; tid < libMesh::n_threads(); tid++)
     609             :     {
     610             :       // Create the object
     611         694 :       bc = _factory.create<BoundaryCondition>(bc_name, name, parameters, tid);
     612             : 
     613             :       // Give users opportunity to set some parameters
     614         694 :       postAddResidualObject(*bc);
     615             : 
     616             :       // Active BoundaryIDs for the object
     617         694 :       const std::set<BoundaryID> & boundary_ids = bc->boundaryIDs();
     618         694 :       _vars[tid].addBoundaryVar(boundary_ids, bc_var);
     619             : 
     620         694 :       ibc = std::static_pointer_cast<IntegratedBCBase>(bc);
     621             : 
     622         694 :       _integrated_bcs.addObject(ibc, tid);
     623         694 :       _vars[tid].addBoundaryVars(boundary_ids, ibc->getCoupledVars());
     624             :     }
     625             :   }
     626             : 
     627             :   else
     628           0 :     mooseError("Unknown BoundaryCondition type for object named ", bc->name());
     629       82742 : }
     630             : 
     631             : void
     632        1727 : NonlinearSystemBase::addConstraint(const std::string & c_name,
     633             :                                    const std::string & name,
     634             :                                    InputParameters & parameters)
     635             : {
     636        1727 :   std::shared_ptr<Constraint> constraint = _factory.create<Constraint>(c_name, name, parameters);
     637        1719 :   _constraints.addObject(constraint);
     638        1719 :   postAddResidualObject(*constraint);
     639             : 
     640        1719 :   if (constraint && constraint->addCouplingEntriesToJacobian())
     641        1706 :     addImplicitGeometricCouplingEntriesToJacobian(true);
     642        1719 : }
     643             : 
     644             : void
     645         915 : NonlinearSystemBase::addDiracKernel(const std::string & kernel_name,
     646             :                                     const std::string & name,
     647             :                                     InputParameters & parameters)
     648             : {
     649        1906 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     650             :   {
     651             :     std::shared_ptr<DiracKernelBase> kernel =
     652         999 :         _factory.create<DiracKernelBase>(kernel_name, name, parameters, tid);
     653         991 :     postAddResidualObject(*kernel);
     654         991 :     _dirac_kernels.addObject(kernel, tid);
     655             :     // Add to theWarehouse, a centralized storage for all moose objects
     656         991 :     _fe_problem.theWarehouse().add(kernel);
     657         991 :   }
     658         907 : }
     659             : 
     660             : void
     661        1449 : NonlinearSystemBase::addDGKernel(std::string dg_kernel_name,
     662             :                                  const std::string & name,
     663             :                                  InputParameters & parameters)
     664             : {
     665        3022 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
     666             :   {
     667        1573 :     auto dg_kernel = _factory.create<DGKernelBase>(dg_kernel_name, name, parameters, tid);
     668        1573 :     _dg_kernels.addObject(dg_kernel, tid);
     669             :     // Add to theWarehouse, a centralized storage for all moose objects
     670        1573 :     _fe_problem.theWarehouse().add(dg_kernel);
     671        1573 :     postAddResidualObject(*dg_kernel);
     672        1573 :   }
     673             : 
     674        1449 :   _doing_dg = true;
     675             : 
     676        1449 :   if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     677          52 :     _has_save_in = true;
     678        1449 :   if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     679          39 :     _has_diag_save_in = true;
     680        1449 : }
     681             : 
     682             : void
     683         915 : NonlinearSystemBase::addInterfaceKernel(std::string interface_kernel_name,
     684             :                                         const std::string & name,
     685             :                                         InputParameters & parameters)
     686             : {
     687        1906 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
     688             :   {
     689             :     std::shared_ptr<InterfaceKernelBase> interface_kernel =
     690         991 :         _factory.create<InterfaceKernelBase>(interface_kernel_name, name, parameters, tid);
     691         991 :     postAddResidualObject(*interface_kernel);
     692             : 
     693         991 :     const std::set<BoundaryID> & boundary_ids = interface_kernel->boundaryIDs();
     694         991 :     auto ik_var = dynamic_cast<const MooseVariableFieldBase *>(&interface_kernel->variable());
     695         991 :     _vars[tid].addBoundaryVar(boundary_ids, ik_var);
     696             : 
     697         991 :     _interface_kernels.addObject(interface_kernel, tid);
     698             :     // Add to theWarehouse, a centralized storage for all moose objects
     699         991 :     _fe_problem.theWarehouse().add(interface_kernel);
     700         991 :     _vars[tid].addBoundaryVars(boundary_ids, interface_kernel->getCoupledVars());
     701         991 :   }
     702         915 : }
     703             : 
     704             : void
     705         177 : NonlinearSystemBase::addDamper(const std::string & damper_name,
     706             :                                const std::string & name,
     707             :                                InputParameters & parameters)
     708             : {
     709         328 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
     710             :   {
     711         218 :     std::shared_ptr<Damper> damper = _factory.create<Damper>(damper_name, name, parameters, tid);
     712             : 
     713             :     // Attempt to cast to the damper types
     714         218 :     std::shared_ptr<ElementDamper> ed = std::dynamic_pointer_cast<ElementDamper>(damper);
     715         218 :     std::shared_ptr<NodalDamper> nd = std::dynamic_pointer_cast<NodalDamper>(damper);
     716         218 :     std::shared_ptr<GeneralDamper> gd = std::dynamic_pointer_cast<GeneralDamper>(damper);
     717             : 
     718         218 :     if (gd)
     719             :     {
     720          67 :       _general_dampers.addObject(gd);
     721          67 :       break; // not threaded
     722             :     }
     723         151 :     else if (ed)
     724          92 :       _element_dampers.addObject(ed, tid);
     725          59 :     else if (nd)
     726          59 :       _nodal_dampers.addObject(nd, tid);
     727             :     else
     728           0 :       mooseError("Invalid damper type");
     729         419 :   }
     730         177 : }
     731             : 
     732             : void
     733         485 : NonlinearSystemBase::addSplit(const std::string & split_name,
     734             :                               const std::string & name,
     735             :                               InputParameters & parameters)
     736             : {
     737         485 :   std::shared_ptr<Split> split = _factory.create<Split>(split_name, name, parameters);
     738         485 :   _splits.addObject(split);
     739             :   // Add to theWarehouse, a centralized storage for all moose objects
     740         485 :   _fe_problem.theWarehouse().add(split);
     741         485 : }
     742             : 
     743             : std::shared_ptr<Split>
     744         485 : NonlinearSystemBase::getSplit(const std::string & name)
     745             : {
     746         485 :   return _splits.getActiveObject(name);
     747             : }
     748             : 
     749             : bool
     750      316641 : NonlinearSystemBase::shouldEvaluatePreSMOResidual() const
     751             : {
     752      316641 :   if (_fe_problem.solverParams(number())._type == Moose::ST_LINEAR)
     753       10807 :     return false;
     754             : 
     755             :   // The legacy behavior (#10464) _always_ performs the pre-SMO residual evaluation
     756             :   // regardless of whether it is needed.
     757             :   //
     758             :   // This is not ideal and has been fixed by #23472. This legacy option ensures a smooth transition
     759             :   // to the new behavior. Modules and Apps that want to migrate to the new behavior should set this
     760             :   // parameter to false.
     761      305834 :   if (_app.parameters().get<bool>("use_legacy_initial_residual_evaluation_behavior"))
     762           0 :     return true;
     763             : 
     764      305834 :   return _use_pre_smo_residual;
     765             : }
     766             : 
     767             : Real
     768      394364 : NonlinearSystemBase::referenceResidual() const
     769             : {
     770      394364 :   return usePreSMOResidual() ? preSMOResidual() : initialResidual();
     771             : }
     772             : 
     773             : Real
     774         171 : NonlinearSystemBase::preSMOResidual() const
     775             : {
     776         171 :   if (!shouldEvaluatePreSMOResidual())
     777           0 :     mooseError("pre-SMO residual is requested but not evaluated.");
     778             : 
     779         171 :   return _pre_smo_residual;
     780             : }
     781             : 
     782             : Real
     783      394476 : NonlinearSystemBase::initialResidual() const
     784             : {
     785      394476 :   return _initial_residual;
     786             : }
     787             : 
     788             : void
     789      313818 : NonlinearSystemBase::setInitialResidual(Real r)
     790             : {
     791      313818 :   _initial_residual = r;
     792      313818 : }
     793             : 
     794             : void
     795           0 : NonlinearSystemBase::zeroVectorForResidual(const std::string & vector_name)
     796             : {
     797           0 :   for (unsigned int i = 0; i < _vecs_to_zero_for_residual.size(); ++i)
     798           0 :     if (vector_name == _vecs_to_zero_for_residual[i])
     799           0 :       return;
     800             : 
     801           0 :   _vecs_to_zero_for_residual.push_back(vector_name);
     802             : }
     803             : 
     804             : void
     805         131 : NonlinearSystemBase::computeResidualTag(NumericVector<Number> & residual, TagID tag_id)
     806             : {
     807         131 :   _nl_vector_tags.clear();
     808         131 :   _nl_vector_tags.insert(tag_id);
     809         131 :   _nl_vector_tags.insert(residualVectorTag());
     810             : 
     811         131 :   associateVectorToTag(residual, residualVectorTag());
     812             : 
     813         131 :   computeResidualTags(_nl_vector_tags);
     814             : 
     815         131 :   disassociateVectorFromTag(residual, residualVectorTag());
     816         131 : }
     817             : 
     818             : void
     819           0 : NonlinearSystemBase::computeResidual(NumericVector<Number> & residual, TagID tag_id)
     820             : {
     821           0 :   mooseDeprecated(" Please use computeResidualTag");
     822             : 
     823           0 :   computeResidualTag(residual, tag_id);
     824           0 : }
     825             : 
     826             : void
     827     3338296 : NonlinearSystemBase::computeResidualTags(const std::set<TagID> & tags)
     828             : {
     829             :   parallel_object_only();
     830             : 
     831    10014888 :   TIME_SECTION("nl::computeResidualTags", 5);
     832             : 
     833     3338296 :   _fe_problem.setCurrentNonlinearSystem(number());
     834     3338296 :   _fe_problem.setCurrentlyComputingResidual(true);
     835             : 
     836     3338296 :   bool required_residual = tags.find(residualVectorTag()) == tags.end() ? false : true;
     837             : 
     838     3338296 :   _n_residual_evaluations++;
     839             : 
     840             :   // not suppose to do anythin on matrix
     841     3338296 :   deactivateAllMatrixTags();
     842             : 
     843     3338296 :   FloatingPointExceptionGuard fpe_guard(_app);
     844             : 
     845     3338296 :   for (const auto & numeric_vec : _vecs_to_zero_for_residual)
     846           0 :     if (hasVector(numeric_vec))
     847             :     {
     848           0 :       NumericVector<Number> & vec = getVector(numeric_vec);
     849           0 :       vec.close();
     850           0 :       vec.zero();
     851             :     }
     852             : 
     853             :   try
     854             :   {
     855     3338296 :     zeroTaggedVectors(tags);
     856     3338296 :     computeResidualInternal(tags);
     857     3338131 :     closeTaggedVectors(tags);
     858             : 
     859     3338131 :     if (required_residual)
     860             :     {
     861     3306219 :       auto & residual = getVector(residualVectorTag());
     862     3306219 :       if (!_time_integrators.empty())
     863             :       {
     864     5815209 :         for (auto & ti : _time_integrators)
     865     2916030 :           ti->postResidual(residual);
     866             :       }
     867             :       else
     868      407040 :         residual += *_Re_non_time;
     869     3306219 :       residual.close();
     870             :     }
     871     3338131 :     if (_fe_problem.computingScalingResidual())
     872             :       // We don't want to do nodal bcs or anything else
     873          50 :       return;
     874             : 
     875     3338081 :     computeNodalBCs(tags);
     876     3338081 :     closeTaggedVectors(tags);
     877             : 
     878             :     // If we are debugging residuals we need one more assignment to have the ghosted copy up to
     879             :     // date
     880     3338081 :     if (_need_residual_ghosted && _debugging_residuals && required_residual)
     881             :     {
     882        2010 :       auto & residual = getVector(residualVectorTag());
     883             : 
     884        2010 :       *_residual_ghosted = residual;
     885        2010 :       _residual_ghosted->close();
     886             :     }
     887             :     // Need to close and update the aux system in case residuals were saved to it.
     888     3338081 :     if (_has_nodalbc_save_in)
     889         171 :       _fe_problem.getAuxiliarySystem().solution().close();
     890     3338081 :     if (hasSaveIn())
     891         309 :       _fe_problem.getAuxiliarySystem().update();
     892             :   }
     893         121 :   catch (MooseException & e)
     894             :   {
     895             :     // The buck stops here, we have already handled the exception by
     896             :     // calling stopSolve(), it is now up to PETSc to return a
     897             :     // "diverged" reason during the next solve.
     898         121 :   }
     899             : 
     900             :   // not supposed to do anything on matrix
     901     3338202 :   activateAllMatrixTags();
     902             : 
     903     3338202 :   _fe_problem.setCurrentlyComputingResidual(false);
     904     3338302 : }
     905             : 
     906             : void
     907        3467 : NonlinearSystemBase::computeResidualAndJacobianTags(const std::set<TagID> & vector_tags,
     908             :                                                     const std::set<TagID> & matrix_tags)
     909             : {
     910             :   const bool required_residual =
     911        3467 :       vector_tags.find(residualVectorTag()) == vector_tags.end() ? false : true;
     912             : 
     913             :   try
     914             :   {
     915        3467 :     zeroTaggedVectors(vector_tags);
     916        3467 :     computeResidualAndJacobianInternal(vector_tags, matrix_tags);
     917        3467 :     closeTaggedVectors(vector_tags);
     918        3467 :     closeTaggedMatrices(matrix_tags);
     919             : 
     920        3467 :     if (required_residual)
     921             :     {
     922        3467 :       auto & residual = getVector(residualVectorTag());
     923        3467 :       if (!_time_integrators.empty())
     924             :       {
     925        3818 :         for (auto & ti : _time_integrators)
     926        1909 :           ti->postResidual(residual);
     927             :       }
     928             :       else
     929        1558 :         residual += *_Re_non_time;
     930        3467 :       residual.close();
     931             :     }
     932             : 
     933        3467 :     computeNodalBCsResidualAndJacobian();
     934        3467 :     closeTaggedVectors(vector_tags);
     935        3467 :     closeTaggedMatrices(matrix_tags);
     936             :   }
     937           0 :   catch (MooseException & e)
     938             :   {
     939             :     // The buck stops here, we have already handled the exception by
     940             :     // calling stopSolve(), it is now up to PETSc to return a
     941             :     // "diverged" reason during the next solve.
     942           0 :   }
     943        3467 : }
     944             : 
     945             : void
     946      262435 : NonlinearSystemBase::onTimestepBegin()
     947             : {
     948      525588 :   for (auto & ti : _time_integrators)
     949      263153 :     ti->preSolve();
     950      262435 :   if (_predictor.get())
     951         387 :     _predictor->timestepSetup();
     952      262435 : }
     953             : 
     954             : void
     955      317776 : NonlinearSystemBase::setInitialSolution()
     956             : {
     957      317776 :   deactivateAllMatrixTags();
     958             : 
     959      317776 :   NumericVector<Number> & initial_solution(solution());
     960      317776 :   if (_predictor.get())
     961             :   {
     962         387 :     if (_predictor->shouldApply())
     963             :     {
     964        1115 :       TIME_SECTION("applyPredictor", 2, "Applying Predictor");
     965             : 
     966         223 :       _predictor->apply(initial_solution);
     967         223 :       _fe_problem.predictorCleanup(initial_solution);
     968         223 :     }
     969             :     else
     970         164 :       _console << " Skipping predictor this step" << std::endl;
     971             :   }
     972             : 
     973             :   // do nodal BC
     974             :   {
     975     1588880 :     TIME_SECTION("initialBCs", 2, "Applying BCs To Initial Condition");
     976             : 
     977      317776 :     const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
     978    15569790 :     for (const auto & bnode : bnd_nodes)
     979             :     {
     980    15252014 :       BoundaryID boundary_id = bnode->_bnd_id;
     981    15252014 :       Node * node = bnode->_node;
     982             : 
     983    15252014 :       if (node->processor_id() == processor_id())
     984             :       {
     985    11703088 :         bool has_preset_nodal_bcs = _preset_nodal_bcs.hasActiveBoundaryObjects(boundary_id);
     986    11703088 :         bool has_ad_preset_nodal_bcs = _ad_preset_nodal_bcs.hasActiveBoundaryObjects(boundary_id);
     987             : 
     988             :         // reinit variables in nodes
     989    11703088 :         if (has_preset_nodal_bcs || has_ad_preset_nodal_bcs)
     990     3685256 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
     991             : 
     992    11703088 :         if (has_preset_nodal_bcs)
     993             :         {
     994     3648536 :           const auto & preset_bcs = _preset_nodal_bcs.getActiveBoundaryObjects(boundary_id);
     995     7956144 :           for (const auto & preset_bc : preset_bcs)
     996     4307608 :             preset_bc->computeValue(initial_solution);
     997             :         }
     998    11703088 :         if (has_ad_preset_nodal_bcs)
     999             :         {
    1000       36720 :           const auto & preset_bcs_res = _ad_preset_nodal_bcs.getActiveBoundaryObjects(boundary_id);
    1001       77278 :           for (const auto & preset_bc : preset_bcs_res)
    1002       40558 :             preset_bc->computeValue(initial_solution);
    1003             :         }
    1004             :       }
    1005             :     }
    1006      317776 :   }
    1007             : 
    1008             : #ifdef MOOSE_KOKKOS_ENABLED
    1009      209292 :   if (_kokkos_preset_nodal_bcs.hasObjects())
    1010        1889 :     setKokkosInitialSolution();
    1011             : #endif
    1012             : 
    1013      317776 :   _sys.solution->close();
    1014      317776 :   update();
    1015             : 
    1016             :   // Set constraint secondary values
    1017      317776 :   setConstraintSecondaryValues(initial_solution, false);
    1018             : 
    1019      317776 :   if (_fe_problem.getDisplacedProblem())
    1020       35761 :     setConstraintSecondaryValues(initial_solution, true);
    1021      317776 : }
    1022             : 
    1023             : void
    1024         121 : NonlinearSystemBase::setPredictor(std::shared_ptr<Predictor> predictor)
    1025             : {
    1026         121 :   _predictor = predictor;
    1027         121 : }
    1028             : 
    1029             : void
    1030     6214521 : NonlinearSystemBase::subdomainSetup(SubdomainID subdomain, THREAD_ID tid)
    1031             : {
    1032     6214521 :   SolverSystem::subdomainSetup();
    1033             : 
    1034     6214521 :   _kernels.subdomainSetup(subdomain, tid);
    1035     6214521 :   _nodal_kernels.subdomainSetup(subdomain, tid);
    1036     6214521 :   _element_dampers.subdomainSetup(subdomain, tid);
    1037     6214521 :   _nodal_dampers.subdomainSetup(subdomain, tid);
    1038     6214521 : }
    1039             : 
    1040             : NumericVector<Number> &
    1041       31985 : NonlinearSystemBase::getResidualTimeVector()
    1042             : {
    1043       31985 :   if (!_Re_time)
    1044             :   {
    1045       31879 :     _Re_time_tag = _fe_problem.addVectorTag("TIME");
    1046             : 
    1047             :     // Most applications don't need the expense of ghosting
    1048       31879 :     ParallelType ptype = _need_residual_ghosted ? GHOSTED : PARALLEL;
    1049       31879 :     _Re_time = &addVector(_Re_time_tag, false, ptype);
    1050             :   }
    1051         106 :   else if (_need_residual_ghosted && _Re_time->type() == PARALLEL)
    1052             :   {
    1053           0 :     const auto vector_name = _subproblem.vectorTagName(_Re_time_tag);
    1054             : 
    1055             :     // If an application changes its mind, the libMesh API lets us
    1056             :     // change the vector.
    1057           0 :     _Re_time = &system().add_vector(vector_name, false, GHOSTED);
    1058           0 :   }
    1059             : 
    1060       31985 :   return *_Re_time;
    1061             : }
    1062             : 
    1063             : NumericVector<Number> &
    1064       95754 : NonlinearSystemBase::getResidualNonTimeVector()
    1065             : {
    1066       95754 :   if (!_Re_non_time)
    1067             :   {
    1068       63562 :     _Re_non_time_tag = _fe_problem.addVectorTag("NONTIME");
    1069             : 
    1070             :     // Most applications don't need the expense of ghosting
    1071       63562 :     ParallelType ptype = _need_residual_ghosted ? GHOSTED : PARALLEL;
    1072       63562 :     _Re_non_time = &addVector(_Re_non_time_tag, false, ptype);
    1073             :   }
    1074       32192 :   else if (_need_residual_ghosted && _Re_non_time->type() == PARALLEL)
    1075             :   {
    1076           0 :     const auto vector_name = _subproblem.vectorTagName(_Re_non_time_tag);
    1077             : 
    1078             :     // If an application changes its mind, the libMesh API lets us
    1079             :     // change the vector.
    1080           0 :     _Re_non_time = &system().add_vector(vector_name, false, GHOSTED);
    1081           0 :   }
    1082             : 
    1083       95754 :   return *_Re_non_time;
    1084             : }
    1085             : 
    1086             : NumericVector<Number> &
    1087           0 : NonlinearSystemBase::residualVector(TagID tag)
    1088             : {
    1089           0 :   mooseDeprecated("Please use getVector()");
    1090           0 :   switch (tag)
    1091             :   {
    1092           0 :     case 0:
    1093           0 :       return getResidualNonTimeVector();
    1094             : 
    1095           0 :     case 1:
    1096           0 :       return getResidualTimeVector();
    1097             : 
    1098           0 :     default:
    1099           0 :       mooseError("The required residual vector is not available");
    1100             :   }
    1101             : }
    1102             : 
    1103             : void
    1104       23409 : NonlinearSystemBase::enforceNodalConstraintsResidual(NumericVector<Number> & residual)
    1105             : {
    1106       23409 :   THREAD_ID tid = 0; // constraints are going to be done single-threaded
    1107       23409 :   residual.close();
    1108       23409 :   if (_constraints.hasActiveNodalConstraints())
    1109             :   {
    1110         602 :     const auto & ncs = _constraints.getActiveNodalConstraints();
    1111        1204 :     for (const auto & nc : ncs)
    1112             :     {
    1113         602 :       std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
    1114         602 :       std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
    1115             : 
    1116         602 :       if ((secondary_node_ids.size() > 0) && (primary_node_ids.size() > 0))
    1117             :       {
    1118         602 :         _fe_problem.reinitNodes(primary_node_ids, tid);
    1119         602 :         _fe_problem.reinitNodesNeighbor(secondary_node_ids, tid);
    1120         602 :         nc->computeResidual(residual);
    1121             :       }
    1122             :     }
    1123         602 :     _fe_problem.addCachedResidualDirectly(residual, tid);
    1124         602 :     residual.close();
    1125             :   }
    1126       23409 : }
    1127             : 
    1128             : void
    1129        3667 : NonlinearSystemBase::enforceNodalConstraintsJacobian()
    1130             : {
    1131        3667 :   if (!hasMatrix(systemMatrixTag()))
    1132           0 :     mooseError(" A system matrix is required");
    1133             : 
    1134        3667 :   auto & jacobian = getMatrix(systemMatrixTag());
    1135        3667 :   THREAD_ID tid = 0; // constraints are going to be done single-threaded
    1136             : 
    1137        3667 :   if (_constraints.hasActiveNodalConstraints())
    1138             :   {
    1139         121 :     const auto & ncs = _constraints.getActiveNodalConstraints();
    1140         242 :     for (const auto & nc : ncs)
    1141             :     {
    1142         121 :       std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
    1143         121 :       std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
    1144             : 
    1145         121 :       if ((secondary_node_ids.size() > 0) && (primary_node_ids.size() > 0))
    1146             :       {
    1147         121 :         _fe_problem.reinitNodes(primary_node_ids, tid);
    1148         121 :         _fe_problem.reinitNodesNeighbor(secondary_node_ids, tid);
    1149         121 :         nc->computeJacobian(jacobian);
    1150             :       }
    1151             :     }
    1152         121 :     _fe_problem.addCachedJacobian(tid);
    1153             :   }
    1154        3667 : }
    1155             : 
    1156             : void
    1157      108178 : NonlinearSystemBase::reinitNodeFace(const Node & secondary_node,
    1158             :                                     const BoundaryID secondary_boundary,
    1159             :                                     const PenetrationInfo & info,
    1160             :                                     const bool displaced)
    1161             : {
    1162      115408 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1163      165882 :                                 : static_cast<SubProblem &>(_fe_problem);
    1164             : 
    1165      108178 :   const Elem * primary_elem = info._elem;
    1166      108178 :   unsigned int primary_side = info._side_num;
    1167      108178 :   std::vector<Point> points;
    1168      108178 :   points.push_back(info._closest_point);
    1169             : 
    1170             :   // *These next steps MUST be done in this order!*
    1171             :   // ADL: This is a Chesterton's fence situation. I don't know which calls exactly the above comment
    1172             :   // is referring to. If I had to guess I would guess just the reinitNodeFace and prepareAssembly
    1173             :   // calls since the former will size the variable's dof indices and then the latter will resize the
    1174             :   // residual/Jacobian based off the variable's cached dof indices size
    1175             : 
    1176             :   // This reinits the variables that exist on the secondary node
    1177      108178 :   _fe_problem.reinitNodeFace(&secondary_node, secondary_boundary, 0);
    1178             : 
    1179             :   // This will set aside residual and jacobian space for the variables that have dofs on
    1180             :   // the secondary node
    1181      108178 :   _fe_problem.prepareAssembly(0);
    1182             : 
    1183      108178 :   _fe_problem.setNeighborSubdomainID(primary_elem, 0);
    1184             : 
    1185             :   //
    1186             :   // Reinit material on undisplaced mesh
    1187             :   //
    1188             : 
    1189             :   const Elem * const undisplaced_primary_elem =
    1190      108178 :       displaced ? _mesh.elemPtr(primary_elem->id()) : primary_elem;
    1191             :   const Point undisplaced_primary_physical_point =
    1192           0 :       [&points, displaced, primary_elem, undisplaced_primary_elem]()
    1193             :   {
    1194      108178 :     if (displaced)
    1195             :     {
    1196             :       const Point reference_point =
    1197       57704 :           FEMap::inverse_map(primary_elem->dim(), primary_elem, points[0]);
    1198       57704 :       return FEMap::map(primary_elem->dim(), undisplaced_primary_elem, reference_point);
    1199             :     }
    1200             :     else
    1201             :       // If our penetration locator is on the reference mesh, then our undisplaced
    1202             :       // physical point is simply the point coming from the penetration locator
    1203       50474 :       return points[0];
    1204      108178 :   }();
    1205             : 
    1206      216356 :   _fe_problem.reinitNeighborPhys(
    1207             :       undisplaced_primary_elem, primary_side, {undisplaced_primary_physical_point}, 0);
    1208             :   // Stateful material properties are only initialized for neighbor material data for internal faces
    1209             :   // for discontinuous Galerkin methods or for conforming interfaces for interface kernels. We don't
    1210             :   // have either of those use cases here where we likely have disconnected meshes
    1211      108178 :   _fe_problem.reinitMaterialsNeighbor(primary_elem->subdomain_id(), 0, /*swap_stateful=*/false);
    1212             : 
    1213             :   // Reinit points for constraint enforcement
    1214      108178 :   if (displaced)
    1215       57704 :     subproblem.reinitNeighborPhys(primary_elem, primary_side, points, 0);
    1216      108178 : }
    1217             : 
    1218             : void
    1219      353537 : NonlinearSystemBase::setConstraintSecondaryValues(NumericVector<Number> & solution, bool displaced)
    1220             : {
    1221             : 
    1222             :   if (displaced)
    1223             :     mooseAssert(_fe_problem.getDisplacedProblem(),
    1224             :                 "If we're calling this method with displaced = true, then we better well have a "
    1225             :                 "displaced problem");
    1226       71522 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1227      389298 :                                 : static_cast<SubProblem &>(_fe_problem);
    1228      353537 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    1229             : 
    1230      353537 :   bool constraints_applied = false;
    1231             : 
    1232      413806 :   for (const auto & it : penetration_locators)
    1233             :   {
    1234       60269 :     PenetrationLocator & pen_loc = *(it.second);
    1235             : 
    1236       60269 :     std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    1237             : 
    1238       60269 :     BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    1239       60269 :     BoundaryID primary_boundary = pen_loc._primary_boundary;
    1240             : 
    1241       60269 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
    1242             :     {
    1243             :       const auto & constraints =
    1244        2977 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
    1245        2977 :       std::unordered_set<unsigned int> needed_mat_props;
    1246        5954 :       for (const auto & constraint : constraints)
    1247             :       {
    1248        2977 :         const auto & mp_deps = constraint->getMatPropDependencies();
    1249        2977 :         needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
    1250             :       }
    1251        2977 :       _fe_problem.setActiveMaterialProperties(needed_mat_props, /*tid=*/0);
    1252             : 
    1253       42140 :       for (unsigned int i = 0; i < secondary_nodes.size(); i++)
    1254             :       {
    1255       39163 :         dof_id_type secondary_node_num = secondary_nodes[i];
    1256       39163 :         Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    1257             : 
    1258       39163 :         if (secondary_node.processor_id() == processor_id())
    1259             :         {
    1260       30944 :           if (pen_loc._penetration_info[secondary_node_num])
    1261             :           {
    1262       30944 :             PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
    1263             : 
    1264       30944 :             reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
    1265             : 
    1266       61888 :             for (const auto & nfc : constraints)
    1267             :             {
    1268       30944 :               if (nfc->isExplicitConstraint())
    1269       28816 :                 continue;
    1270             :               // Return if this constraint does not correspond to the primary-secondary pair
    1271             :               // prepared by the outer loops.
    1272             :               // This continue statement is required when, e.g. one secondary surface constrains
    1273             :               // more than one primary surface.
    1274        4256 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    1275        2128 :                   nfc->primaryBoundary() != primary_boundary)
    1276           0 :                 continue;
    1277             : 
    1278        2128 :               if (nfc->shouldApply())
    1279             :               {
    1280        2128 :                 constraints_applied = true;
    1281        2128 :                 nfc->computeSecondaryValue(solution);
    1282             :               }
    1283             : 
    1284        2128 :               if (nfc->hasWritableCoupledVariables())
    1285             :               {
    1286           0 :                 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1287           0 :                 for (auto * var : nfc->getWritableCoupledVariables())
    1288             :                 {
    1289           0 :                   if (var->isNodalDefined())
    1290           0 :                     var->insert(_fe_problem.getAuxiliarySystem().solution());
    1291             :                 }
    1292           0 :               }
    1293             :             }
    1294             :           }
    1295             :         }
    1296             :       }
    1297        2977 :     }
    1298             :   }
    1299             : 
    1300             :   // go over NodeELemConstraints
    1301      353537 :   std::set<dof_id_type> unique_secondary_node_ids;
    1302             : 
    1303      793493 :   for (const auto & secondary_id : _mesh.meshSubdomains())
    1304             :   {
    1305     1174370 :     for (const auto & primary_id : _mesh.meshSubdomains())
    1306             :     {
    1307      734414 :       if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
    1308             :       {
    1309             :         const auto & constraints =
    1310         180 :             _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
    1311             : 
    1312             :         // get unique set of ids of all nodes on current block
    1313         180 :         unique_secondary_node_ids.clear();
    1314         180 :         const MeshBase & meshhelper = _mesh.getMesh();
    1315         360 :         for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
    1316       17340 :                                           meshhelper.active_subdomain_elements_end(secondary_id)))
    1317             :         {
    1318       49140 :           for (auto & n : elem->node_ref_range())
    1319       40740 :             unique_secondary_node_ids.insert(n.id());
    1320         180 :         }
    1321             : 
    1322       14040 :         for (auto secondary_node_id : unique_secondary_node_ids)
    1323             :         {
    1324       13860 :           Node & secondary_node = _mesh.nodeRef(secondary_node_id);
    1325             : 
    1326             :           // check if secondary node is on current processor
    1327       13860 :           if (secondary_node.processor_id() == processor_id())
    1328             :           {
    1329             :             // This reinits the variables that exist on the secondary node
    1330       11088 :             _fe_problem.reinitNodeFace(&secondary_node, secondary_id, 0);
    1331             : 
    1332             :             // This will set aside residual and jacobian space for the variables that have dofs
    1333             :             // on the secondary node
    1334       11088 :             _fe_problem.prepareAssembly(0);
    1335             : 
    1336       23584 :             for (const auto & nec : constraints)
    1337             :             {
    1338       12496 :               if (nec->shouldApply())
    1339             :               {
    1340        5680 :                 constraints_applied = true;
    1341        5680 :                 nec->computeSecondaryValue(solution);
    1342             :               }
    1343             :             }
    1344             :           }
    1345             :         }
    1346             :       }
    1347             :     }
    1348             :   }
    1349             : 
    1350             :   // See if constraints were applied anywhere
    1351      353537 :   _communicator.max(constraints_applied);
    1352             : 
    1353      353537 :   if (constraints_applied)
    1354             :   {
    1355         719 :     solution.close();
    1356         719 :     update();
    1357             :   }
    1358      353537 : }
    1359             : 
    1360             : void
    1361       28287 : NonlinearSystemBase::constraintResiduals(NumericVector<Number> & residual, bool displaced)
    1362             : {
    1363             :   // Make sure the residual is in a good state
    1364       28287 :   residual.close();
    1365             : 
    1366             :   if (displaced)
    1367             :     mooseAssert(_fe_problem.getDisplacedProblem(),
    1368             :                 "If we're calling this method with displaced = true, then we better well have a "
    1369             :                 "displaced problem");
    1370        9756 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1371       33165 :                                 : static_cast<SubProblem &>(_fe_problem);
    1372       28287 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    1373             : 
    1374             :   bool constraints_applied;
    1375       28287 :   bool residual_has_inserted_values = false;
    1376       28287 :   if (!_assemble_constraints_separately)
    1377       28287 :     constraints_applied = false;
    1378       52353 :   for (const auto & it : penetration_locators)
    1379             :   {
    1380       24066 :     if (_assemble_constraints_separately)
    1381             :     {
    1382             :       // Reset the constraint_applied flag before each new constraint, as they need to be
    1383             :       // assembled separately
    1384           0 :       constraints_applied = false;
    1385             :     }
    1386       24066 :     PenetrationLocator & pen_loc = *(it.second);
    1387             : 
    1388       24066 :     std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    1389             : 
    1390       24066 :     BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    1391       24066 :     BoundaryID primary_boundary = pen_loc._primary_boundary;
    1392             : 
    1393       24066 :     bool has_writable_variables(false);
    1394             : 
    1395       24066 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
    1396             :     {
    1397             :       const auto & constraints =
    1398       14004 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
    1399             : 
    1400       99926 :       for (unsigned int i = 0; i < secondary_nodes.size(); i++)
    1401             :       {
    1402       85922 :         dof_id_type secondary_node_num = secondary_nodes[i];
    1403       85922 :         Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    1404             : 
    1405       85922 :         if (secondary_node.processor_id() == processor_id())
    1406             :         {
    1407       73050 :           if (pen_loc._penetration_info[secondary_node_num])
    1408             :           {
    1409       73050 :             PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
    1410             : 
    1411       73050 :             reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
    1412             : 
    1413      146100 :             for (const auto & nfc : constraints)
    1414             :             {
    1415             :               // Return if this constraint does not correspond to the primary-secondary pair
    1416             :               // prepared by the outer loops.
    1417             :               // This continue statement is required when, e.g. one secondary surface constrains
    1418             :               // more than one primary surface.
    1419      146100 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    1420       73050 :                   nfc->primaryBoundary() != primary_boundary)
    1421           0 :                 continue;
    1422             : 
    1423       73050 :               if (nfc->shouldApply())
    1424             :               {
    1425       44234 :                 constraints_applied = true;
    1426       44234 :                 nfc->computeResidual();
    1427             : 
    1428       44234 :                 if (nfc->overwriteSecondaryResidual())
    1429             :                 {
    1430             :                   // The below will actually overwrite the residual for every single dof that
    1431             :                   // lives on the node. We definitely don't want to do that!
    1432             :                   // _fe_problem.setResidual(residual, 0);
    1433             : 
    1434       44234 :                   const auto & secondary_var = nfc->variable();
    1435       44234 :                   const auto & secondary_dofs = secondary_var.dofIndices();
    1436             :                   mooseAssert(secondary_dofs.size() == secondary_var.count(),
    1437             :                               "We are on a node so there should only be one dof per variable (for "
    1438             :                               "an ArrayVariable we should have a number of dofs equal to the "
    1439             :                               "number of components");
    1440             : 
    1441             :                   // Assume that if the user is overwriting the secondary residual, then they are
    1442             :                   // supplying residuals that do not correspond to their other physics
    1443             :                   // (e.g. Kernels), hence we should not apply a scalingFactor that is normally
    1444             :                   // based on the order of their other physics (e.g. Kernels)
    1445       88468 :                   std::vector<Number> values = {nfc->secondaryResidual()};
    1446       44234 :                   residual.insert(values, secondary_dofs);
    1447       44234 :                   residual_has_inserted_values = true;
    1448       44234 :                 }
    1449             :                 else
    1450           0 :                   _fe_problem.cacheResidual(0);
    1451       44234 :                 _fe_problem.cacheResidualNeighbor(0);
    1452             :               }
    1453       73050 :               if (nfc->hasWritableCoupledVariables())
    1454             :               {
    1455       28816 :                 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1456       28816 :                 has_writable_variables = true;
    1457       57632 :                 for (auto * var : nfc->getWritableCoupledVariables())
    1458             :                 {
    1459       28816 :                   if (var->isNodalDefined())
    1460       28816 :                     var->insert(_fe_problem.getAuxiliarySystem().solution());
    1461             :                 }
    1462       28816 :               }
    1463             :             }
    1464             :           }
    1465             :         }
    1466             :       }
    1467             :     }
    1468       24066 :     _communicator.max(has_writable_variables);
    1469             : 
    1470       24066 :     if (has_writable_variables)
    1471             :     {
    1472             :       // Explicit contact dynamic constraints write to auxiliary variables and update the old
    1473             :       // displacement solution on the constraint boundaries. Close solutions and update system
    1474             :       // accordingly.
    1475        2401 :       _fe_problem.getAuxiliarySystem().solution().close();
    1476        2401 :       _fe_problem.getAuxiliarySystem().system().update();
    1477        2401 :       solutionOld().close();
    1478             :     }
    1479             : 
    1480       24066 :     if (_assemble_constraints_separately)
    1481             :     {
    1482             :       // Make sure that secondary contribution to primary are assembled, and ghosts have been
    1483             :       // exchanged, as current primaries might become secondaries on next iteration and will need to
    1484             :       // contribute their former secondaries' contributions to the future primaries. See if
    1485             :       // constraints were applied anywhere
    1486           0 :       _communicator.max(constraints_applied);
    1487             : 
    1488           0 :       if (constraints_applied)
    1489             :       {
    1490             :         // If any of the above constraints inserted values in the residual, it needs to be
    1491             :         // assembled before adding the cached residuals below.
    1492           0 :         _communicator.max(residual_has_inserted_values);
    1493           0 :         if (residual_has_inserted_values)
    1494             :         {
    1495           0 :           residual.close();
    1496           0 :           residual_has_inserted_values = false;
    1497             :         }
    1498           0 :         _fe_problem.addCachedResidualDirectly(residual, 0);
    1499           0 :         residual.close();
    1500             : 
    1501           0 :         if (_need_residual_ghosted)
    1502           0 :           *_residual_ghosted = residual;
    1503             :       }
    1504             :     }
    1505             :   }
    1506       28287 :   if (!_assemble_constraints_separately)
    1507             :   {
    1508       28287 :     _communicator.max(constraints_applied);
    1509             : 
    1510       28287 :     if (constraints_applied)
    1511             :     {
    1512             :       // If any of the above constraints inserted values in the residual, it needs to be assembled
    1513             :       // before adding the cached residuals below.
    1514       10864 :       _communicator.max(residual_has_inserted_values);
    1515       10864 :       if (residual_has_inserted_values)
    1516       10864 :         residual.close();
    1517             : 
    1518       10864 :       _fe_problem.addCachedResidualDirectly(residual, 0);
    1519       10864 :       residual.close();
    1520             : 
    1521       10864 :       if (_need_residual_ghosted)
    1522       10864 :         *_residual_ghosted = residual;
    1523             :     }
    1524             :   }
    1525             : 
    1526             :   // go over element-element constraint interface
    1527       28287 :   THREAD_ID tid = 0;
    1528       28287 :   const auto & element_pair_locators = subproblem.geomSearchData()._element_pair_locators;
    1529       28287 :   for (const auto & it : element_pair_locators)
    1530             :   {
    1531           0 :     ElementPairLocator & elem_pair_loc = *(it.second);
    1532             : 
    1533           0 :     if (_constraints.hasActiveElemElemConstraints(it.first, displaced))
    1534             :     {
    1535             :       // ElemElemConstraint objects
    1536             :       const auto & element_constraints =
    1537           0 :           _constraints.getActiveElemElemConstraints(it.first, displaced);
    1538             : 
    1539             :       // go over pair elements
    1540             :       const std::list<std::pair<const Elem *, const Elem *>> & elem_pairs =
    1541           0 :           elem_pair_loc.getElemPairs();
    1542           0 :       for (const auto & pr : elem_pairs)
    1543             :       {
    1544           0 :         const Elem * elem1 = pr.first;
    1545           0 :         const Elem * elem2 = pr.second;
    1546             : 
    1547           0 :         if (elem1->processor_id() != processor_id())
    1548           0 :           continue;
    1549             : 
    1550           0 :         const ElementPairInfo & info = elem_pair_loc.getElemPairInfo(pr);
    1551             : 
    1552             :         // for each element process constraints on the
    1553           0 :         for (const auto & ec : element_constraints)
    1554             :         {
    1555           0 :           _fe_problem.setCurrentSubdomainID(elem1, tid);
    1556           0 :           subproblem.reinitElemPhys(elem1, info._elem1_constraint_q_point, tid);
    1557           0 :           _fe_problem.setNeighborSubdomainID(elem2, tid);
    1558           0 :           subproblem.reinitNeighborPhys(elem2, info._elem2_constraint_q_point, tid);
    1559             : 
    1560           0 :           ec->prepareShapes(ec->variable().number());
    1561           0 :           ec->prepareNeighborShapes(ec->variable().number());
    1562             : 
    1563           0 :           ec->reinit(info);
    1564           0 :           ec->computeResidual();
    1565           0 :           _fe_problem.cacheResidual(tid);
    1566           0 :           _fe_problem.cacheResidualNeighbor(tid);
    1567             :         }
    1568           0 :         _fe_problem.addCachedResidual(tid);
    1569             :       }
    1570             :     }
    1571             :   }
    1572             : 
    1573             :   // go over NodeElemConstraints
    1574       28287 :   std::set<dof_id_type> unique_secondary_node_ids;
    1575             : 
    1576       28287 :   constraints_applied = false;
    1577       28287 :   residual_has_inserted_values = false;
    1578       28287 :   bool has_writable_variables = false;
    1579       97398 :   for (const auto & secondary_id : _mesh.meshSubdomains())
    1580             :   {
    1581      296138 :     for (const auto & primary_id : _mesh.meshSubdomains())
    1582             :     {
    1583      227027 :       if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
    1584             :       {
    1585             :         const auto & constraints =
    1586         360 :             _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
    1587             : 
    1588             :         // get unique set of ids of all nodes on current block
    1589         360 :         unique_secondary_node_ids.clear();
    1590         360 :         const MeshBase & meshhelper = _mesh.getMesh();
    1591         720 :         for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
    1592       17880 :                                           meshhelper.active_subdomain_elements_end(secondary_id)))
    1593             :         {
    1594       98280 :           for (auto & n : elem->node_ref_range())
    1595       81480 :             unique_secondary_node_ids.insert(n.id());
    1596         360 :         }
    1597             : 
    1598       28080 :         for (auto secondary_node_id : unique_secondary_node_ids)
    1599             :         {
    1600       27720 :           Node & secondary_node = _mesh.nodeRef(secondary_node_id);
    1601             :           // check if secondary node is on current processor
    1602       27720 :           if (secondary_node.processor_id() == processor_id())
    1603             :           {
    1604             :             // This reinits the variables that exist on the secondary node
    1605       22176 :             _fe_problem.reinitNodeFace(&secondary_node, secondary_id, 0);
    1606             : 
    1607             :             // This will set aside residual and jacobian space for the variables that have dofs
    1608             :             // on the secondary node
    1609       22176 :             _fe_problem.prepareAssembly(0);
    1610             : 
    1611       47168 :             for (const auto & nec : constraints)
    1612             :             {
    1613       24992 :               if (nec->shouldApply())
    1614             :               {
    1615       11360 :                 constraints_applied = true;
    1616       11360 :                 nec->computeResidual();
    1617             : 
    1618       11360 :                 if (nec->overwriteSecondaryResidual())
    1619             :                 {
    1620           0 :                   _fe_problem.setResidual(residual, 0);
    1621           0 :                   residual_has_inserted_values = true;
    1622             :                 }
    1623             :                 else
    1624       11360 :                   _fe_problem.cacheResidual(0);
    1625       11360 :                 _fe_problem.cacheResidualNeighbor(0);
    1626             :               }
    1627       24992 :               if (nec->hasWritableCoupledVariables())
    1628             :               {
    1629         352 :                 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1630         352 :                 has_writable_variables = true;
    1631         704 :                 for (auto * var : nec->getWritableCoupledVariables())
    1632             :                 {
    1633         352 :                   if (var->isNodalDefined())
    1634         352 :                     var->insert(_fe_problem.getAuxiliarySystem().solution());
    1635             :                 }
    1636         352 :               }
    1637             :             }
    1638       22176 :             _fe_problem.addCachedResidual(0);
    1639             :           }
    1640             :         }
    1641             :       }
    1642             :     }
    1643             :   }
    1644       28287 :   _communicator.max(constraints_applied);
    1645             : 
    1646       28287 :   if (constraints_applied)
    1647             :   {
    1648             :     // If any of the above constraints inserted values in the residual, it needs to be assembled
    1649             :     // before adding the cached residuals below.
    1650         360 :     _communicator.max(residual_has_inserted_values);
    1651         360 :     if (residual_has_inserted_values)
    1652           0 :       residual.close();
    1653             : 
    1654         360 :     _fe_problem.addCachedResidualDirectly(residual, 0);
    1655         360 :     residual.close();
    1656             : 
    1657         360 :     if (_need_residual_ghosted)
    1658         360 :       *_residual_ghosted = residual;
    1659             :   }
    1660       28287 :   _communicator.max(has_writable_variables);
    1661             : 
    1662       28287 :   if (has_writable_variables)
    1663             :   {
    1664             :     // Explicit contact dynamic constraints write to auxiliary variables and update the old
    1665             :     // displacement solution on the constraint boundaries. Close solutions and update system
    1666             :     // accordingly.
    1667          20 :     _fe_problem.getAuxiliarySystem().solution().close();
    1668          20 :     _fe_problem.getAuxiliarySystem().system().update();
    1669          20 :     solutionOld().close();
    1670             :   }
    1671             : 
    1672             :   // We may have additional tagged vectors that also need to be accumulated
    1673       28287 :   _fe_problem.addCachedResidual(0);
    1674       28287 : }
    1675             : 
    1676             : void
    1677        4528 : NonlinearSystemBase::overwriteNodeFace(NumericVector<Number> & soln)
    1678             : {
    1679             :   // Overwrite results from integrator in case we have explicit dynamics contact constraints
    1680        4528 :   auto & subproblem = _fe_problem.getDisplacedProblem()
    1681        6929 :                           ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1682        6929 :                           : static_cast<SubProblem &>(_fe_problem);
    1683        4528 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    1684             : 
    1685        6929 :   for (const auto & it : penetration_locators)
    1686             :   {
    1687        2401 :     PenetrationLocator & pen_loc = *(it.second);
    1688             : 
    1689        2401 :     const auto & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    1690        2401 :     const BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    1691        2401 :     const BoundaryID primary_boundary = pen_loc._primary_boundary;
    1692             : 
    1693        2401 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, true))
    1694             :     {
    1695             :       const auto & constraints =
    1696        2401 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, true);
    1697       39217 :       for (const auto i : index_range(secondary_nodes))
    1698             :       {
    1699       36816 :         const auto secondary_node_num = secondary_nodes[i];
    1700       36816 :         const Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    1701             : 
    1702       36816 :         if (secondary_node.processor_id() == processor_id())
    1703       28816 :           if (pen_loc._penetration_info[secondary_node_num])
    1704       57632 :             for (const auto & nfc : constraints)
    1705             :             {
    1706       28816 :               if (!nfc->isExplicitConstraint())
    1707           0 :                 continue;
    1708             : 
    1709             :               // Return if this constraint does not correspond to the primary-secondary pair
    1710             :               // prepared by the outer loops.
    1711             :               // This continue statement is required when, e.g. one secondary surface constrains
    1712             :               // more than one primary surface.
    1713       57632 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    1714       28816 :                   nfc->primaryBoundary() != primary_boundary)
    1715           0 :                 continue;
    1716             : 
    1717       28816 :               nfc->overwriteBoundaryVariables(soln, secondary_node);
    1718             :             }
    1719             :       }
    1720             :     }
    1721             :   }
    1722        4528 :   soln.close();
    1723        4528 : }
    1724             : 
    1725             : void
    1726     3434303 : NonlinearSystemBase::residualSetup()
    1727             : {
    1728    10302909 :   TIME_SECTION("residualSetup", 3);
    1729             : 
    1730     3434303 :   SolverSystem::residualSetup();
    1731             : 
    1732     7176439 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
    1733             :   {
    1734     3742136 :     _kernels.residualSetup(tid);
    1735     3742136 :     _nodal_kernels.residualSetup(tid);
    1736     3742136 :     _dirac_kernels.residualSetup(tid);
    1737     3742136 :     if (_doing_dg)
    1738       38033 :       _dg_kernels.residualSetup(tid);
    1739     3742136 :     _interface_kernels.residualSetup(tid);
    1740     3742136 :     _element_dampers.residualSetup(tid);
    1741     3742136 :     _nodal_dampers.residualSetup(tid);
    1742     3742136 :     _integrated_bcs.residualSetup(tid);
    1743             :   }
    1744     3434303 :   _scalar_kernels.residualSetup();
    1745     3434303 :   _constraints.residualSetup();
    1746     3434303 :   _general_dampers.residualSetup();
    1747     3434303 :   _nodal_bcs.residualSetup();
    1748     3434303 :   _preset_nodal_bcs.residualSetup();
    1749     3434303 :   _ad_preset_nodal_bcs.residualSetup();
    1750             : 
    1751             : #ifdef MOOSE_KOKKOS_ENABLED
    1752     2255095 :   _kokkos_kernels.residualSetup();
    1753     2255095 :   _kokkos_nodal_kernels.residualSetup();
    1754     2255095 :   _kokkos_integrated_bcs.residualSetup();
    1755     2255095 :   _kokkos_nodal_bcs.residualSetup();
    1756             : #endif
    1757             : 
    1758             :   // Avoid recursion
    1759     3434303 :   if (this == &_fe_problem.currentNonlinearSystem())
    1760     3341763 :     _fe_problem.residualSetup();
    1761     3434303 :   _app.solutionInvalidity().resetSolutionInvalidCurrentIteration();
    1762     3434303 : }
    1763             : 
    1764             : void
    1765     3338296 : NonlinearSystemBase::computeResidualInternal(const std::set<TagID> & tags)
    1766             : {
    1767             :   parallel_object_only();
    1768             : 
    1769    10014888 :   TIME_SECTION("computeResidualInternal", 3);
    1770             : 
    1771     3338296 :   residualSetup();
    1772             : 
    1773             : #ifdef MOOSE_KOKKOS_ENABLED
    1774     2190962 :   if (_fe_problem.hasKokkosResidualObjects())
    1775       26756 :     computeKokkosResidual(tags);
    1776             : #endif
    1777             : 
    1778     3338296 :   const auto vector_tag_data = _fe_problem.getVectorTags(tags);
    1779             : 
    1780             :   // Residual contributions from UOs - for now this is used for ray tracing
    1781             :   // and ray kernels that contribute to the residual (think line sources)
    1782     3338296 :   std::vector<UserObject *> uos;
    1783     3338296 :   _fe_problem.theWarehouse()
    1784     6676592 :       .query()
    1785     3338296 :       .condition<AttribSystem>("UserObject")
    1786     3338296 :       .condition<AttribExecOns>(EXEC_PRE_KERNELS)
    1787     3338296 :       .queryInto(uos);
    1788     3338296 :   for (auto & uo : uos)
    1789           0 :     uo->residualSetup();
    1790     3338296 :   for (auto & uo : uos)
    1791             :   {
    1792           0 :     uo->initialize();
    1793           0 :     uo->execute();
    1794           0 :     uo->finalize();
    1795             :   }
    1796             : 
    1797             :   // reinit scalar variables
    1798     6976206 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    1799     3637910 :     _fe_problem.reinitScalars(tid);
    1800             : 
    1801             :   // residual contributions from the domain
    1802             :   PARALLEL_TRY
    1803             :   {
    1804    10014888 :     TIME_SECTION("Kernels", 3 /*, "Computing Kernels"*/);
    1805             : 
    1806     3338296 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    1807             : 
    1808     3338296 :     ComputeResidualThread cr(_fe_problem, tags);
    1809     3338296 :     Threads::parallel_reduce(elem_range, cr);
    1810             : 
    1811             :     // We pass face information directly to FV residual objects for their evaluation. Consequently
    1812             :     // we must make sure to do separate threaded loops for 1) undisplaced face information objects
    1813             :     // and undisplaced residual objects and 2) displaced face information objects and displaced
    1814             :     // residual objects
    1815             :     using FVRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
    1816     3338272 :     if (_fe_problem.haveFV())
    1817             :     {
    1818             :       ComputeFVFluxResidualThread<FVRange> fvr(
    1819      150860 :           _fe_problem, this->number(), tags, /*on_displaced=*/false);
    1820      150860 :       FVRange faces(_fe_problem.mesh().ownedFaceInfoBegin(), _fe_problem.mesh().ownedFaceInfoEnd());
    1821      150860 :       Threads::parallel_reduce(faces, fvr);
    1822      150860 :     }
    1823     3338264 :     if (auto displaced_problem = _fe_problem.getDisplacedProblem();
    1824     3338264 :         displaced_problem && displaced_problem->haveFV())
    1825             :     {
    1826             :       ComputeFVFluxResidualThread<FVRange> fvr(
    1827           0 :           _fe_problem, this->number(), tags, /*on_displaced=*/true);
    1828           0 :       FVRange faces(displaced_problem->mesh().ownedFaceInfoBegin(),
    1829           0 :                     displaced_problem->mesh().ownedFaceInfoEnd());
    1830           0 :       Threads::parallel_reduce(faces, fvr);
    1831     3338264 :     }
    1832             : 
    1833     3338264 :     unsigned int n_threads = libMesh::n_threads();
    1834     6976134 :     for (unsigned int i = 0; i < n_threads;
    1835             :          i++) // Add any cached residuals that might be hanging around
    1836     3637870 :       _fe_problem.addCachedResidual(i);
    1837     3338264 :   }
    1838     3338264 :   PARALLEL_CATCH;
    1839             : 
    1840             :   // residual contributions from the scalar kernels
    1841             :   PARALLEL_TRY
    1842             :   {
    1843             :     // do scalar kernels (not sure how to thread this)
    1844     3338143 :     if (_scalar_kernels.hasActiveObjects())
    1845             :     {
    1846      221043 :       TIME_SECTION("ScalarKernels", 3 /*, "Computing ScalarKernels"*/);
    1847             : 
    1848             :       MooseObjectWarehouse<ScalarKernelBase> * scalar_kernel_warehouse;
    1849             :       // This code should be refactored once we can do tags for scalar
    1850             :       // kernels
    1851             :       // Should redo this based on Warehouse
    1852       73681 :       if (!tags.size() || tags.size() == _fe_problem.numVectorTags(Moose::VECTOR_TAG_RESIDUAL))
    1853       73660 :         scalar_kernel_warehouse = &_scalar_kernels;
    1854          21 :       else if (tags.size() == 1)
    1855             :         scalar_kernel_warehouse =
    1856          12 :             &(_scalar_kernels.getVectorTagObjectWarehouse(*(tags.begin()), 0));
    1857             :       else
    1858             :         // scalar_kernels is not threading
    1859           9 :         scalar_kernel_warehouse = &(_scalar_kernels.getVectorTagsObjectWarehouse(tags, 0));
    1860             : 
    1861       73681 :       bool have_scalar_contributions = false;
    1862       73681 :       const auto & scalars = scalar_kernel_warehouse->getActiveObjects();
    1863      270946 :       for (const auto & scalar_kernel : scalars)
    1864             :       {
    1865      197265 :         scalar_kernel->reinit();
    1866      197265 :         const std::vector<dof_id_type> & dof_indices = scalar_kernel->variable().dofIndices();
    1867      197265 :         const DofMap & dof_map = scalar_kernel->variable().dofMap();
    1868      197265 :         const dof_id_type first_dof = dof_map.first_dof();
    1869      197265 :         const dof_id_type end_dof = dof_map.end_dof();
    1870      227734 :         for (dof_id_type dof : dof_indices)
    1871             :         {
    1872      197842 :           if (dof >= first_dof && dof < end_dof)
    1873             :           {
    1874      167373 :             scalar_kernel->computeResidual();
    1875      167373 :             have_scalar_contributions = true;
    1876      167373 :             break;
    1877             :           }
    1878             :         }
    1879             :       }
    1880       73681 :       if (have_scalar_contributions)
    1881       64576 :         _fe_problem.addResidualScalar();
    1882       73681 :     }
    1883             :   }
    1884     3338143 :   PARALLEL_CATCH;
    1885             : 
    1886             :   // residual contributions from Block NodalKernels
    1887             :   PARALLEL_TRY
    1888             :   {
    1889     3338143 :     if (_nodal_kernels.hasActiveBlockObjects())
    1890             :     {
    1891       46788 :       TIME_SECTION("NodalKernels", 3 /*, "Computing NodalKernels"*/);
    1892             : 
    1893       15596 :       ComputeNodalKernelsThread cnk(_fe_problem, _nodal_kernels, tags);
    1894             : 
    1895       15596 :       const ConstNodeRange & range = _fe_problem.getCurrentAlgebraicNodeRange();
    1896             : 
    1897       15596 :       if (range.begin() != range.end())
    1898             :       {
    1899       15596 :         _fe_problem.reinitNode(*range.begin(), 0);
    1900             : 
    1901       15596 :         Threads::parallel_reduce(range, cnk);
    1902             : 
    1903       15596 :         unsigned int n_threads = libMesh::n_threads();
    1904       38526 :         for (unsigned int i = 0; i < n_threads;
    1905             :              i++) // Add any cached residuals that might be hanging around
    1906       22930 :           _fe_problem.addCachedResidual(i);
    1907             :       }
    1908       15596 :     }
    1909             :   }
    1910     3338143 :   PARALLEL_CATCH;
    1911             : 
    1912     3338143 :   if (_fe_problem.computingScalingResidual())
    1913             :     // We computed the volumetric objects. We can return now before we get into
    1914             :     // any strongly enforced constraint conditions or penalty-type objects
    1915             :     // (DGKernels, IntegratedBCs, InterfaceKernels, Constraints)
    1916          50 :     return;
    1917             : 
    1918             :   // residual contributions from boundary NodalKernels
    1919             :   PARALLEL_TRY
    1920             :   {
    1921     3338093 :     if (_nodal_kernels.hasActiveBoundaryObjects())
    1922             :     {
    1923        3012 :       TIME_SECTION("NodalKernelBCs", 3 /*, "Computing NodalKernelBCs"*/);
    1924             : 
    1925        1004 :       ComputeNodalKernelBcsThread cnk(_fe_problem, _nodal_kernels, tags);
    1926             : 
    1927        1004 :       const ConstBndNodeRange & bnd_node_range = _fe_problem.getCurrentAlgebraicBndNodeRange();
    1928             : 
    1929        1004 :       Threads::parallel_reduce(bnd_node_range, cnk);
    1930             : 
    1931        1004 :       unsigned int n_threads = libMesh::n_threads();
    1932        2094 :       for (unsigned int i = 0; i < n_threads;
    1933             :            i++) // Add any cached residuals that might be hanging around
    1934        1090 :         _fe_problem.addCachedResidual(i);
    1935        1004 :     }
    1936             :   }
    1937     3338093 :   PARALLEL_CATCH;
    1938             : 
    1939     3338093 :   mortarConstraints(Moose::ComputeType::Residual, tags, {});
    1940             : 
    1941     3338093 :   if (_residual_copy.get())
    1942             :   {
    1943           0 :     _Re_non_time->close();
    1944           0 :     _Re_non_time->localize(*_residual_copy);
    1945             :   }
    1946             : 
    1947     3338093 :   if (_need_residual_ghosted)
    1948             :   {
    1949       13234 :     _Re_non_time->close();
    1950       13234 :     *_residual_ghosted = *_Re_non_time;
    1951       13234 :     _residual_ghosted->close();
    1952             :   }
    1953             : 
    1954     3338093 :   PARALLEL_TRY { computeDiracContributions(tags, false); }
    1955     3338081 :   PARALLEL_CATCH;
    1956             : 
    1957     3338081 :   if (_fe_problem._has_constraints)
    1958             :   {
    1959       23409 :     PARALLEL_TRY { enforceNodalConstraintsResidual(*_Re_non_time); }
    1960       23409 :     PARALLEL_CATCH;
    1961       23409 :     _Re_non_time->close();
    1962             :   }
    1963             : 
    1964             :   // Add in Residual contributions from other Constraints
    1965     3338081 :   if (_fe_problem._has_constraints)
    1966             :   {
    1967             :     PARALLEL_TRY
    1968             :     {
    1969             :       // Undisplaced Constraints
    1970       23409 :       constraintResiduals(*_Re_non_time, false);
    1971             : 
    1972             :       // Displaced Constraints
    1973       23409 :       if (_fe_problem.getDisplacedProblem())
    1974        4878 :         constraintResiduals(*_Re_non_time, true);
    1975             : 
    1976       23409 :       if (_fe_problem.computingNonlinearResid())
    1977       10705 :         _constraints.residualEnd();
    1978             :     }
    1979       23409 :     PARALLEL_CATCH;
    1980       23409 :     _Re_non_time->close();
    1981             :   }
    1982             : 
    1983             :   // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
    1984             :   // counters
    1985     3338081 :   _app.solutionInvalidity().syncIteration();
    1986     3338081 :   _app.solutionInvalidity().solutionInvalidAccumulation();
    1987     3338594 : }
    1988             : 
    1989             : void
    1990        3467 : NonlinearSystemBase::computeResidualAndJacobianInternal(const std::set<TagID> & vector_tags,
    1991             :                                                         const std::set<TagID> & matrix_tags)
    1992             : {
    1993       10401 :   TIME_SECTION("computeResidualAndJacobianInternal", 3);
    1994             : 
    1995             :   // Make matrix ready to use
    1996        3467 :   activateAllMatrixTags();
    1997             : 
    1998       10401 :   for (auto tag : matrix_tags)
    1999             :   {
    2000        6934 :     if (!hasMatrix(tag))
    2001        3467 :       continue;
    2002             : 
    2003        3467 :     auto & jacobian = getMatrix(tag);
    2004             :     // Necessary for speed
    2005        3467 :     if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&jacobian))
    2006             :     {
    2007        3467 :       LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
    2008             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2009             :                                     PETSC_TRUE));
    2010        3467 :       if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    2011           0 :         LibmeshPetscCall(
    2012             :             MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
    2013        3467 :       if (_fe_problem.ignoreZerosInJacobian())
    2014           0 :         LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2015             :                                       MAT_IGNORE_ZERO_ENTRIES,
    2016             :                                       PETSC_TRUE));
    2017             :     }
    2018             :   }
    2019             : 
    2020        3467 :   residualSetup();
    2021             : 
    2022             :   // Residual contributions from UOs - for now this is used for ray tracing
    2023             :   // and ray kernels that contribute to the residual (think line sources)
    2024        3467 :   std::vector<UserObject *> uos;
    2025        3467 :   _fe_problem.theWarehouse()
    2026        6934 :       .query()
    2027        3467 :       .condition<AttribSystem>("UserObject")
    2028        3467 :       .condition<AttribExecOns>(EXEC_PRE_KERNELS)
    2029        3467 :       .queryInto(uos);
    2030        3467 :   for (auto & uo : uos)
    2031           0 :     uo->residualSetup();
    2032        3467 :   for (auto & uo : uos)
    2033             :   {
    2034           0 :     uo->initialize();
    2035           0 :     uo->execute();
    2036           0 :     uo->finalize();
    2037             :   }
    2038             : 
    2039             :   // reinit scalar variables
    2040        7273 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    2041        3806 :     _fe_problem.reinitScalars(tid);
    2042             : 
    2043             :   // residual contributions from the domain
    2044             :   PARALLEL_TRY
    2045             :   {
    2046       10401 :     TIME_SECTION("Kernels", 3 /*, "Computing Kernels"*/);
    2047             : 
    2048        3467 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    2049             : 
    2050        3467 :     ComputeResidualAndJacobianThread crj(_fe_problem, vector_tags, matrix_tags);
    2051        3467 :     Threads::parallel_reduce(elem_range, crj);
    2052             : 
    2053             :     using FVRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
    2054        3467 :     if (_fe_problem.haveFV())
    2055             :     {
    2056             :       ComputeFVFluxRJThread<FVRange> fvrj(
    2057        1451 :           _fe_problem, this->number(), vector_tags, matrix_tags, /*on_displaced=*/false);
    2058        1451 :       FVRange faces(_fe_problem.mesh().ownedFaceInfoBegin(), _fe_problem.mesh().ownedFaceInfoEnd());
    2059        1451 :       Threads::parallel_reduce(faces, fvrj);
    2060        1451 :     }
    2061        3467 :     if (auto displaced_problem = _fe_problem.getDisplacedProblem();
    2062        3467 :         displaced_problem && displaced_problem->haveFV())
    2063             :     {
    2064             :       ComputeFVFluxRJThread<FVRange> fvr(
    2065           0 :           _fe_problem, this->number(), vector_tags, matrix_tags, /*on_displaced=*/true);
    2066           0 :       FVRange faces(displaced_problem->mesh().ownedFaceInfoBegin(),
    2067           0 :                     displaced_problem->mesh().ownedFaceInfoEnd());
    2068           0 :       Threads::parallel_reduce(faces, fvr);
    2069        3467 :     }
    2070             : 
    2071        3467 :     mortarConstraints(Moose::ComputeType::ResidualAndJacobian, vector_tags, matrix_tags);
    2072             : 
    2073        3467 :     unsigned int n_threads = libMesh::n_threads();
    2074        7273 :     for (unsigned int i = 0; i < n_threads;
    2075             :          i++) // Add any cached residuals that might be hanging around
    2076             :     {
    2077        3806 :       _fe_problem.addCachedResidual(i);
    2078        3806 :       _fe_problem.addCachedJacobian(i);
    2079             :     }
    2080        3467 :   }
    2081        3467 :   PARALLEL_CATCH;
    2082        3467 : }
    2083             : 
    2084             : void
    2085           0 : NonlinearSystemBase::computeNodalBCs(NumericVector<Number> & residual)
    2086             : {
    2087           0 :   _nl_vector_tags.clear();
    2088             : 
    2089           0 :   const auto & residual_vector_tags = _fe_problem.getVectorTags(Moose::VECTOR_TAG_RESIDUAL);
    2090           0 :   for (const auto & residual_vector_tag : residual_vector_tags)
    2091           0 :     _nl_vector_tags.insert(residual_vector_tag._id);
    2092             : 
    2093           0 :   associateVectorToTag(residual, residualVectorTag());
    2094           0 :   computeNodalBCs(residual, _nl_vector_tags);
    2095           0 :   disassociateVectorFromTag(residual, residualVectorTag());
    2096           0 : }
    2097             : 
    2098             : void
    2099           0 : NonlinearSystemBase::computeNodalBCs(NumericVector<Number> & residual, const std::set<TagID> & tags)
    2100             : {
    2101           0 :   associateVectorToTag(residual, residualVectorTag());
    2102             : 
    2103           0 :   computeNodalBCs(tags);
    2104             : 
    2105           0 :   disassociateVectorFromTag(residual, residualVectorTag());
    2106           0 : }
    2107             : 
    2108             : void
    2109     3338081 : NonlinearSystemBase::computeNodalBCs(const std::set<TagID> & tags)
    2110             : {
    2111             :   // We need to close the diag_save_in variables on the aux system before NodalBCBases clear the
    2112             :   // dofs on boundary nodes
    2113     3338081 :   if (_has_save_in)
    2114         309 :     _fe_problem.getAuxiliarySystem().solution().close();
    2115             : 
    2116             :   // Select nodal kernels
    2117             :   MooseObjectWarehouse<NodalBCBase> * nbc_warehouse;
    2118             : 
    2119     3338081 :   if (tags.size() == _fe_problem.numVectorTags(Moose::VECTOR_TAG_RESIDUAL) || !tags.size())
    2120     3299200 :     nbc_warehouse = &_nodal_bcs;
    2121       38881 :   else if (tags.size() == 1)
    2122       18306 :     nbc_warehouse = &(_nodal_bcs.getVectorTagObjectWarehouse(*(tags.begin()), 0));
    2123             :   else
    2124       20575 :     nbc_warehouse = &(_nodal_bcs.getVectorTagsObjectWarehouse(tags, 0));
    2125             : 
    2126             :   // Return early if there is no nodal kernel
    2127     3338081 :   if (!nbc_warehouse->size())
    2128      450320 :     return;
    2129             : 
    2130             :   PARALLEL_TRY
    2131             :   {
    2132     2887761 :     const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    2133             : 
    2134     2887761 :     if (!bnd_nodes.empty())
    2135             :     {
    2136     8662350 :       TIME_SECTION("NodalBCs", 3 /*, "Computing NodalBCs"*/);
    2137             : 
    2138   151120760 :       for (const auto & bnode : bnd_nodes)
    2139             :       {
    2140   148233310 :         BoundaryID boundary_id = bnode->_bnd_id;
    2141   148233310 :         Node * node = bnode->_node;
    2142             : 
    2143   262254284 :         if (node->processor_id() == processor_id() &&
    2144   114020974 :             nbc_warehouse->hasActiveBoundaryObjects(boundary_id))
    2145             :         {
    2146             :           // reinit variables in nodes
    2147    58381899 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
    2148             : 
    2149    58381899 :           const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id);
    2150   122393110 :           for (const auto & nbc : bcs)
    2151    64011211 :             if (nbc->shouldApply())
    2152    64009807 :               nbc->computeResidual();
    2153             :         }
    2154             :       }
    2155     2887450 :     }
    2156             :   }
    2157     2887761 :   PARALLEL_CATCH;
    2158             : 
    2159     2887761 :   if (_Re_time)
    2160     2564983 :     _Re_time->close();
    2161     2887761 :   _Re_non_time->close();
    2162             : }
    2163             : 
    2164             : void
    2165        3467 : NonlinearSystemBase::computeNodalBCsResidualAndJacobian()
    2166             : {
    2167             :   PARALLEL_TRY
    2168             :   {
    2169        3467 :     const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    2170             : 
    2171        3467 :     if (!bnd_nodes.empty())
    2172             :     {
    2173       10401 :       TIME_SECTION("NodalBCs", 3 /*, "Computing NodalBCs"*/);
    2174             : 
    2175       86555 :       for (const auto & bnode : bnd_nodes)
    2176             :       {
    2177       83088 :         BoundaryID boundary_id = bnode->_bnd_id;
    2178       83088 :         Node * node = bnode->_node;
    2179             : 
    2180       83088 :         if (node->processor_id() == processor_id())
    2181             :         {
    2182             :           // reinit variables in nodes
    2183       62704 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
    2184       62704 :           if (_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
    2185             :           {
    2186       12501 :             const auto & bcs = _nodal_bcs.getActiveBoundaryObjects(boundary_id);
    2187       25002 :             for (const auto & nbc : bcs)
    2188       12501 :               if (nbc->shouldApply())
    2189       12501 :                 nbc->computeResidualAndJacobian();
    2190             :           }
    2191             :         }
    2192             :       }
    2193        3467 :     }
    2194             :   }
    2195        3467 :   PARALLEL_CATCH;
    2196             : 
    2197             :   // Set the cached NodalBCBase values in the Jacobian matrix
    2198        3467 :   _fe_problem.assembly(0, number()).setCachedJacobian(Assembly::GlobalDataKey{});
    2199        3467 : }
    2200             : 
    2201             : void
    2202         717 : NonlinearSystemBase::getNodeDofs(dof_id_type node_id, std::vector<dof_id_type> & dofs)
    2203             : {
    2204         717 :   const Node & node = _mesh.nodeRef(node_id);
    2205         717 :   unsigned int s = number();
    2206         717 :   if (node.has_dofs(s))
    2207             :   {
    2208        1472 :     for (unsigned int v = 0; v < nVariables(); v++)
    2209        1472 :       for (unsigned int c = 0; c < node.n_comp(s, v); c++)
    2210         717 :         dofs.push_back(node.dof_number(s, v, c));
    2211             :   }
    2212         717 : }
    2213             : 
    2214             : void
    2215        5567 : NonlinearSystemBase::findImplicitGeometricCouplingEntries(
    2216             :     GeometricSearchData & geom_search_data,
    2217             :     std::unordered_map<dof_id_type, std::vector<dof_id_type>> & graph)
    2218             : {
    2219        5567 :   const auto & node_to_elem_map = _mesh.nodeToElemMap();
    2220        5567 :   const auto & nearest_node_locators = geom_search_data._nearest_node_locators;
    2221        7696 :   for (const auto & it : nearest_node_locators)
    2222             :   {
    2223        2129 :     std::vector<dof_id_type> & secondary_nodes = it.second->_secondary_nodes;
    2224             : 
    2225       10915 :     for (const auto & secondary_node : secondary_nodes)
    2226             :     {
    2227        8786 :       std::set<dof_id_type> unique_secondary_indices;
    2228        8786 :       std::set<dof_id_type> unique_primary_indices;
    2229             : 
    2230        8786 :       auto node_to_elem_pair = node_to_elem_map.find(secondary_node);
    2231        8786 :       if (node_to_elem_pair != node_to_elem_map.end())
    2232             :       {
    2233        8666 :         const std::vector<dof_id_type> & elems = node_to_elem_pair->second;
    2234             : 
    2235             :         // Get the dof indices from each elem connected to the node
    2236       23314 :         for (const auto & cur_elem : elems)
    2237             :         {
    2238       14648 :           std::vector<dof_id_type> dof_indices;
    2239       14648 :           dofMap().dof_indices(_mesh.elemPtr(cur_elem), dof_indices);
    2240             : 
    2241       73240 :           for (const auto & dof : dof_indices)
    2242       58592 :             unique_secondary_indices.insert(dof);
    2243       14648 :         }
    2244             :       }
    2245             : 
    2246        8786 :       std::vector<dof_id_type> primary_nodes = it.second->_neighbor_nodes[secondary_node];
    2247             : 
    2248       49576 :       for (const auto & primary_node : primary_nodes)
    2249             :       {
    2250       40790 :         auto primary_node_to_elem_pair = node_to_elem_map.find(primary_node);
    2251             :         mooseAssert(primary_node_to_elem_pair != node_to_elem_map.end(),
    2252             :                     "Missing entry in node to elem map");
    2253       40790 :         const std::vector<dof_id_type> & primary_node_elems = primary_node_to_elem_pair->second;
    2254             : 
    2255             :         // Get the dof indices from each elem connected to the node
    2256      107078 :         for (const auto & cur_elem : primary_node_elems)
    2257             :         {
    2258       66288 :           std::vector<dof_id_type> dof_indices;
    2259       66288 :           dofMap().dof_indices(_mesh.elemPtr(cur_elem), dof_indices);
    2260             : 
    2261      331440 :           for (const auto & dof : dof_indices)
    2262      265152 :             unique_primary_indices.insert(dof);
    2263       66288 :         }
    2264             :       }
    2265             : 
    2266       55414 :       for (const auto & secondary_id : unique_secondary_indices)
    2267      506684 :         for (const auto & primary_id : unique_primary_indices)
    2268             :         {
    2269      460056 :           graph[secondary_id].push_back(primary_id);
    2270      460056 :           graph[primary_id].push_back(secondary_id);
    2271             :         }
    2272        8786 :     }
    2273             :   }
    2274             : 
    2275             :   // handle node-to-node constraints
    2276        5567 :   const auto & ncs = _constraints.getActiveNodalConstraints();
    2277        5724 :   for (const auto & nc : ncs)
    2278             :   {
    2279         157 :     std::vector<dof_id_type> primary_dofs;
    2280         157 :     std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
    2281         314 :     for (const auto & node_id : primary_node_ids)
    2282             :     {
    2283         157 :       Node * node = _mesh.queryNodePtr(node_id);
    2284         157 :       if (node && node->processor_id() == this->processor_id())
    2285             :       {
    2286         142 :         getNodeDofs(node_id, primary_dofs);
    2287             :       }
    2288             :     }
    2289             : 
    2290         157 :     _communicator.allgather(primary_dofs);
    2291             : 
    2292         157 :     std::vector<dof_id_type> secondary_dofs;
    2293         157 :     std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
    2294         732 :     for (const auto & node_id : secondary_node_ids)
    2295             :     {
    2296         575 :       Node * node = _mesh.queryNodePtr(node_id);
    2297         575 :       if (node && node->processor_id() == this->processor_id())
    2298             :       {
    2299         575 :         getNodeDofs(node_id, secondary_dofs);
    2300             :       }
    2301             :     }
    2302             : 
    2303         157 :     _communicator.allgather(secondary_dofs);
    2304             : 
    2305         314 :     for (const auto & primary_id : primary_dofs)
    2306         870 :       for (const auto & secondary_id : secondary_dofs)
    2307             :       {
    2308         713 :         graph[primary_id].push_back(secondary_id);
    2309         713 :         graph[secondary_id].push_back(primary_id);
    2310             :       }
    2311         157 :   }
    2312             : 
    2313             :   // Make every entry sorted and unique
    2314       30319 :   for (auto & it : graph)
    2315             :   {
    2316       24752 :     std::vector<dof_id_type> & row = it.second;
    2317       24752 :     std::sort(row.begin(), row.end());
    2318       24752 :     std::vector<dof_id_type>::iterator uit = std::unique(row.begin(), row.end());
    2319       24752 :     row.resize(uit - row.begin());
    2320             :   }
    2321        5567 : }
    2322             : 
    2323             : void
    2324        4135 : NonlinearSystemBase::addImplicitGeometricCouplingEntries(GeometricSearchData & geom_search_data)
    2325             : {
    2326        4135 :   if (!hasMatrix(systemMatrixTag()))
    2327           0 :     mooseError("Need a system matrix ");
    2328             : 
    2329             :   // At this point, have no idea how to make
    2330             :   // this work with tag system
    2331        4135 :   auto & jacobian = getMatrix(systemMatrixTag());
    2332             : 
    2333        4135 :   std::unordered_map<dof_id_type, std::vector<dof_id_type>> graph;
    2334             : 
    2335        4135 :   findImplicitGeometricCouplingEntries(geom_search_data, graph);
    2336             : 
    2337       28010 :   for (const auto & it : graph)
    2338             :   {
    2339       23875 :     dof_id_type dof = it.first;
    2340       23875 :     const auto & row = it.second;
    2341             : 
    2342      281261 :     for (const auto & coupled_dof : row)
    2343      257386 :       jacobian.add(dof, coupled_dof, 0);
    2344             :   }
    2345        4135 : }
    2346             : 
    2347             : void
    2348        4763 : NonlinearSystemBase::constraintJacobians(const SparseMatrix<Number> & jacobian_to_view,
    2349             :                                          bool displaced)
    2350             : {
    2351        4763 :   if (!hasMatrix(systemMatrixTag()))
    2352           0 :     mooseError("A system matrix is required");
    2353             : 
    2354        4763 :   auto & jacobian = getMatrix(systemMatrixTag());
    2355             : 
    2356        4763 :   if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    2357           0 :     LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2358             :                                   MAT_NEW_NONZERO_ALLOCATION_ERR,
    2359             :                                   PETSC_FALSE));
    2360        4763 :   if (_fe_problem.ignoreZerosInJacobian())
    2361           0 :     LibmeshPetscCall(MatSetOption(
    2362             :         static_cast<PetscMatrix<Number> &>(jacobian).mat(), MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
    2363             : 
    2364        4763 :   std::vector<numeric_index_type> zero_rows;
    2365             : 
    2366             :   if (displaced)
    2367             :     mooseAssert(_fe_problem.getDisplacedProblem(),
    2368             :                 "If we're calling this method with displaced = true, then we better well have a "
    2369             :                 "displaced problem");
    2370        2192 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    2371        5859 :                                 : static_cast<SubProblem &>(_fe_problem);
    2372        4763 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    2373             : 
    2374             :   bool constraints_applied;
    2375        4763 :   if (!_assemble_constraints_separately)
    2376        4763 :     constraints_applied = false;
    2377        6829 :   for (const auto & it : penetration_locators)
    2378             :   {
    2379        2066 :     if (_assemble_constraints_separately)
    2380             :     {
    2381             :       // Reset the constraint_applied flag before each new constraint, as they need to be
    2382             :       // assembled separately
    2383           0 :       constraints_applied = false;
    2384             :     }
    2385        2066 :     PenetrationLocator & pen_loc = *(it.second);
    2386             : 
    2387        2066 :     std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    2388             : 
    2389        2066 :     BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    2390        2066 :     BoundaryID primary_boundary = pen_loc._primary_boundary;
    2391             : 
    2392        2066 :     zero_rows.clear();
    2393        2066 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
    2394             :     {
    2395             :       const auto & constraints =
    2396        1128 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
    2397             : 
    2398        5726 :       for (const auto & secondary_node_num : secondary_nodes)
    2399             :       {
    2400        4598 :         Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    2401             : 
    2402        4598 :         if (secondary_node.processor_id() == processor_id())
    2403             :         {
    2404        4184 :           if (pen_loc._penetration_info[secondary_node_num])
    2405             :           {
    2406        4184 :             PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
    2407             : 
    2408        4184 :             reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
    2409        4184 :             _fe_problem.reinitOffDiagScalars(0);
    2410             : 
    2411        8368 :             for (const auto & nfc : constraints)
    2412             :             {
    2413        4184 :               if (nfc->isExplicitConstraint())
    2414           0 :                 continue;
    2415             :               // Return if this constraint does not correspond to the primary-secondary pair
    2416             :               // prepared by the outer loops.
    2417             :               // This continue statement is required when, e.g. one secondary surface constrains
    2418             :               // more than one primary surface.
    2419        8368 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    2420        4184 :                   nfc->primaryBoundary() != primary_boundary)
    2421           0 :                 continue;
    2422             : 
    2423        4184 :               nfc->_jacobian = &jacobian_to_view;
    2424             : 
    2425        4184 :               if (nfc->shouldApply())
    2426             :               {
    2427        4184 :                 constraints_applied = true;
    2428             : 
    2429        4184 :                 nfc->prepareShapes(nfc->variable().number());
    2430        4184 :                 nfc->prepareNeighborShapes(nfc->variable().number());
    2431             : 
    2432        4184 :                 nfc->computeJacobian();
    2433             : 
    2434        4184 :                 if (nfc->overwriteSecondaryJacobian())
    2435             :                 {
    2436             :                   // Add this variable's dof's row to be zeroed
    2437        4184 :                   zero_rows.push_back(nfc->variable().nodalDofIndex());
    2438             :                 }
    2439             : 
    2440        4184 :                 std::vector<dof_id_type> secondary_dofs(1, nfc->variable().nodalDofIndex());
    2441             : 
    2442             :                 // Assume that if the user is overwriting the secondary Jacobian, then they are
    2443             :                 // supplying Jacobians that do not correspond to their other physics
    2444             :                 // (e.g. Kernels), hence we should not apply a scalingFactor that is normally
    2445             :                 // based on the order of their other physics (e.g. Kernels)
    2446             :                 Real scaling_factor =
    2447        4184 :                     nfc->overwriteSecondaryJacobian() ? 1. : nfc->variable().scalingFactor();
    2448             : 
    2449             :                 // Cache the jacobian block for the secondary side
    2450        8368 :                 nfc->addJacobian(_fe_problem.assembly(0, number()),
    2451        4184 :                                  nfc->_Kee,
    2452             :                                  secondary_dofs,
    2453        4184 :                                  nfc->_connected_dof_indices,
    2454             :                                  scaling_factor);
    2455             : 
    2456             :                 // Cache Ken, Kne, Knn
    2457        4184 :                 if (nfc->addCouplingEntriesToJacobian())
    2458             :                 {
    2459             :                   // Make sure we use a proper scaling factor (e.g. don't use an interior scaling
    2460             :                   // factor when we're overwriting secondary stuff)
    2461        8368 :                   nfc->addJacobian(_fe_problem.assembly(0, number()),
    2462        4184 :                                    nfc->_Ken,
    2463             :                                    secondary_dofs,
    2464        4184 :                                    nfc->primaryVariable().dofIndicesNeighbor(),
    2465             :                                    scaling_factor);
    2466             : 
    2467             :                   // Use _connected_dof_indices to get all the correct columns
    2468        8368 :                   nfc->addJacobian(_fe_problem.assembly(0, number()),
    2469        4184 :                                    nfc->_Kne,
    2470        4184 :                                    nfc->primaryVariable().dofIndicesNeighbor(),
    2471        4184 :                                    nfc->_connected_dof_indices,
    2472        4184 :                                    nfc->primaryVariable().scalingFactor());
    2473             : 
    2474             :                   // We've handled Ken and Kne, finally handle Knn
    2475        4184 :                   _fe_problem.cacheJacobianNeighbor(0);
    2476             :                 }
    2477             : 
    2478             :                 // Do the off-diagonals next
    2479        4184 :                 const std::vector<MooseVariableFEBase *> coupled_vars = nfc->getCoupledMooseVars();
    2480        8368 :                 for (const auto & jvar : coupled_vars)
    2481             :                 {
    2482             :                   // Only compute jacobians for nonlinear variables
    2483        4184 :                   if (jvar->kind() != Moose::VAR_SOLVER)
    2484           0 :                     continue;
    2485             : 
    2486             :                   // Only compute Jacobian entries if this coupling is being used by the
    2487             :                   // preconditioner
    2488        4256 :                   if (nfc->variable().number() == jvar->number() ||
    2489         144 :                       !_fe_problem.areCoupled(
    2490          72 :                           nfc->variable().number(), jvar->number(), this->number()))
    2491        4112 :                     continue;
    2492             : 
    2493             :                   // Need to zero out the matrices first
    2494          72 :                   _fe_problem.prepareAssembly(0);
    2495             : 
    2496          72 :                   nfc->prepareShapes(nfc->variable().number());
    2497          72 :                   nfc->prepareNeighborShapes(jvar->number());
    2498             : 
    2499          72 :                   nfc->computeOffDiagJacobian(jvar->number());
    2500             : 
    2501             :                   // Cache the jacobian block for the secondary side
    2502         144 :                   nfc->addJacobian(_fe_problem.assembly(0, number()),
    2503          72 :                                    nfc->_Kee,
    2504             :                                    secondary_dofs,
    2505          72 :                                    nfc->_connected_dof_indices,
    2506             :                                    scaling_factor);
    2507             : 
    2508             :                   // Cache Ken, Kne, Knn
    2509          72 :                   if (nfc->addCouplingEntriesToJacobian())
    2510             :                   {
    2511             :                     // Make sure we use a proper scaling factor (e.g. don't use an interior scaling
    2512             :                     // factor when we're overwriting secondary stuff)
    2513         144 :                     nfc->addJacobian(_fe_problem.assembly(0, number()),
    2514          72 :                                      nfc->_Ken,
    2515             :                                      secondary_dofs,
    2516          72 :                                      jvar->dofIndicesNeighbor(),
    2517             :                                      scaling_factor);
    2518             : 
    2519             :                     // Use _connected_dof_indices to get all the correct columns
    2520         144 :                     nfc->addJacobian(_fe_problem.assembly(0, number()),
    2521          72 :                                      nfc->_Kne,
    2522          72 :                                      nfc->variable().dofIndicesNeighbor(),
    2523          72 :                                      nfc->_connected_dof_indices,
    2524          72 :                                      nfc->variable().scalingFactor());
    2525             : 
    2526             :                     // We've handled Ken and Kne, finally handle Knn
    2527          72 :                     _fe_problem.cacheJacobianNeighbor(0);
    2528             :                   }
    2529             :                 }
    2530        4184 :               }
    2531             :             }
    2532             :           }
    2533             :         }
    2534             :       }
    2535             :     }
    2536        2066 :     if (_assemble_constraints_separately)
    2537             :     {
    2538             :       // See if constraints were applied anywhere
    2539           0 :       _communicator.max(constraints_applied);
    2540             : 
    2541           0 :       if (constraints_applied)
    2542             :       {
    2543           0 :         LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2544             :                                       MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2545             :                                       PETSC_TRUE));
    2546             : 
    2547           0 :         jacobian.close();
    2548           0 :         jacobian.zero_rows(zero_rows, 0.0);
    2549           0 :         jacobian.close();
    2550           0 :         _fe_problem.addCachedJacobian(0);
    2551           0 :         jacobian.close();
    2552             :       }
    2553             :     }
    2554             :   }
    2555        4763 :   if (!_assemble_constraints_separately)
    2556             :   {
    2557             :     // See if constraints were applied anywhere
    2558        4763 :     _communicator.max(constraints_applied);
    2559             : 
    2560        4763 :     if (constraints_applied)
    2561             :     {
    2562        1054 :       LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2563             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2564             :                                     PETSC_TRUE));
    2565             : 
    2566        1054 :       jacobian.close();
    2567        1054 :       jacobian.zero_rows(zero_rows, 0.0);
    2568        1054 :       jacobian.close();
    2569        1054 :       _fe_problem.addCachedJacobian(0);
    2570        1054 :       jacobian.close();
    2571             :     }
    2572             :   }
    2573             : 
    2574        4763 :   THREAD_ID tid = 0;
    2575             :   // go over element-element constraint interface
    2576        4763 :   const auto & element_pair_locators = subproblem.geomSearchData()._element_pair_locators;
    2577        4763 :   for (const auto & it : element_pair_locators)
    2578             :   {
    2579           0 :     ElementPairLocator & elem_pair_loc = *(it.second);
    2580             : 
    2581           0 :     if (_constraints.hasActiveElemElemConstraints(it.first, displaced))
    2582             :     {
    2583             :       // ElemElemConstraint objects
    2584             :       const auto & element_constraints =
    2585           0 :           _constraints.getActiveElemElemConstraints(it.first, displaced);
    2586             : 
    2587             :       // go over pair elements
    2588             :       const std::list<std::pair<const Elem *, const Elem *>> & elem_pairs =
    2589           0 :           elem_pair_loc.getElemPairs();
    2590           0 :       for (const auto & pr : elem_pairs)
    2591             :       {
    2592           0 :         const Elem * elem1 = pr.first;
    2593           0 :         const Elem * elem2 = pr.second;
    2594             : 
    2595           0 :         if (elem1->processor_id() != processor_id())
    2596           0 :           continue;
    2597             : 
    2598           0 :         const ElementPairInfo & info = elem_pair_loc.getElemPairInfo(pr);
    2599             : 
    2600             :         // for each element process constraints on the
    2601           0 :         for (const auto & ec : element_constraints)
    2602             :         {
    2603           0 :           _fe_problem.setCurrentSubdomainID(elem1, tid);
    2604           0 :           subproblem.reinitElemPhys(elem1, info._elem1_constraint_q_point, tid);
    2605           0 :           _fe_problem.setNeighborSubdomainID(elem2, tid);
    2606           0 :           subproblem.reinitNeighborPhys(elem2, info._elem2_constraint_q_point, tid);
    2607             : 
    2608           0 :           ec->prepareShapes(ec->variable().number());
    2609           0 :           ec->prepareNeighborShapes(ec->variable().number());
    2610             : 
    2611           0 :           ec->reinit(info);
    2612           0 :           ec->computeJacobian();
    2613           0 :           _fe_problem.cacheJacobian(tid);
    2614           0 :           _fe_problem.cacheJacobianNeighbor(tid);
    2615             :         }
    2616           0 :         _fe_problem.addCachedJacobian(tid);
    2617             :       }
    2618             :     }
    2619             :   }
    2620             : 
    2621             :   // go over NodeElemConstraints
    2622        4763 :   std::set<dof_id_type> unique_secondary_node_ids;
    2623        4763 :   constraints_applied = false;
    2624       20461 :   for (const auto & secondary_id : _mesh.meshSubdomains())
    2625             :   {
    2626       77282 :     for (const auto & primary_id : _mesh.meshSubdomains())
    2627             :     {
    2628       61584 :       if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
    2629             :       {
    2630             :         const auto & constraints =
    2631         180 :             _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
    2632             : 
    2633             :         // get unique set of ids of all nodes on current block
    2634         180 :         unique_secondary_node_ids.clear();
    2635         180 :         const MeshBase & meshhelper = _mesh.getMesh();
    2636         360 :         for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
    2637        8940 :                                           meshhelper.active_subdomain_elements_end(secondary_id)))
    2638             :         {
    2639       49140 :           for (auto & n : elem->node_ref_range())
    2640       40740 :             unique_secondary_node_ids.insert(n.id());
    2641         180 :         }
    2642             : 
    2643       14040 :         for (auto secondary_node_id : unique_secondary_node_ids)
    2644             :         {
    2645       13860 :           const Node & secondary_node = _mesh.nodeRef(secondary_node_id);
    2646             :           // check if secondary node is on current processor
    2647       13860 :           if (secondary_node.processor_id() == processor_id())
    2648             :           {
    2649             :             // This reinits the variables that exist on the secondary node
    2650       11088 :             _fe_problem.reinitNodeFace(&secondary_node, secondary_id, 0);
    2651             : 
    2652             :             // This will set aside residual and jacobian space for the variables that have dofs
    2653             :             // on the secondary node
    2654       11088 :             _fe_problem.prepareAssembly(0);
    2655       11088 :             _fe_problem.reinitOffDiagScalars(0);
    2656             : 
    2657       23584 :             for (const auto & nec : constraints)
    2658             :             {
    2659       12496 :               if (nec->shouldApply())
    2660             :               {
    2661        5680 :                 constraints_applied = true;
    2662             : 
    2663        5680 :                 nec->_jacobian = &jacobian_to_view;
    2664        5680 :                 nec->prepareShapes(nec->variable().number());
    2665        5680 :                 nec->prepareNeighborShapes(nec->variable().number());
    2666             : 
    2667        5680 :                 nec->computeJacobian();
    2668             : 
    2669        5680 :                 if (nec->overwriteSecondaryJacobian())
    2670             :                 {
    2671             :                   // Add this variable's dof's row to be zeroed
    2672           0 :                   zero_rows.push_back(nec->variable().nodalDofIndex());
    2673             :                 }
    2674             : 
    2675        5680 :                 std::vector<dof_id_type> secondary_dofs(1, nec->variable().nodalDofIndex());
    2676             : 
    2677             :                 // Cache the jacobian block for the secondary side
    2678       11360 :                 nec->addJacobian(_fe_problem.assembly(0, number()),
    2679        5680 :                                  nec->_Kee,
    2680             :                                  secondary_dofs,
    2681        5680 :                                  nec->_connected_dof_indices,
    2682        5680 :                                  nec->variable().scalingFactor());
    2683             : 
    2684             :                 // Cache the jacobian block for the primary side
    2685       11360 :                 nec->addJacobian(_fe_problem.assembly(0, number()),
    2686        5680 :                                  nec->_Kne,
    2687        5680 :                                  nec->primaryVariable().dofIndicesNeighbor(),
    2688        5680 :                                  nec->_connected_dof_indices,
    2689        5680 :                                  nec->primaryVariable().scalingFactor());
    2690             : 
    2691        5680 :                 _fe_problem.cacheJacobian(0);
    2692        5680 :                 _fe_problem.cacheJacobianNeighbor(0);
    2693             : 
    2694             :                 // Do the off-diagonals next
    2695        5680 :                 const std::vector<MooseVariableFEBase *> coupled_vars = nec->getCoupledMooseVars();
    2696       11440 :                 for (const auto & jvar : coupled_vars)
    2697             :                 {
    2698             :                   // Only compute jacobians for nonlinear variables
    2699        5760 :                   if (jvar->kind() != Moose::VAR_SOLVER)
    2700          80 :                     continue;
    2701             : 
    2702             :                   // Only compute Jacobian entries if this coupling is being used by the
    2703             :                   // preconditioner
    2704        6320 :                   if (nec->variable().number() == jvar->number() ||
    2705        1280 :                       !_fe_problem.areCoupled(
    2706         640 :                           nec->variable().number(), jvar->number(), this->number()))
    2707        5040 :                     continue;
    2708             : 
    2709             :                   // Need to zero out the matrices first
    2710         640 :                   _fe_problem.prepareAssembly(0);
    2711             : 
    2712         640 :                   nec->prepareShapes(nec->variable().number());
    2713         640 :                   nec->prepareNeighborShapes(jvar->number());
    2714             : 
    2715         640 :                   nec->computeOffDiagJacobian(jvar->number());
    2716             : 
    2717             :                   // Cache the jacobian block for the secondary side
    2718        1280 :                   nec->addJacobian(_fe_problem.assembly(0, number()),
    2719         640 :                                    nec->_Kee,
    2720             :                                    secondary_dofs,
    2721         640 :                                    nec->_connected_dof_indices,
    2722         640 :                                    nec->variable().scalingFactor());
    2723             : 
    2724             :                   // Cache the jacobian block for the primary side
    2725        1280 :                   nec->addJacobian(_fe_problem.assembly(0, number()),
    2726         640 :                                    nec->_Kne,
    2727         640 :                                    nec->variable().dofIndicesNeighbor(),
    2728         640 :                                    nec->_connected_dof_indices,
    2729         640 :                                    nec->variable().scalingFactor());
    2730             : 
    2731         640 :                   _fe_problem.cacheJacobian(0);
    2732         640 :                   _fe_problem.cacheJacobianNeighbor(0);
    2733             :                 }
    2734        5680 :               }
    2735             :             }
    2736             :           }
    2737             :         }
    2738             :       }
    2739             :     }
    2740             :   }
    2741             :   // See if constraints were applied anywhere
    2742        4763 :   _communicator.max(constraints_applied);
    2743             : 
    2744        4763 :   if (constraints_applied)
    2745             :   {
    2746         180 :     LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2747             :                                   MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2748             :                                   PETSC_TRUE));
    2749             : 
    2750         180 :     jacobian.close();
    2751         180 :     jacobian.zero_rows(zero_rows, 0.0);
    2752         180 :     jacobian.close();
    2753         180 :     _fe_problem.addCachedJacobian(0);
    2754         180 :     jacobian.close();
    2755             :   }
    2756        4763 : }
    2757             : 
    2758             : void
    2759      527339 : NonlinearSystemBase::computeScalarKernelsJacobians(const std::set<TagID> & tags)
    2760             : {
    2761             :   MooseObjectWarehouse<ScalarKernelBase> * scalar_kernel_warehouse;
    2762             : 
    2763      527339 :   if (!tags.size() || tags.size() == _fe_problem.numMatrixTags())
    2764      517515 :     scalar_kernel_warehouse = &_scalar_kernels;
    2765        9824 :   else if (tags.size() == 1)
    2766        8350 :     scalar_kernel_warehouse = &(_scalar_kernels.getMatrixTagObjectWarehouse(*(tags.begin()), 0));
    2767             :   else
    2768        1474 :     scalar_kernel_warehouse = &(_scalar_kernels.getMatrixTagsObjectWarehouse(tags, 0));
    2769             : 
    2770             :   // Compute the diagonal block for scalar variables
    2771      527339 :   if (scalar_kernel_warehouse->hasActiveObjects())
    2772             :   {
    2773       17554 :     const auto & scalars = scalar_kernel_warehouse->getActiveObjects();
    2774             : 
    2775       17554 :     _fe_problem.reinitScalars(/*tid=*/0);
    2776             : 
    2777       17554 :     _fe_problem.reinitOffDiagScalars(/*_tid*/ 0);
    2778             : 
    2779       17554 :     bool have_scalar_contributions = false;
    2780       62904 :     for (const auto & kernel : scalars)
    2781             :     {
    2782       45350 :       if (!kernel->computesJacobian())
    2783           0 :         continue;
    2784             : 
    2785       45350 :       kernel->reinit();
    2786       45350 :       const std::vector<dof_id_type> & dof_indices = kernel->variable().dofIndices();
    2787       45350 :       const DofMap & dof_map = kernel->variable().dofMap();
    2788       45350 :       const dof_id_type first_dof = dof_map.first_dof();
    2789       45350 :       const dof_id_type end_dof = dof_map.end_dof();
    2790       51509 :       for (dof_id_type dof : dof_indices)
    2791             :       {
    2792       45392 :         if (dof >= first_dof && dof < end_dof)
    2793             :         {
    2794       39233 :           kernel->computeJacobian();
    2795       39233 :           _fe_problem.addJacobianOffDiagScalar(kernel->variable().number());
    2796       39233 :           have_scalar_contributions = true;
    2797       39233 :           break;
    2798             :         }
    2799             :       }
    2800             :     }
    2801             : 
    2802       17554 :     if (have_scalar_contributions)
    2803       15622 :       _fe_problem.addJacobianScalar();
    2804             :   }
    2805      527339 : }
    2806             : 
    2807             : void
    2808      543399 : NonlinearSystemBase::jacobianSetup()
    2809             : {
    2810      543399 :   SolverSystem::jacobianSetup();
    2811             : 
    2812     1136935 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
    2813             :   {
    2814      593536 :     _kernels.jacobianSetup(tid);
    2815      593536 :     _nodal_kernels.jacobianSetup(tid);
    2816      593536 :     _dirac_kernels.jacobianSetup(tid);
    2817      593536 :     if (_doing_dg)
    2818        2998 :       _dg_kernels.jacobianSetup(tid);
    2819      593536 :     _interface_kernels.jacobianSetup(tid);
    2820      593536 :     _element_dampers.jacobianSetup(tid);
    2821      593536 :     _nodal_dampers.jacobianSetup(tid);
    2822      593536 :     _integrated_bcs.jacobianSetup(tid);
    2823             :   }
    2824      543399 :   _scalar_kernels.jacobianSetup();
    2825      543399 :   _constraints.jacobianSetup();
    2826      543399 :   _general_dampers.jacobianSetup();
    2827      543399 :   _nodal_bcs.jacobianSetup();
    2828      543399 :   _preset_nodal_bcs.jacobianSetup();
    2829      543399 :   _ad_preset_nodal_bcs.jacobianSetup();
    2830             : 
    2831             : #ifdef MOOSE_KOKKOS_ENABLED
    2832      355516 :   _kokkos_kernels.jacobianSetup();
    2833      355516 :   _kokkos_nodal_kernels.jacobianSetup();
    2834      355516 :   _kokkos_integrated_bcs.jacobianSetup();
    2835      355516 :   _kokkos_nodal_bcs.jacobianSetup();
    2836             : #endif
    2837             : 
    2838             :   // Avoid recursion
    2839      543399 :   if (this == &_fe_problem.currentNonlinearSystem())
    2840      527339 :     _fe_problem.jacobianSetup();
    2841      543399 :   _app.solutionInvalidity().resetSolutionInvalidCurrentIteration();
    2842      543399 : }
    2843             : 
    2844             : void
    2845      527339 : NonlinearSystemBase::computeJacobianInternal(const std::set<TagID> & tags)
    2846             : {
    2847     1582017 :   TIME_SECTION("computeJacobianInternal", 3);
    2848             : 
    2849      527339 :   _fe_problem.setCurrentNonlinearSystem(number());
    2850             : 
    2851             :   // Make matrix ready to use
    2852      527339 :   activateAllMatrixTags();
    2853             : 
    2854     1574179 :   for (auto tag : tags)
    2855             :   {
    2856     1046840 :     if (!hasMatrix(tag))
    2857      517515 :       continue;
    2858             : 
    2859      529325 :     auto & jacobian = getMatrix(tag);
    2860             :     // Necessary for speed
    2861      529325 :     if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&jacobian))
    2862             :     {
    2863      528039 :       LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
    2864             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2865             :                                     PETSC_TRUE));
    2866      528039 :       if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    2867       13371 :         LibmeshPetscCall(
    2868             :             MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
    2869      528039 :       if (_fe_problem.ignoreZerosInJacobian())
    2870           0 :         LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2871             :                                       MAT_IGNORE_ZERO_ENTRIES,
    2872             :                                       PETSC_TRUE));
    2873             :     }
    2874             :   }
    2875             : 
    2876      527339 :   jacobianSetup();
    2877             : 
    2878             : #ifdef MOOSE_KOKKOS_ENABLED
    2879      344822 :   if (_fe_problem.hasKokkosResidualObjects())
    2880        4437 :     computeKokkosJacobian(tags);
    2881             : #endif
    2882             : 
    2883             :   // Jacobian contributions from UOs - for now this is used for ray tracing
    2884             :   // and ray kernels that contribute to the Jacobian (think line sources)
    2885      527339 :   std::vector<UserObject *> uos;
    2886      527339 :   _fe_problem.theWarehouse()
    2887     1054678 :       .query()
    2888      527339 :       .condition<AttribSystem>("UserObject")
    2889      527339 :       .condition<AttribExecOns>(EXEC_PRE_KERNELS)
    2890      527339 :       .queryInto(uos);
    2891      527339 :   for (auto & uo : uos)
    2892           0 :     uo->jacobianSetup();
    2893      527339 :   for (auto & uo : uos)
    2894             :   {
    2895           0 :     uo->initialize();
    2896           0 :     uo->execute();
    2897           0 :     uo->finalize();
    2898             :   }
    2899             : 
    2900             :   // reinit scalar variables
    2901     1103442 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    2902      576103 :     _fe_problem.reinitScalars(tid);
    2903             : 
    2904             :   PARALLEL_TRY
    2905             :   {
    2906             :     // We would like to compute ScalarKernels, block NodalKernels, FVFluxKernels, and mortar objects
    2907             :     // up front because we want these included whether we are computing an ordinary Jacobian or a
    2908             :     // Jacobian for determining variable scaling factors
    2909      527339 :     computeScalarKernelsJacobians(tags);
    2910             : 
    2911             :     // Block restricted Nodal Kernels
    2912      527339 :     if (_nodal_kernels.hasActiveBlockObjects())
    2913             :     {
    2914        3998 :       ComputeNodalKernelJacobiansThread cnkjt(_fe_problem, *this, _nodal_kernels, tags);
    2915        3998 :       const ConstNodeRange & range = _fe_problem.getCurrentAlgebraicNodeRange();
    2916        3998 :       Threads::parallel_reduce(range, cnkjt);
    2917             : 
    2918        3998 :       unsigned int n_threads = libMesh::n_threads();
    2919        9262 :       for (unsigned int i = 0; i < n_threads;
    2920             :            i++) // Add any cached jacobians that might be hanging around
    2921        5264 :         _fe_problem.assembly(i, number()).addCachedJacobian(Assembly::GlobalDataKey{});
    2922        3998 :     }
    2923             : 
    2924             :     using FVRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
    2925      527339 :     if (_fe_problem.haveFV())
    2926             :     {
    2927             :       // the same loop works for both residual and jacobians because it keys
    2928             :       // off of FEProblem's _currently_computing_jacobian parameter
    2929             :       ComputeFVFluxJacobianThread<FVRange> fvj(
    2930       37610 :           _fe_problem, this->number(), tags, /*on_displaced=*/false);
    2931       37610 :       FVRange faces(_fe_problem.mesh().ownedFaceInfoBegin(), _fe_problem.mesh().ownedFaceInfoEnd());
    2932       37610 :       Threads::parallel_reduce(faces, fvj);
    2933       37610 :     }
    2934      527339 :     if (auto displaced_problem = _fe_problem.getDisplacedProblem();
    2935      527339 :         displaced_problem && displaced_problem->haveFV())
    2936             :     {
    2937             :       ComputeFVFluxJacobianThread<FVRange> fvr(
    2938           0 :           _fe_problem, this->number(), tags, /*on_displaced=*/true);
    2939           0 :       FVRange faces(displaced_problem->mesh().ownedFaceInfoBegin(),
    2940           0 :                     displaced_problem->mesh().ownedFaceInfoEnd());
    2941           0 :       Threads::parallel_reduce(faces, fvr);
    2942      527339 :     }
    2943             : 
    2944      527339 :     mortarConstraints(Moose::ComputeType::Jacobian, {}, tags);
    2945             : 
    2946             :     // Get our element range for looping over
    2947      527339 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    2948             : 
    2949      527339 :     if (_fe_problem.computingScalingJacobian())
    2950             :     {
    2951             :       // Only compute Jacobians corresponding to the diagonals of volumetric compute objects
    2952             :       // because this typically gives us a good representation of the physics. NodalBCs and
    2953             :       // Constraints can introduce dramatically different scales (often order unity).
    2954             :       // IntegratedBCs and/or InterfaceKernels may use penalty factors. DGKernels may be ok, but
    2955             :       // they are almost always used in conjunction with Kernels
    2956         602 :       ComputeJacobianForScalingThread cj(_fe_problem, tags);
    2957         602 :       Threads::parallel_reduce(elem_range, cj);
    2958         602 :       unsigned int n_threads = libMesh::n_threads();
    2959        1263 :       for (unsigned int i = 0; i < n_threads;
    2960             :            i++) // Add any Jacobian contributions still hanging around
    2961         661 :         _fe_problem.addCachedJacobian(i);
    2962             : 
    2963             :       // Check whether any exceptions were thrown and propagate this information for parallel
    2964             :       // consistency before
    2965             :       // 1) we do parallel communication when closing tagged matrices
    2966             :       // 2) early returning before reaching our PARALLEL_CATCH below
    2967         602 :       _fe_problem.checkExceptionAndStopSolve();
    2968             : 
    2969         602 :       closeTaggedMatrices(tags);
    2970             : 
    2971         602 :       return;
    2972         602 :     }
    2973             : 
    2974      526737 :     switch (_fe_problem.coupling())
    2975             :     {
    2976      433388 :       case Moose::COUPLING_DIAG:
    2977             :       {
    2978      433388 :         ComputeJacobianThread cj(_fe_problem, tags);
    2979      433388 :         Threads::parallel_reduce(elem_range, cj);
    2980             : 
    2981      433380 :         unsigned int n_threads = libMesh::n_threads();
    2982      908780 :         for (unsigned int i = 0; i < n_threads;
    2983             :              i++) // Add any Jacobian contributions still hanging around
    2984      475400 :           _fe_problem.addCachedJacobian(i);
    2985             : 
    2986             :         // Boundary restricted Nodal Kernels
    2987      433380 :         if (_nodal_kernels.hasActiveBoundaryObjects())
    2988             :         {
    2989          46 :           ComputeNodalKernelBCJacobiansThread cnkjt(_fe_problem, *this, _nodal_kernels, tags);
    2990          46 :           const ConstBndNodeRange & bnd_range = _fe_problem.getCurrentAlgebraicBndNodeRange();
    2991             : 
    2992          46 :           Threads::parallel_reduce(bnd_range, cnkjt);
    2993          46 :           unsigned int n_threads = libMesh::n_threads();
    2994          96 :           for (unsigned int i = 0; i < n_threads;
    2995             :                i++) // Add any cached jacobians that might be hanging around
    2996          50 :             _fe_problem.assembly(i, number()).addCachedJacobian(Assembly::GlobalDataKey{});
    2997          46 :         }
    2998      433380 :       }
    2999      433380 :       break;
    3000             : 
    3001       93349 :       default:
    3002             :       case Moose::COUPLING_CUSTOM:
    3003             :       {
    3004       93349 :         ComputeFullJacobianThread cj(_fe_problem, tags);
    3005       93349 :         Threads::parallel_reduce(elem_range, cj);
    3006       93349 :         unsigned int n_threads = libMesh::n_threads();
    3007             : 
    3008      193378 :         for (unsigned int i = 0; i < n_threads; i++)
    3009      100033 :           _fe_problem.addCachedJacobian(i);
    3010             : 
    3011             :         // Boundary restricted Nodal Kernels
    3012       93345 :         if (_nodal_kernels.hasActiveBoundaryObjects())
    3013             :         {
    3014          10 :           ComputeNodalKernelBCJacobiansThread cnkjt(_fe_problem, *this, _nodal_kernels, tags);
    3015          10 :           const ConstBndNodeRange & bnd_range = _fe_problem.getCurrentAlgebraicBndNodeRange();
    3016             : 
    3017          10 :           Threads::parallel_reduce(bnd_range, cnkjt);
    3018          10 :           unsigned int n_threads = libMesh::n_threads();
    3019          21 :           for (unsigned int i = 0; i < n_threads;
    3020             :                i++) // Add any cached jacobians that might be hanging around
    3021          11 :             _fe_problem.assembly(i, number()).addCachedJacobian(Assembly::GlobalDataKey{});
    3022          10 :         }
    3023       93349 :       }
    3024       93345 :       break;
    3025             :     }
    3026             : 
    3027      526725 :     computeDiracContributions(tags, true);
    3028             : 
    3029             :     static bool first = true;
    3030             : 
    3031             :     // This adds zeroes into geometric coupling entries to ensure they stay in the matrix
    3032     1052826 :     if ((_fe_problem.restoreOriginalNonzeroPattern() || first) &&
    3033      526105 :         _add_implicit_geometric_coupling_entries_to_jacobian)
    3034             :     {
    3035        3051 :       first = false;
    3036        3051 :       addImplicitGeometricCouplingEntries(_fe_problem.geomSearchData());
    3037             : 
    3038        3051 :       if (_fe_problem.getDisplacedProblem())
    3039        1084 :         addImplicitGeometricCouplingEntries(_fe_problem.getDisplacedProblem()->geomSearchData());
    3040             :     }
    3041             :   }
    3042      526721 :   PARALLEL_CATCH;
    3043             : 
    3044             :   // Have no idea how to have constraints work
    3045             :   // with the tag system
    3046             :   PARALLEL_TRY
    3047             :   {
    3048             :     // Add in Jacobian contributions from other Constraints
    3049      526619 :     if (_fe_problem._has_constraints && tags.count(systemMatrixTag()))
    3050             :     {
    3051             :       // Some constraints need to be able to read values from the Jacobian, which requires that it
    3052             :       // be closed/assembled
    3053        3667 :       auto & system_matrix = getMatrix(systemMatrixTag());
    3054             : #if PETSC_RELEASE_GREATER_EQUALS(3, 23, 0)
    3055             :       SparseMatrix<Number> * view_jac_ptr;
    3056        3667 :       std::unique_ptr<SparseMatrix<Number>> hash_copy;
    3057        3667 :       if (system_matrix.use_hash_table())
    3058             :       {
    3059        2309 :         hash_copy = libMesh::cast_ref<PetscMatrix<Number> &>(system_matrix).copy_from_hash();
    3060        2309 :         view_jac_ptr = hash_copy.get();
    3061             :       }
    3062             :       else
    3063        1358 :         view_jac_ptr = &system_matrix;
    3064        3667 :       auto & jacobian_to_view = *view_jac_ptr;
    3065             : #else
    3066             :       auto & jacobian_to_view = system_matrix;
    3067             : #endif
    3068        3667 :       if (&jacobian_to_view == &system_matrix)
    3069        1358 :         system_matrix.close();
    3070             : 
    3071             :       // Nodal Constraints
    3072        3667 :       enforceNodalConstraintsJacobian();
    3073             : 
    3074             :       // Undisplaced Constraints
    3075        3667 :       constraintJacobians(jacobian_to_view, false);
    3076             : 
    3077             :       // Displaced Constraints
    3078        3667 :       if (_fe_problem.getDisplacedProblem())
    3079        1096 :         constraintJacobians(jacobian_to_view, true);
    3080        3667 :     }
    3081             :   }
    3082      526619 :   PARALLEL_CATCH;
    3083             : 
    3084             :   // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs
    3085             :   // on boundary nodes
    3086      526619 :   if (_has_diag_save_in)
    3087         185 :     _fe_problem.getAuxiliarySystem().solution().close();
    3088             : 
    3089             :   PARALLEL_TRY
    3090             :   {
    3091             :     MooseObjectWarehouse<NodalBCBase> * nbc_warehouse;
    3092             :     // Select nodal kernels
    3093      526619 :     if (tags.size() == _fe_problem.numMatrixTags() || !tags.size())
    3094      516805 :       nbc_warehouse = &_nodal_bcs;
    3095        9814 :     else if (tags.size() == 1)
    3096        8340 :       nbc_warehouse = &(_nodal_bcs.getMatrixTagObjectWarehouse(*(tags.begin()), 0));
    3097             :     else
    3098        1474 :       nbc_warehouse = &(_nodal_bcs.getMatrixTagsObjectWarehouse(tags, 0));
    3099             : 
    3100      526619 :     if (nbc_warehouse->hasActiveObjects())
    3101             :     {
    3102             :       // We may be switching from add to set. Moreover, we rely on a call to MatZeroRows to enforce
    3103             :       // the nodal boundary condition constraints which requires that the matrix be truly assembled
    3104             :       // as opposed to just flushed. Consequently we can't do the following despite any desire to
    3105             :       // keep our initial sparsity pattern honored (see https://gitlab.com/petsc/petsc/-/issues/852)
    3106             :       //
    3107             :       // flushTaggedMatrices(tags);
    3108      429899 :       closeTaggedMatrices(tags);
    3109             : 
    3110             :       // Cache the information about which BCs are coupled to which
    3111             :       // variables, so we don't have to figure it out for each node.
    3112      429899 :       std::map<std::string, std::set<unsigned int>> bc_involved_vars;
    3113      429899 :       const std::set<BoundaryID> & all_boundary_ids = _mesh.getBoundaryIDs();
    3114     2157412 :       for (const auto & bid : all_boundary_ids)
    3115             :       {
    3116             :         // Get reference to all the NodalBCs for this ID.  This is only
    3117             :         // safe if there are NodalBCBases there to be gotten...
    3118     1727513 :         if (nbc_warehouse->hasActiveBoundaryObjects(bid))
    3119             :         {
    3120      851177 :           const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(bid);
    3121     1788010 :           for (const auto & bc : bcs)
    3122             :           {
    3123             :             const std::vector<MooseVariableFEBase *> & coupled_moose_vars =
    3124      936833 :                 bc->getCoupledMooseVars();
    3125             : 
    3126             :             // Create the set of "involved" MOOSE nonlinear vars, which includes all coupled vars
    3127             :             // and the BC's own variable
    3128      936833 :             std::set<unsigned int> & var_set = bc_involved_vars[bc->name()];
    3129      995105 :             for (const auto & coupled_var : coupled_moose_vars)
    3130       58272 :               if (coupled_var->kind() == Moose::VAR_SOLVER)
    3131       56694 :                 var_set.insert(coupled_var->number());
    3132             : 
    3133      936833 :             var_set.insert(bc->variable().number());
    3134             :           }
    3135             :         }
    3136             :       }
    3137             : 
    3138             :       // reinit scalar variables again. This reinit does not re-fill any of the scalar variable
    3139             :       // solution arrays because that was done above. It only will reorder the derivative
    3140             :       // information for AD calculations to be suitable for NodalBC calculations
    3141      898322 :       for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    3142      468423 :         _fe_problem.reinitScalars(tid, true);
    3143             : 
    3144             :       // Get variable coupling list.  We do all the NodalBCBase stuff on
    3145             :       // thread 0...  The couplingEntries() data structure determines
    3146             :       // which variables are "coupled" as far as the preconditioner is
    3147             :       // concerned, not what variables a boundary condition specifically
    3148             :       // depends on.
    3149      429899 :       auto & coupling_entries = _fe_problem.couplingEntries(/*_tid=*/0, this->number());
    3150             : 
    3151             :       // Compute Jacobians for NodalBCBases
    3152      429899 :       const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    3153    22411535 :       for (const auto & bnode : bnd_nodes)
    3154             :       {
    3155    21981636 :         BoundaryID boundary_id = bnode->_bnd_id;
    3156    21981636 :         Node * node = bnode->_node;
    3157             : 
    3158    32254745 :         if (nbc_warehouse->hasActiveBoundaryObjects(boundary_id) &&
    3159    10273109 :             node->processor_id() == processor_id())
    3160             :         {
    3161     8013348 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
    3162             : 
    3163     8013348 :           const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id);
    3164    17050445 :           for (const auto & bc : bcs)
    3165             :           {
    3166             :             // Get the set of involved MOOSE vars for this BC
    3167     9037097 :             std::set<unsigned int> & var_set = bc_involved_vars[bc->name()];
    3168             : 
    3169             :             // Loop over all the variables whose Jacobian blocks are
    3170             :             // actually being computed, call computeOffDiagJacobian()
    3171             :             // for each one which is actually coupled (otherwise the
    3172             :             // value is zero.)
    3173    22747630 :             for (const auto & it : coupling_entries)
    3174             :             {
    3175    13710533 :               unsigned int ivar = it.first->number(), jvar = it.second->number();
    3176             : 
    3177             :               // We are only going to call computeOffDiagJacobian() if:
    3178             :               // 1.) the BC's variable is ivar
    3179             :               // 2.) jvar is "involved" with the BC (including jvar==ivar), and
    3180             :               // 3.) the BC should apply.
    3181    13710533 :               if ((bc->variable().number() == ivar) && var_set.count(jvar) && bc->shouldApply())
    3182     9126481 :                 bc->computeOffDiagJacobian(jvar);
    3183             :             }
    3184             : 
    3185     9037097 :             const auto & coupled_scalar_vars = bc->getCoupledMooseScalarVars();
    3186     9037468 :             for (const auto & jvariable : coupled_scalar_vars)
    3187         371 :               if (hasScalarVariable(jvariable->name()))
    3188         371 :                 bc->computeOffDiagJacobianScalar(jvariable->number());
    3189             :           }
    3190             :         }
    3191             :       } // end loop over boundary nodes
    3192             : 
    3193             :       // Set the cached NodalBCBase values in the Jacobian matrix
    3194      429899 :       _fe_problem.assembly(0, number()).setCachedJacobian(Assembly::GlobalDataKey{});
    3195      429899 :     }
    3196             :   }
    3197      526619 :   PARALLEL_CATCH;
    3198             : 
    3199      526619 :   closeTaggedMatrices(tags);
    3200             : 
    3201             :   // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs
    3202             :   // on boundary nodes
    3203      526619 :   if (_has_nodalbc_diag_save_in)
    3204          23 :     _fe_problem.getAuxiliarySystem().solution().close();
    3205             : 
    3206      526619 :   if (hasDiagSaveIn())
    3207         185 :     _fe_problem.getAuxiliarySystem().update();
    3208             : 
    3209             :   // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
    3210             :   // counters
    3211      526619 :   _app.solutionInvalidity().syncIteration();
    3212      526619 :   _app.solutionInvalidity().solutionInvalidAccumulation();
    3213      528035 : }
    3214             : 
    3215             : void
    3216           0 : NonlinearSystemBase::computeJacobian(SparseMatrix<Number> & jacobian)
    3217             : {
    3218           0 :   _nl_matrix_tags.clear();
    3219             : 
    3220           0 :   auto & tags = _fe_problem.getMatrixTags();
    3221             : 
    3222           0 :   for (auto & tag : tags)
    3223           0 :     _nl_matrix_tags.insert(tag.second);
    3224             : 
    3225           0 :   computeJacobian(jacobian, _nl_matrix_tags);
    3226           0 : }
    3227             : 
    3228             : void
    3229           0 : NonlinearSystemBase::computeJacobian(SparseMatrix<Number> & jacobian, const std::set<TagID> & tags)
    3230             : {
    3231           0 :   associateMatrixToTag(jacobian, systemMatrixTag());
    3232             : 
    3233           0 :   computeJacobianTags(tags);
    3234             : 
    3235           0 :   disassociateMatrixFromTag(jacobian, systemMatrixTag());
    3236           0 : }
    3237             : 
    3238             : void
    3239      527339 : NonlinearSystemBase::computeJacobianTags(const std::set<TagID> & tags)
    3240             : {
    3241     1582017 :   TIME_SECTION("computeJacobianTags", 5);
    3242             : 
    3243      527339 :   FloatingPointExceptionGuard fpe_guard(_app);
    3244             : 
    3245             :   try
    3246             :   {
    3247      527339 :     computeJacobianInternal(tags);
    3248             :   }
    3249         106 :   catch (MooseException & e)
    3250             :   {
    3251             :     // The buck stops here, we have already handled the exception by
    3252             :     // calling stopSolve(), it is now up to PETSc to return a
    3253             :     // "diverged" reason during the next solve.
    3254         102 :   }
    3255      527331 : }
    3256             : 
    3257             : void
    3258         302 : NonlinearSystemBase::computeJacobianBlocks(std::vector<JacobianBlock *> & blocks)
    3259             : {
    3260         302 :   _nl_matrix_tags.clear();
    3261             : 
    3262         302 :   auto & tags = _fe_problem.getMatrixTags();
    3263         906 :   for (auto & tag : tags)
    3264         604 :     _nl_matrix_tags.insert(tag.second);
    3265             : 
    3266         302 :   computeJacobianBlocks(blocks, _nl_matrix_tags);
    3267         302 : }
    3268             : 
    3269             : void
    3270         662 : NonlinearSystemBase::computeJacobianBlocks(std::vector<JacobianBlock *> & blocks,
    3271             :                                            const std::set<TagID> & tags)
    3272             : {
    3273        1986 :   TIME_SECTION("computeJacobianBlocks", 3);
    3274         662 :   FloatingPointExceptionGuard fpe_guard(_app);
    3275             : 
    3276        2322 :   for (unsigned int i = 0; i < blocks.size(); i++)
    3277             :   {
    3278        1660 :     SparseMatrix<Number> & jacobian = blocks[i]->_jacobian;
    3279             : 
    3280        1660 :     LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    3281             :                                   MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    3282             :                                   PETSC_TRUE));
    3283        1660 :     if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    3284           0 :       LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    3285             :                                     MAT_NEW_NONZERO_ALLOCATION_ERR,
    3286             :                                     PETSC_TRUE));
    3287             : 
    3288        1660 :     jacobian.zero();
    3289             :   }
    3290             : 
    3291        1387 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    3292         725 :     _fe_problem.reinitScalars(tid);
    3293             : 
    3294             :   PARALLEL_TRY
    3295             :   {
    3296         662 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    3297         662 :     ComputeJacobianBlocksThread cjb(_fe_problem, blocks, tags);
    3298         662 :     Threads::parallel_reduce(elem_range, cjb);
    3299         662 :   }
    3300         662 :   PARALLEL_CATCH;
    3301             : 
    3302        2322 :   for (unsigned int i = 0; i < blocks.size(); i++)
    3303        1660 :     blocks[i]->_jacobian.close();
    3304             : 
    3305        2322 :   for (unsigned int i = 0; i < blocks.size(); i++)
    3306             :   {
    3307        1660 :     libMesh::System & precond_system = blocks[i]->_precond_system;
    3308        1660 :     SparseMatrix<Number> & jacobian = blocks[i]->_jacobian;
    3309             : 
    3310        1660 :     unsigned int ivar = blocks[i]->_ivar;
    3311        1660 :     unsigned int jvar = blocks[i]->_jvar;
    3312             : 
    3313             :     // Dirichlet BCs
    3314        1660 :     std::vector<numeric_index_type> zero_rows;
    3315             :     PARALLEL_TRY
    3316             :     {
    3317        1660 :       const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    3318       55916 :       for (const auto & bnode : bnd_nodes)
    3319             :       {
    3320       54256 :         BoundaryID boundary_id = bnode->_bnd_id;
    3321       54256 :         Node * node = bnode->_node;
    3322             : 
    3323       54256 :         if (_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
    3324             :         {
    3325       47600 :           const auto & bcs = _nodal_bcs.getActiveBoundaryObjects(boundary_id);
    3326             : 
    3327       47600 :           if (node->processor_id() == processor_id())
    3328             :           {
    3329       37396 :             _fe_problem.reinitNodeFace(node, boundary_id, 0);
    3330             : 
    3331      172510 :             for (const auto & bc : bcs)
    3332      135114 :               if (bc->variable().number() == ivar && bc->shouldApply())
    3333             :               {
    3334             :                 // The first zero is for the variable number... there is only one variable in
    3335             :                 // each mini-system The second zero only works with Lagrange elements!
    3336       51264 :                 zero_rows.push_back(node->dof_number(precond_system.number(), 0, 0));
    3337             :               }
    3338             :           }
    3339             :         }
    3340             :       }
    3341             :     }
    3342        1660 :     PARALLEL_CATCH;
    3343             : 
    3344        1660 :     jacobian.close();
    3345             : 
    3346             :     // This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
    3347        1660 :     if (ivar == jvar)
    3348        1544 :       jacobian.zero_rows(zero_rows, 1.0);
    3349             :     else
    3350         116 :       jacobian.zero_rows(zero_rows, 0.0);
    3351             : 
    3352        1660 :     jacobian.close();
    3353        1660 :   }
    3354         662 : }
    3355             : 
    3356             : void
    3357      370503 : NonlinearSystemBase::updateActive(THREAD_ID tid)
    3358             : {
    3359      370503 :   _element_dampers.updateActive(tid);
    3360      370503 :   _nodal_dampers.updateActive(tid);
    3361      370503 :   _integrated_bcs.updateActive(tid);
    3362      370503 :   _dg_kernels.updateActive(tid);
    3363      370503 :   _interface_kernels.updateActive(tid);
    3364      370503 :   _dirac_kernels.updateActive(tid);
    3365      370503 :   _kernels.updateActive(tid);
    3366      370503 :   _nodal_kernels.updateActive(tid);
    3367             : 
    3368      370503 :   if (tid == 0)
    3369             :   {
    3370      340472 :     _general_dampers.updateActive();
    3371      340472 :     _nodal_bcs.updateActive();
    3372      340472 :     _preset_nodal_bcs.updateActive();
    3373      340472 :     _ad_preset_nodal_bcs.updateActive();
    3374      340472 :     _splits.updateActive();
    3375      340472 :     _constraints.updateActive();
    3376      340472 :     _scalar_kernels.updateActive();
    3377             : 
    3378             : #ifdef MOOSE_KOKKOS_ENABLED
    3379      224464 :     _kokkos_kernels.updateActive();
    3380      224464 :     _kokkos_nodal_kernels.updateActive();
    3381      224464 :     _kokkos_integrated_bcs.updateActive();
    3382      224464 :     _kokkos_nodal_bcs.updateActive();
    3383      224464 :     _kokkos_preset_nodal_bcs.updateActive();
    3384             : #endif
    3385             :   }
    3386      370503 : }
    3387             : 
    3388             : Real
    3389        1420 : NonlinearSystemBase::computeDamping(const NumericVector<Number> & solution,
    3390             :                                     const NumericVector<Number> & update)
    3391             : {
    3392             :   // Default to no damping
    3393        1420 :   Real damping = 1.0;
    3394        1420 :   bool has_active_dampers = false;
    3395             : 
    3396             :   try
    3397             :   {
    3398        1420 :     if (_element_dampers.hasActiveObjects())
    3399             :     {
    3400             :       PARALLEL_TRY
    3401             :       {
    3402        2450 :         TIME_SECTION("computeDampers", 3, "Computing Dampers");
    3403         490 :         has_active_dampers = true;
    3404         490 :         *_increment_vec = update;
    3405         490 :         ComputeElemDampingThread cid(_fe_problem, *this);
    3406         490 :         Threads::parallel_reduce(_fe_problem.getCurrentAlgebraicElementRange(), cid);
    3407         490 :         damping = std::min(cid.damping(), damping);
    3408         490 :       }
    3409         490 :       PARALLEL_CATCH;
    3410             :     }
    3411             : 
    3412        1370 :     if (_nodal_dampers.hasActiveObjects())
    3413             :     {
    3414             :       PARALLEL_TRY
    3415             :       {
    3416        2620 :         TIME_SECTION("computeDamping::element", 3, "Computing Element Damping");
    3417             : 
    3418         524 :         has_active_dampers = true;
    3419         524 :         *_increment_vec = update;
    3420         524 :         ComputeNodalDampingThread cndt(_fe_problem, *this);
    3421         524 :         Threads::parallel_reduce(_fe_problem.getCurrentAlgebraicNodeRange(), cndt);
    3422         524 :         damping = std::min(cndt.damping(), damping);
    3423         524 :       }
    3424         524 :       PARALLEL_CATCH;
    3425             :     }
    3426             : 
    3427        1314 :     if (_general_dampers.hasActiveObjects())
    3428             :     {
    3429             :       PARALLEL_TRY
    3430             :       {
    3431        2020 :         TIME_SECTION("computeDamping::general", 3, "Computing General Damping");
    3432             : 
    3433         404 :         has_active_dampers = true;
    3434         404 :         const auto & gdampers = _general_dampers.getActiveObjects();
    3435         808 :         for (const auto & damper : gdampers)
    3436             :         {
    3437         404 :           Real gd_damping = damper->computeDamping(solution, update);
    3438             :           try
    3439             :           {
    3440         404 :             damper->checkMinDamping(gd_damping);
    3441             :           }
    3442           8 :           catch (MooseException & e)
    3443             :           {
    3444          16 :             _fe_problem.setException(e.what());
    3445           8 :           }
    3446         404 :           damping = std::min(gd_damping, damping);
    3447             :         }
    3448         404 :       }
    3449         404 :       PARALLEL_CATCH;
    3450             :     }
    3451             :   }
    3452         114 :   catch (MooseException & e)
    3453             :   {
    3454             :     // The buck stops here, we have already handled the exception by
    3455             :     // calling stopSolve(), it is now up to PETSc to return a
    3456             :     // "diverged" reason during the next solve.
    3457         114 :   }
    3458           0 :   catch (std::exception & e)
    3459             :   {
    3460             :     // Allow the libmesh error/exception on negative jacobian
    3461           0 :     const std::string & message = e.what();
    3462           0 :     if (message.find("Jacobian") == std::string::npos)
    3463           0 :       throw e;
    3464           0 :   }
    3465             : 
    3466        1420 :   _communicator.min(damping);
    3467             : 
    3468        1420 :   if (has_active_dampers && damping < 1.0)
    3469         995 :     _console << " Damping factor: " << damping << std::endl;
    3470             : 
    3471        1420 :   return damping;
    3472             : }
    3473             : 
    3474             : void
    3475     3864818 : NonlinearSystemBase::computeDiracContributions(const std::set<TagID> & tags, bool is_jacobian)
    3476             : {
    3477     3864818 :   _fe_problem.clearDiracInfo();
    3478             : 
    3479     3864818 :   std::set<const Elem *> dirac_elements;
    3480             : 
    3481     3864818 :   if (_dirac_kernels.hasActiveObjects())
    3482             :   {
    3483      192085 :     TIME_SECTION("computeDirac", 3, "Computing DiracKernels");
    3484             : 
    3485             :     // TODO: Need a threading fix... but it's complicated!
    3486       79882 :     for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
    3487             :     {
    3488       41481 :       const auto & dkernels = _dirac_kernels.getActiveObjects(tid);
    3489       96376 :       for (const auto & dkernel : dkernels)
    3490             :       {
    3491       54911 :         dkernel->clearPoints();
    3492       54911 :         dkernel->addPoints();
    3493             :       }
    3494             :     }
    3495             : 
    3496       38401 :     ComputeDiracThread cd(_fe_problem, tags, is_jacobian);
    3497             : 
    3498       38401 :     _fe_problem.getDiracElements(dirac_elements);
    3499             : 
    3500       38401 :     DistElemRange range(dirac_elements.begin(), dirac_elements.end(), 1);
    3501             :     // TODO: Make Dirac work thread!
    3502             :     // Threads::parallel_reduce(range, cd);
    3503             : 
    3504       38401 :     cd(range);
    3505       38401 :   }
    3506     3864802 : }
    3507             : 
    3508             : NumericVector<Number> &
    3509           0 : NonlinearSystemBase::residualCopy()
    3510             : {
    3511           0 :   if (!_residual_copy.get())
    3512           0 :     _residual_copy = NumericVector<Number>::build(_communicator);
    3513             : 
    3514           0 :   return *_residual_copy;
    3515             : }
    3516             : 
    3517             : NumericVector<Number> &
    3518         360 : NonlinearSystemBase::residualGhosted()
    3519             : {
    3520         360 :   _need_residual_ghosted = true;
    3521         360 :   if (!_residual_ghosted)
    3522             :   {
    3523             :     // The first time we realize we need a ghosted residual vector,
    3524             :     // we add it.
    3525         576 :     _residual_ghosted = &addVector("residual_ghosted", false, GHOSTED);
    3526             : 
    3527             :     // If we've already realized we need time and/or non-time
    3528             :     // residual vectors, but we haven't yet realized they need to be
    3529             :     // ghosted, fix that now.
    3530             :     //
    3531             :     // If an application changes its mind, the libMesh API lets us
    3532             :     // change the vector.
    3533         288 :     if (_Re_time)
    3534             :     {
    3535          50 :       const auto vector_name = _subproblem.vectorTagName(_Re_time_tag);
    3536          50 :       _Re_time = &system().add_vector(vector_name, false, GHOSTED);
    3537          50 :     }
    3538         288 :     if (_Re_non_time)
    3539             :     {
    3540         288 :       const auto vector_name = _subproblem.vectorTagName(_Re_non_time_tag);
    3541         288 :       _Re_non_time = &system().add_vector(vector_name, false, GHOSTED);
    3542         288 :     }
    3543             :   }
    3544         360 :   return *_residual_ghosted;
    3545             : }
    3546             : 
    3547             : void
    3548       69847 : NonlinearSystemBase::augmentSparsity(SparsityPattern::Graph & sparsity,
    3549             :                                      std::vector<dof_id_type> & n_nz,
    3550             :                                      std::vector<dof_id_type> & n_oz)
    3551             : {
    3552       69847 :   if (_add_implicit_geometric_coupling_entries_to_jacobian)
    3553             :   {
    3554        1231 :     _fe_problem.updateGeomSearch();
    3555             : 
    3556        1231 :     std::unordered_map<dof_id_type, std::vector<dof_id_type>> graph;
    3557             : 
    3558        1231 :     findImplicitGeometricCouplingEntries(_fe_problem.geomSearchData(), graph);
    3559             : 
    3560        1231 :     if (_fe_problem.getDisplacedProblem())
    3561         201 :       findImplicitGeometricCouplingEntries(_fe_problem.getDisplacedProblem()->geomSearchData(),
    3562             :                                            graph);
    3563             : 
    3564        1231 :     const dof_id_type first_dof_on_proc = dofMap().first_dof(processor_id());
    3565        1231 :     const dof_id_type end_dof_on_proc = dofMap().end_dof(processor_id());
    3566             : 
    3567             :     // The total number of dofs on and off processor
    3568        1231 :     const dof_id_type n_dofs_on_proc = dofMap().n_local_dofs();
    3569        1231 :     const dof_id_type n_dofs_not_on_proc = dofMap().n_dofs() - dofMap().n_local_dofs();
    3570             : 
    3571        2088 :     for (const auto & git : graph)
    3572             :     {
    3573         857 :       dof_id_type dof = git.first;
    3574         857 :       dof_id_type local_dof = dof - first_dof_on_proc;
    3575             : 
    3576         857 :       if (dof < first_dof_on_proc || dof >= end_dof_on_proc)
    3577         126 :         continue;
    3578             : 
    3579         731 :       const auto & row = git.second;
    3580             : 
    3581         731 :       SparsityPattern::Row & sparsity_row = sparsity[local_dof];
    3582             : 
    3583         731 :       unsigned int original_row_length = sparsity_row.size();
    3584             : 
    3585         731 :       sparsity_row.insert(sparsity_row.end(), row.begin(), row.end());
    3586             : 
    3587        1462 :       SparsityPattern::sort_row(
    3588         731 :           sparsity_row.begin(), sparsity_row.begin() + original_row_length, sparsity_row.end());
    3589             : 
    3590             :       // Fix up nonzero arrays
    3591        4807 :       for (const auto & coupled_dof : row)
    3592             :       {
    3593        4076 :         if (coupled_dof < first_dof_on_proc || coupled_dof >= end_dof_on_proc)
    3594             :         {
    3595        1224 :           if (n_oz[local_dof] < n_dofs_not_on_proc)
    3596         612 :             n_oz[local_dof]++;
    3597             :         }
    3598             :         else
    3599             :         {
    3600        3464 :           if (n_nz[local_dof] < n_dofs_on_proc)
    3601        3464 :             n_nz[local_dof]++;
    3602             :         }
    3603             :       }
    3604             :     }
    3605        1231 :   }
    3606       69847 : }
    3607             : 
    3608             : void
    3609           0 : NonlinearSystemBase::setSolutionUDot(const NumericVector<Number> & u_dot)
    3610             : {
    3611           0 :   *_u_dot = u_dot;
    3612           0 : }
    3613             : 
    3614             : void
    3615           0 : NonlinearSystemBase::setSolutionUDotDot(const NumericVector<Number> & u_dotdot)
    3616             : {
    3617           0 :   *_u_dotdot = u_dotdot;
    3618           0 : }
    3619             : 
    3620             : void
    3621           0 : NonlinearSystemBase::setSolutionUDotOld(const NumericVector<Number> & u_dot_old)
    3622             : {
    3623           0 :   *_u_dot_old = u_dot_old;
    3624           0 : }
    3625             : 
    3626             : void
    3627           0 : NonlinearSystemBase::setSolutionUDotDotOld(const NumericVector<Number> & u_dotdot_old)
    3628             : {
    3629           0 :   *_u_dotdot_old = u_dotdot_old;
    3630           0 : }
    3631             : 
    3632             : void
    3633       15029 : NonlinearSystemBase::setPreconditioner(std::shared_ptr<MoosePreconditioner> pc)
    3634             : {
    3635       15029 :   if (_preconditioner.get() != nullptr)
    3636           7 :     mooseError("More than one active Preconditioner detected");
    3637             : 
    3638       15022 :   _preconditioner = pc;
    3639       15022 : }
    3640             : 
    3641             : MoosePreconditioner const *
    3642       55556 : NonlinearSystemBase::getPreconditioner() const
    3643             : {
    3644       55556 :   return _preconditioner.get();
    3645             : }
    3646             : 
    3647             : void
    3648         322 : NonlinearSystemBase::setupDampers()
    3649             : {
    3650         322 :   _increment_vec = &_sys.add_vector("u_increment", true, GHOSTED);
    3651         322 : }
    3652             : 
    3653             : void
    3654        1753 : NonlinearSystemBase::reinitIncrementAtQpsForDampers(THREAD_ID /*tid*/,
    3655             :                                                     const std::set<MooseVariable *> & damped_vars)
    3656             : {
    3657        3529 :   for (const auto & var : damped_vars)
    3658        1776 :     var->computeIncrementAtQps(*_increment_vec);
    3659        1753 : }
    3660             : 
    3661             : void
    3662        7441 : NonlinearSystemBase::reinitIncrementAtNodeForDampers(THREAD_ID /*tid*/,
    3663             :                                                      const std::set<MooseVariable *> & damped_vars)
    3664             : {
    3665       14882 :   for (const auto & var : damped_vars)
    3666        7441 :     var->computeIncrementAtNode(*_increment_vec);
    3667        7441 : }
    3668             : 
    3669             : void
    3670       43918 : NonlinearSystemBase::checkKernelCoverage(const std::set<SubdomainID> & mesh_subdomains) const
    3671             : {
    3672             :   // Obtain all blocks and variables covered by all kernels
    3673       43918 :   std::set<SubdomainID> input_subdomains;
    3674       43918 :   std::set<std::string> kernel_variables;
    3675             : 
    3676       43918 :   bool global_kernels_exist = false;
    3677       43918 :   global_kernels_exist |= _scalar_kernels.hasActiveObjects();
    3678       43918 :   global_kernels_exist |= _nodal_kernels.hasActiveObjects();
    3679             : 
    3680       43918 :   _kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3681       43918 :   _dg_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3682       43918 :   _nodal_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3683       43918 :   _scalar_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3684       43918 :   _constraints.subdomainsCovered(input_subdomains, kernel_variables);
    3685             : 
    3686             : #ifdef MOOSE_KOKKOS_ENABLED
    3687       29427 :   _kokkos_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3688       29427 :   _kokkos_nodal_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3689             : #endif
    3690             : 
    3691       43918 :   if (_fe_problem.haveFV())
    3692             :   {
    3693        3538 :     std::vector<FVElementalKernel *> fv_elemental_kernels;
    3694        3538 :     _fe_problem.theWarehouse()
    3695        7076 :         .query()
    3696        3538 :         .template condition<AttribSystem>("FVElementalKernel")
    3697        3538 :         .queryInto(fv_elemental_kernels);
    3698             : 
    3699        7560 :     for (auto fv_kernel : fv_elemental_kernels)
    3700             :     {
    3701        4022 :       if (fv_kernel->blockRestricted())
    3702        1972 :         for (auto block_id : fv_kernel->blockIDs())
    3703        1103 :           input_subdomains.insert(block_id);
    3704             :       else
    3705        3153 :         global_kernels_exist = true;
    3706        4022 :       kernel_variables.insert(fv_kernel->variable().name());
    3707             : 
    3708             :       // Check for lagrange multiplier
    3709        4022 :       if (dynamic_cast<FVScalarLagrangeMultiplierConstraint *>(fv_kernel))
    3710         268 :         kernel_variables.insert(dynamic_cast<FVScalarLagrangeMultiplierConstraint *>(fv_kernel)
    3711         268 :                                     ->lambdaVariable()
    3712         134 :                                     .name());
    3713             :     }
    3714             : 
    3715        3538 :     std::vector<FVFluxKernel *> fv_flux_kernels;
    3716        3538 :     _fe_problem.theWarehouse()
    3717        7076 :         .query()
    3718        3538 :         .template condition<AttribSystem>("FVFluxKernel")
    3719        3538 :         .queryInto(fv_flux_kernels);
    3720             : 
    3721        8819 :     for (auto fv_kernel : fv_flux_kernels)
    3722             :     {
    3723        5281 :       if (fv_kernel->blockRestricted())
    3724        2350 :         for (auto block_id : fv_kernel->blockIDs())
    3725        1250 :           input_subdomains.insert(block_id);
    3726             :       else
    3727        4181 :         global_kernels_exist = true;
    3728        5281 :       kernel_variables.insert(fv_kernel->variable().name());
    3729             :     }
    3730             : 
    3731        3538 :     std::vector<FVInterfaceKernel *> fv_interface_kernels;
    3732        3538 :     _fe_problem.theWarehouse()
    3733        7076 :         .query()
    3734        3538 :         .template condition<AttribSystem>("FVInterfaceKernel")
    3735        3538 :         .queryInto(fv_interface_kernels);
    3736             : 
    3737        3843 :     for (auto fvik : fv_interface_kernels)
    3738         305 :       if (auto scalar_fvik = dynamic_cast<FVScalarLagrangeMultiplierInterface *>(fvik))
    3739          14 :         kernel_variables.insert(scalar_fvik->lambdaVariable().name());
    3740             : 
    3741        3538 :     std::vector<FVFluxBC *> fv_flux_bcs;
    3742        3538 :     _fe_problem.theWarehouse()
    3743        7076 :         .query()
    3744        3538 :         .template condition<AttribSystem>("FVFluxBC")
    3745        3538 :         .queryInto(fv_flux_bcs);
    3746             : 
    3747        5582 :     for (auto fvbc : fv_flux_bcs)
    3748        2044 :       if (auto scalar_fvbc = dynamic_cast<FVBoundaryScalarLagrangeMultiplierConstraint *>(fvbc))
    3749          14 :         kernel_variables.insert(scalar_fvbc->lambdaVariable().name());
    3750        3538 :   }
    3751             : 
    3752             :   // Check kernel coverage of subdomains (blocks) in your mesh
    3753       43918 :   if (!global_kernels_exist)
    3754             :   {
    3755       39902 :     std::set<SubdomainID> difference;
    3756       39902 :     std::set_difference(mesh_subdomains.begin(),
    3757             :                         mesh_subdomains.end(),
    3758             :                         input_subdomains.begin(),
    3759             :                         input_subdomains.end(),
    3760             :                         std::inserter(difference, difference.end()));
    3761             : 
    3762             :     // there supposed to be no kernels on this lower-dimensional subdomain
    3763       40140 :     for (const auto & id : _mesh.interiorLowerDBlocks())
    3764         238 :       difference.erase(id);
    3765       40140 :     for (const auto & id : _mesh.boundaryLowerDBlocks())
    3766         238 :       difference.erase(id);
    3767             : 
    3768       39902 :     if (!difference.empty())
    3769             :     {
    3770             :       std::vector<SubdomainID> difference_vec =
    3771           8 :           std::vector<SubdomainID>(difference.begin(), difference.end());
    3772           8 :       std::vector<SubdomainName> difference_names = _mesh.getSubdomainNames(difference_vec);
    3773           8 :       std::stringstream missing_block_names;
    3774           8 :       std::copy(difference_names.begin(),
    3775             :                 difference_names.end(),
    3776           8 :                 std::ostream_iterator<std::string>(missing_block_names, " "));
    3777           8 :       std::stringstream missing_block_ids;
    3778           8 :       std::copy(difference.begin(),
    3779             :                 difference.end(),
    3780           8 :                 std::ostream_iterator<unsigned int>(missing_block_ids, " "));
    3781             : 
    3782           8 :       mooseError("Each subdomain must contain at least one Kernel.\nThe following block(s) lack an "
    3783           8 :                  "active kernel: " +
    3784           8 :                      missing_block_names.str(),
    3785             :                  " (ids: ",
    3786           8 :                  missing_block_ids.str(),
    3787             :                  ")");
    3788           0 :     }
    3789       39894 :   }
    3790             : 
    3791             :   // Check kernel use of variables
    3792       43910 :   std::set<VariableName> variables(getVariableNames().begin(), getVariableNames().end());
    3793             : 
    3794       43910 :   std::set<VariableName> difference;
    3795       43910 :   std::set_difference(variables.begin(),
    3796             :                       variables.end(),
    3797             :                       kernel_variables.begin(),
    3798             :                       kernel_variables.end(),
    3799             :                       std::inserter(difference, difference.end()));
    3800             : 
    3801             :   // skip checks for varaibles defined on lower-dimensional subdomain
    3802       43910 :   std::set<VariableName> vars(difference);
    3803       44273 :   for (auto & var_name : vars)
    3804             :   {
    3805         363 :     auto blks = getSubdomainsForVar(var_name);
    3806         744 :     for (const auto & id : blks)
    3807         381 :       if (_mesh.interiorLowerDBlocks().count(id) > 0 || _mesh.boundaryLowerDBlocks().count(id) > 0)
    3808         381 :         difference.erase(var_name);
    3809         363 :   }
    3810             : 
    3811       43910 :   if (!difference.empty())
    3812             :   {
    3813           8 :     std::stringstream missing_kernel_vars;
    3814           8 :     std::copy(difference.begin(),
    3815             :               difference.end(),
    3816           8 :               std::ostream_iterator<std::string>(missing_kernel_vars, " "));
    3817           8 :     mooseError("Each variable must be referenced by at least one active Kernel.\nThe following "
    3818           8 :                "variable(s) lack an active kernel: " +
    3819           8 :                missing_kernel_vars.str());
    3820           0 :   }
    3821       43902 : }
    3822             : 
    3823             : bool
    3824       29369 : NonlinearSystemBase::containsTimeKernel()
    3825             : {
    3826       29369 :   auto & time_kernels = _kernels.getVectorTagObjectWarehouse(timeVectorTag(), 0);
    3827             : 
    3828       29369 :   return time_kernels.hasActiveObjects();
    3829             : }
    3830             : 
    3831             : std::vector<std::string>
    3832           0 : NonlinearSystemBase::timeKernelVariableNames()
    3833             : {
    3834           0 :   std::vector<std::string> variable_names;
    3835           0 :   const auto & time_kernels = _kernels.getVectorTagObjectWarehouse(timeVectorTag(), 0);
    3836           0 :   if (time_kernels.hasActiveObjects())
    3837           0 :     for (const auto & kernel : time_kernels.getObjects())
    3838           0 :       variable_names.push_back(kernel->variable().name());
    3839             : 
    3840           0 :   return variable_names;
    3841           0 : }
    3842             : 
    3843             : bool
    3844       30195 : NonlinearSystemBase::needBoundaryMaterialOnSide(BoundaryID bnd_id, THREAD_ID tid) const
    3845             : {
    3846             :   // IntegratedBCs are for now the only objects we consider to be consuming
    3847             :   // matprops on boundaries.
    3848       30195 :   if (_integrated_bcs.hasActiveBoundaryObjects(bnd_id, tid))
    3849        6690 :     for (const auto & bc : _integrated_bcs.getActiveBoundaryObjects(bnd_id, tid))
    3850        4261 :       if (std::static_pointer_cast<MaterialPropertyInterface>(bc)->getMaterialPropertyCalled())
    3851        1604 :         return true;
    3852             : 
    3853             :   // Thin layer heat transfer in the heat_transfer module is being used on a boundary even though
    3854             :   // it's an interface kernel. That boundary is external, on both sides of a gap in a mesh
    3855       28591 :   if (_interface_kernels.hasActiveBoundaryObjects(bnd_id, tid))
    3856         391 :     for (const auto & ik : _interface_kernels.getActiveBoundaryObjects(bnd_id, tid))
    3857         311 :       if (std::static_pointer_cast<MaterialPropertyInterface>(ik)->getMaterialPropertyCalled())
    3858         231 :         return true;
    3859             : 
    3860             :   // Because MortarConstraints do not inherit from BoundaryRestrictable, they are not sorted
    3861             :   // by boundary in the MooseObjectWarehouse. So for now, we return true for all boundaries
    3862             :   // Note: constraints are not threaded at this time
    3863       28360 :   if (_constraints.hasActiveObjects(/*tid*/ 0))
    3864        2535 :     for (const auto & ct : _constraints.getActiveObjects(/*tid*/ 0))
    3865        2124 :       if (auto mpi = std::dynamic_pointer_cast<MaterialPropertyInterface>(ct);
    3866        2124 :           mpi && mpi->getMaterialPropertyCalled())
    3867        2124 :         return true;
    3868       27395 :   return false;
    3869             : }
    3870             : 
    3871             : bool
    3872        3173 : NonlinearSystemBase::needInterfaceMaterialOnSide(BoundaryID bnd_id, THREAD_ID tid) const
    3873             : {
    3874             :   // InterfaceKernels are for now the only objects we consider to be consuming matprops on internal
    3875             :   // boundaries.
    3876        3173 :   if (_interface_kernels.hasActiveBoundaryObjects(bnd_id, tid))
    3877         482 :     for (const auto & ik : _interface_kernels.getActiveBoundaryObjects(bnd_id, tid))
    3878         376 :       if (std::static_pointer_cast<MaterialPropertyInterface>(ik)->getMaterialPropertyCalled())
    3879         270 :         return true;
    3880        2903 :   return false;
    3881             : }
    3882             : 
    3883             : bool
    3884       13336 : NonlinearSystemBase::needInternalNeighborSideMaterial(SubdomainID subdomain_id, THREAD_ID tid) const
    3885             : {
    3886             :   // DGKernels are for now the only objects we consider to be consuming matprops on
    3887             :   // internal sides.
    3888       13336 :   if (_dg_kernels.hasActiveBlockObjects(subdomain_id, tid))
    3889         788 :     for (const auto & dg : _dg_kernels.getActiveBlockObjects(subdomain_id, tid))
    3890         654 :       if (std::static_pointer_cast<MaterialPropertyInterface>(dg)->getMaterialPropertyCalled())
    3891         495 :         return true;
    3892             :   // NOTE:
    3893             :   // HDG kernels do not require face material properties on internal sides at this time.
    3894             :   // The idea is to have element locality of HDG for hybridization
    3895       12841 :   return false;
    3896             : }
    3897             : 
    3898             : bool
    3899           0 : NonlinearSystemBase::doingDG() const
    3900             : {
    3901           0 :   return _doing_dg;
    3902             : }
    3903             : 
    3904             : void
    3905         556 : NonlinearSystemBase::setPreviousNewtonSolution(const NumericVector<Number> & soln)
    3906             : {
    3907         556 :   if (hasVector(Moose::PREVIOUS_NL_SOLUTION_TAG))
    3908         556 :     getVector(Moose::PREVIOUS_NL_SOLUTION_TAG) = soln;
    3909         556 : }
    3910             : 
    3911             : void
    3912     3868899 : NonlinearSystemBase::mortarConstraints(const Moose::ComputeType compute_type,
    3913             :                                        const std::set<TagID> & vector_tags,
    3914             :                                        const std::set<TagID> & matrix_tags)
    3915             : {
    3916             :   parallel_object_only();
    3917             : 
    3918             :   try
    3919             :   {
    3920     3878018 :     for (auto & map_pr : _undisplaced_mortar_functors)
    3921        9119 :       map_pr.second(compute_type, vector_tags, matrix_tags);
    3922             : 
    3923     3873587 :     for (auto & map_pr : _displaced_mortar_functors)
    3924        4688 :       map_pr.second(compute_type, vector_tags, matrix_tags);
    3925             :   }
    3926           0 :   catch (MetaPhysicL::LogicError &)
    3927             :   {
    3928           0 :     mooseError(
    3929             :         "We caught a MetaPhysicL error in NonlinearSystemBase::mortarConstraints. This is very "
    3930             :         "likely due to AD not having a sufficiently large derivative container size. Please run "
    3931             :         "MOOSE configure with the '--with-derivative-size=<n>' option");
    3932           0 :   }
    3933     3868899 : }
    3934             : 
    3935             : void
    3936         439 : NonlinearSystemBase::setupScalingData()
    3937             : {
    3938         439 :   if (_auto_scaling_initd)
    3939           0 :     return;
    3940             : 
    3941             :   // Want the libMesh count of variables, not MOOSE, e.g. I don't care about array variable counts
    3942         439 :   const auto n_vars = system().n_vars();
    3943             : 
    3944         439 :   if (_scaling_group_variables.empty())
    3945             :   {
    3946         427 :     _var_to_group_var.reserve(n_vars);
    3947         427 :     _num_scaling_groups = n_vars;
    3948             : 
    3949        1128 :     for (const auto var_number : make_range(n_vars))
    3950         701 :       _var_to_group_var.emplace(var_number, var_number);
    3951             :   }
    3952             :   else
    3953             :   {
    3954          12 :     std::set<unsigned int> var_numbers, var_numbers_covered, var_numbers_not_covered;
    3955          48 :     for (const auto var_number : make_range(n_vars))
    3956          36 :       var_numbers.insert(var_number);
    3957             : 
    3958          12 :     _num_scaling_groups = _scaling_group_variables.size();
    3959             : 
    3960          24 :     for (const auto group_index : index_range(_scaling_group_variables))
    3961          48 :       for (const auto & var_name : _scaling_group_variables[group_index])
    3962             :       {
    3963          36 :         if (!hasVariable(var_name) && !hasScalarVariable(var_name))
    3964           0 :           mooseError("'",
    3965             :                      var_name,
    3966             :                      "', provided to the 'scaling_group_variables' parameter, does not exist in "
    3967             :                      "the nonlinear system.");
    3968             : 
    3969             :         const MooseVariableBase & var =
    3970          36 :             hasVariable(var_name)
    3971          24 :                 ? static_cast<MooseVariableBase &>(getVariable(0, var_name))
    3972          60 :                 : static_cast<MooseVariableBase &>(getScalarVariable(0, var_name));
    3973          36 :         auto map_pair = _var_to_group_var.emplace(var.number(), group_index);
    3974          36 :         if (!map_pair.second)
    3975           0 :           mooseError("Variable ", var_name, " is contained in multiple scaling grouplings");
    3976          36 :         var_numbers_covered.insert(var.number());
    3977             :       }
    3978             : 
    3979          12 :     std::set_difference(var_numbers.begin(),
    3980             :                         var_numbers.end(),
    3981             :                         var_numbers_covered.begin(),
    3982             :                         var_numbers_covered.end(),
    3983             :                         std::inserter(var_numbers_not_covered, var_numbers_not_covered.begin()));
    3984             : 
    3985          12 :     _num_scaling_groups = _scaling_group_variables.size() + var_numbers_not_covered.size();
    3986             : 
    3987          12 :     auto index = static_cast<unsigned int>(_scaling_group_variables.size());
    3988          12 :     for (auto var_number : var_numbers_not_covered)
    3989           0 :       _var_to_group_var.emplace(var_number, index++);
    3990          12 :   }
    3991             : 
    3992         439 :   _variable_autoscaled.resize(n_vars, true);
    3993         439 :   const auto & number_to_var_map = _vars[0].numberToVariableMap();
    3994             : 
    3995         439 :   if (_ignore_variables_for_autoscaling.size())
    3996          50 :     for (const auto i : index_range(_variable_autoscaled))
    3997          40 :       if (std::find(_ignore_variables_for_autoscaling.begin(),
    3998             :                     _ignore_variables_for_autoscaling.end(),
    3999          80 :                     libmesh_map_find(number_to_var_map, i)->name()) !=
    4000          80 :           _ignore_variables_for_autoscaling.end())
    4001          20 :         _variable_autoscaled[i] = false;
    4002             : 
    4003         439 :   _auto_scaling_initd = true;
    4004             : }
    4005             : 
    4006             : bool
    4007        1112 : NonlinearSystemBase::computeScaling()
    4008             : {
    4009        1112 :   if (_compute_scaling_once && _computed_scaling)
    4010         460 :     return true;
    4011             : 
    4012         652 :   _console << "\nPerforming automatic scaling calculation\n" << std::endl;
    4013             : 
    4014        3260 :   TIME_SECTION("computeScaling", 3, "Computing Automatic Scaling");
    4015             : 
    4016             :   // It's funny but we need to assemble our vector of scaling factors here otherwise we will be
    4017             :   // applying scaling factors of 0 during Assembly of our scaling Jacobian
    4018         652 :   assembleScalingVector();
    4019             : 
    4020             :   // container for repeated access of element global dof indices
    4021         652 :   std::vector<dof_id_type> dof_indices;
    4022             : 
    4023         652 :   if (!_auto_scaling_initd)
    4024         439 :     setupScalingData();
    4025             : 
    4026         652 :   std::vector<Real> inverse_scaling_factors(_num_scaling_groups, 0);
    4027         652 :   std::vector<Real> resid_inverse_scaling_factors(_num_scaling_groups, 0);
    4028         652 :   std::vector<Real> jac_inverse_scaling_factors(_num_scaling_groups, 0);
    4029         652 :   auto & dof_map = dofMap();
    4030             : 
    4031             :   // what types of scaling do we want?
    4032         652 :   bool jac_scaling = _resid_vs_jac_scaling_param < 1. - TOLERANCE;
    4033         652 :   bool resid_scaling = _resid_vs_jac_scaling_param > TOLERANCE;
    4034             : 
    4035         652 :   const NumericVector<Number> & scaling_residual = RHS();
    4036             : 
    4037         652 :   if (jac_scaling)
    4038             :   {
    4039             :     // if (!_auto_scaling_initd)
    4040             :     // We need to reinit this when the number of dofs changes
    4041             :     // but there is no good way to track that
    4042             :     // In theory, it is the job of libmesh system to track this,
    4043             :     // but this special matrix is not owned by libMesh system
    4044             :     // Let us reinit eveytime since it is not expensive
    4045             :     {
    4046         602 :       auto init_vector = NumericVector<Number>::build(this->comm());
    4047         602 :       init_vector->init(system().n_dofs(), system().n_local_dofs(), /*fast=*/false, PARALLEL);
    4048             : 
    4049         602 :       _scaling_matrix->clear();
    4050         602 :       _scaling_matrix->init(*init_vector);
    4051         602 :     }
    4052             : 
    4053         602 :     _fe_problem.computingScalingJacobian(true);
    4054             :     // Dispatch to derived classes to ensure that we use the correct matrix tag
    4055         602 :     computeScalingJacobian();
    4056         602 :     _fe_problem.computingScalingJacobian(false);
    4057             :   }
    4058             : 
    4059         652 :   if (resid_scaling)
    4060             :   {
    4061          50 :     _fe_problem.computingScalingResidual(true);
    4062          50 :     _fe_problem.computingNonlinearResid(true);
    4063             :     // Dispatch to derived classes to ensure that we use the correct vector tag
    4064          50 :     computeScalingResidual();
    4065          50 :     _fe_problem.computingNonlinearResid(false);
    4066          50 :     _fe_problem.computingScalingResidual(false);
    4067             :   }
    4068             : 
    4069             :   // Did something bad happen during residual/Jacobian scaling computation?
    4070         652 :   if (_fe_problem.getFailNextNonlinearConvergenceCheck())
    4071           0 :     return false;
    4072             : 
    4073      228330 :   auto examine_dof_indices = [this,
    4074             :                               jac_scaling,
    4075             :                               resid_scaling,
    4076             :                               &dof_map,
    4077             :                               &jac_inverse_scaling_factors,
    4078             :                               &resid_inverse_scaling_factors,
    4079             :                               &scaling_residual](const auto & dof_indices, const auto var_number)
    4080             :   {
    4081     1136309 :     for (auto dof_index : dof_indices)
    4082      907979 :       if (dof_map.local_index(dof_index))
    4083             :       {
    4084      903220 :         if (jac_scaling)
    4085             :         {
    4086             :           // For now we will use the diagonal for determining scaling
    4087      899103 :           auto mat_value = (*_scaling_matrix)(dof_index, dof_index);
    4088      899103 :           auto & factor = jac_inverse_scaling_factors[_var_to_group_var[var_number]];
    4089      899103 :           factor = std::max(factor, std::abs(mat_value));
    4090             :         }
    4091      903220 :         if (resid_scaling)
    4092             :         {
    4093        4117 :           auto vec_value = scaling_residual(dof_index);
    4094        4117 :           auto & factor = resid_inverse_scaling_factors[_var_to_group_var[var_number]];
    4095        4117 :           factor = std::max(factor, std::abs(vec_value));
    4096             :         }
    4097             :       }
    4098      228330 :   };
    4099             : 
    4100             :   // Compute our scaling factors for the spatial field variables
    4101       82245 :   for (const auto & elem : _fe_problem.getCurrentAlgebraicElementRange())
    4102      310836 :     for (const auto i : make_range(system().n_vars()))
    4103      229243 :       if (_variable_autoscaled[i] && system().variable_type(i).family != SCALAR)
    4104             :       {
    4105      228237 :         dof_map.dof_indices(elem, dof_indices, i);
    4106      228237 :         examine_dof_indices(dof_indices, i);
    4107             :       }
    4108             : 
    4109        1712 :   for (const auto i : make_range(system().n_vars()))
    4110        1060 :     if (_variable_autoscaled[i] && system().variable_type(i).family == SCALAR)
    4111             :     {
    4112          93 :       dof_map.SCALAR_dof_indices(dof_indices, i);
    4113          93 :       examine_dof_indices(dof_indices, i);
    4114             :     }
    4115             : 
    4116         652 :   if (resid_scaling)
    4117          50 :     _communicator.max(resid_inverse_scaling_factors);
    4118         652 :   if (jac_scaling)
    4119         602 :     _communicator.max(jac_inverse_scaling_factors);
    4120             : 
    4121         652 :   if (jac_scaling && resid_scaling)
    4122           0 :     for (MooseIndex(inverse_scaling_factors) i = 0; i < inverse_scaling_factors.size(); ++i)
    4123             :     {
    4124             :       // Be careful not to take log(0)
    4125           0 :       if (!resid_inverse_scaling_factors[i])
    4126             :       {
    4127           0 :         if (!jac_inverse_scaling_factors[i])
    4128           0 :           inverse_scaling_factors[i] = 1;
    4129             :         else
    4130           0 :           inverse_scaling_factors[i] = jac_inverse_scaling_factors[i];
    4131             :       }
    4132           0 :       else if (!jac_inverse_scaling_factors[i])
    4133             :         // We know the resid is not zero
    4134           0 :         inverse_scaling_factors[i] = resid_inverse_scaling_factors[i];
    4135             :       else
    4136           0 :         inverse_scaling_factors[i] =
    4137           0 :             std::exp(_resid_vs_jac_scaling_param * std::log(resid_inverse_scaling_factors[i]) +
    4138           0 :                      (1 - _resid_vs_jac_scaling_param) * std::log(jac_inverse_scaling_factors[i]));
    4139           0 :     }
    4140         652 :   else if (jac_scaling)
    4141         602 :     inverse_scaling_factors = jac_inverse_scaling_factors;
    4142          50 :   else if (resid_scaling)
    4143          50 :     inverse_scaling_factors = resid_inverse_scaling_factors;
    4144             :   else
    4145           0 :     mooseError("We shouldn't be calling this routine if we're not performing any scaling");
    4146             : 
    4147             :   // We have to make sure that our scaling values are not zero
    4148        1688 :   for (auto & scaling_factor : inverse_scaling_factors)
    4149        1036 :     if (scaling_factor == 0)
    4150          40 :       scaling_factor = 1;
    4151             : 
    4152             :   // Now flatten the group scaling factors to the individual variable scaling factors
    4153         652 :   std::vector<Real> flattened_inverse_scaling_factors(system().n_vars());
    4154        1712 :   for (const auto i : index_range(flattened_inverse_scaling_factors))
    4155        1060 :     flattened_inverse_scaling_factors[i] = inverse_scaling_factors[_var_to_group_var[i]];
    4156             : 
    4157             :   // Now set the scaling factors for the variables
    4158         652 :   applyScalingFactors(flattened_inverse_scaling_factors);
    4159         652 :   if (auto displaced_problem = _fe_problem.getDisplacedProblem().get())
    4160          63 :     displaced_problem->systemBaseNonlinear(number()).applyScalingFactors(
    4161             :         flattened_inverse_scaling_factors);
    4162             : 
    4163         652 :   _computed_scaling = true;
    4164         652 :   return true;
    4165         652 : }
    4166             : 
    4167             : void
    4168      318428 : NonlinearSystemBase::assembleScalingVector()
    4169             : {
    4170      955284 :   if (!hasVector("scaling_factors"))
    4171             :     // No variables have indicated they need scaling
    4172      317878 :     return;
    4173             : 
    4174        1100 :   auto & scaling_vector = getVector("scaling_factors");
    4175             : 
    4176         550 :   const auto & lm_mesh = _mesh.getMesh();
    4177         550 :   const auto & dof_map = dofMap();
    4178             : 
    4179         550 :   const auto & field_variables = _vars[0].fieldVariables();
    4180         550 :   const auto & scalar_variables = _vars[0].scalars();
    4181             : 
    4182         550 :   std::vector<dof_id_type> dof_indices;
    4183             : 
    4184         550 :   for (const Elem * const elem :
    4185       13672 :        as_range(lm_mesh.active_local_elements_begin(), lm_mesh.active_local_elements_end()))
    4186       31020 :     for (const auto * const field_var : field_variables)
    4187             :     {
    4188       18448 :       const auto & factors = field_var->arrayScalingFactor();
    4189       36896 :       for (const auto i : make_range(field_var->count()))
    4190             :       {
    4191       18448 :         dof_map.dof_indices(elem, dof_indices, field_var->number() + i);
    4192       76448 :         for (const auto dof : dof_indices)
    4193       58000 :           scaling_vector.set(dof, factors[i]);
    4194             :       }
    4195         550 :     }
    4196             : 
    4197         662 :   for (const auto * const scalar_var : scalar_variables)
    4198             :   {
    4199             :     mooseAssert(scalar_var->count() == 1,
    4200             :                 "Scalar variables should always have only one component.");
    4201         112 :     dof_map.SCALAR_dof_indices(dof_indices, scalar_var->number());
    4202         224 :     for (const auto dof : dof_indices)
    4203         112 :       scaling_vector.set(dof, scalar_var->scalingFactor());
    4204             :   }
    4205             : 
    4206             :   // Parallel assemble
    4207         550 :   scaling_vector.close();
    4208             : 
    4209         550 :   if (auto * displaced_problem = _fe_problem.getDisplacedProblem().get())
    4210             :     // copy into the corresponding displaced system vector because they should be the exact same
    4211           0 :     displaced_problem->systemBaseNonlinear(number()).getVector("scaling_factors") = scaling_vector;
    4212         550 : }
    4213             : 
    4214             : bool
    4215      317776 : NonlinearSystemBase::preSolve()
    4216             : {
    4217             :   // Clear the iteration counters
    4218      317776 :   _current_l_its.clear();
    4219      317776 :   _current_nl_its = 0;
    4220             : 
    4221             :   // Initialize the solution vector using a predictor and known values from nodal bcs
    4222      317776 :   setInitialSolution();
    4223             : 
    4224             :   // Now that the initial solution has ben set, potentially perform a residual/Jacobian evaluation
    4225             :   // to determine variable scaling factors
    4226      317776 :   if (_automatic_scaling)
    4227             :   {
    4228        1112 :     const bool scaling_succeeded = computeScaling();
    4229        1112 :     if (!scaling_succeeded)
    4230           0 :       return false;
    4231             :   }
    4232             : 
    4233             :   // We do not know a priori what variable a global degree of freedom corresponds to, so we need a
    4234             :   // map from global dof to scaling factor. We just use a ghosted NumericVector for that mapping
    4235      317776 :   assembleScalingVector();
    4236             : 
    4237      317776 :   return true;
    4238             : }
    4239             : 
    4240             : void
    4241        5612 : NonlinearSystemBase::destroyColoring()
    4242             : {
    4243        5612 :   if (matrixFromColoring())
    4244         117 :     LibmeshPetscCall(MatFDColoringDestroy(&_fdcoloring));
    4245        5612 : }
    4246             : 
    4247             : FieldSplitPreconditionerBase &
    4248           0 : NonlinearSystemBase::getFieldSplitPreconditioner()
    4249             : {
    4250           0 :   if (!_fsp)
    4251           0 :     mooseError("No field split preconditioner is present for this system");
    4252             : 
    4253           0 :   return *_fsp;
    4254             : }

Generated by: LCOV version 1.14