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

Generated by: LCOV version 1.14