LCOV - code coverage report
Current view: top level - src/systems - NonlinearSystemBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 1874 2106 89.0 %
Date: 2025-08-08 20:01:16 Functions: 82 97 84.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14