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

Generated by: LCOV version 1.14