LCOV - code coverage report
Current view: top level - src/systems - NonlinearSystemBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 1874 2106 89.0 %
Date: 2025-07-17 01:28:37 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       57095 : NonlinearSystemBase::NonlinearSystemBase(FEProblemBase & fe_problem,
     114             :                                          System & sys,
     115       57095 :                                          const std::string & name)
     116             :   : SolverSystem(fe_problem, fe_problem, name, Moose::VAR_SOLVER),
     117       57095 :     PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "NonlinearSystemBase"),
     118       57095 :     _sys(sys),
     119       57095 :     _last_nl_rnorm(0.),
     120       57095 :     _current_nl_its(0),
     121       57095 :     _residual_ghosted(NULL),
     122       57095 :     _Re_time_tag(-1),
     123       57095 :     _Re_time(NULL),
     124       57095 :     _Re_non_time_tag(-1),
     125       57095 :     _Re_non_time(NULL),
     126       57095 :     _scalar_kernels(/*threaded=*/false),
     127       57095 :     _nodal_bcs(/*threaded=*/false),
     128       57095 :     _preset_nodal_bcs(/*threaded=*/false),
     129       57095 :     _ad_preset_nodal_bcs(/*threaded=*/false),
     130       57095 :     _splits(/*threaded=*/false),
     131       57095 :     _increment_vec(NULL),
     132       57095 :     _use_finite_differenced_preconditioner(false),
     133       57095 :     _fdcoloring(nullptr),
     134       57095 :     _have_decomposition(false),
     135       57095 :     _use_field_split_preconditioner(false),
     136       57095 :     _add_implicit_geometric_coupling_entries_to_jacobian(false),
     137       57095 :     _assemble_constraints_separately(false),
     138       57095 :     _need_residual_ghosted(false),
     139       57095 :     _debugging_residuals(false),
     140       57095 :     _doing_dg(false),
     141       57095 :     _n_iters(0),
     142       57095 :     _n_linear_iters(0),
     143       57095 :     _n_residual_evaluations(0),
     144       57095 :     _final_residual(0.),
     145       57095 :     _computing_pre_smo_residual(false),
     146       57095 :     _pre_smo_residual(0),
     147       57095 :     _initial_residual(0),
     148       57095 :     _use_pre_smo_residual(false),
     149       57095 :     _print_all_var_norms(false),
     150       57095 :     _has_save_in(false),
     151       57095 :     _has_diag_save_in(false),
     152       57095 :     _has_nodalbc_save_in(false),
     153       57095 :     _has_nodalbc_diag_save_in(false),
     154       57095 :     _computed_scaling(false),
     155       57095 :     _compute_scaling_once(true),
     156       57095 :     _resid_vs_jac_scaling_param(0),
     157       57095 :     _off_diagonals_in_auto_scaling(false),
     158      285475 :     _auto_scaling_initd(false)
     159             : {
     160       57095 :   getResidualNonTimeVector();
     161             :   // Don't need to add the matrix - it already exists (for now)
     162       57095 :   _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       57095 :   _fe_problem.addMatrixTag("TIME");
     167             : 
     168       57095 :   _Re_tag = _fe_problem.addVectorTag("RESIDUAL");
     169             : 
     170       57095 :   _sys.identify_variable_groups(_fe_problem.identifyVariableGroupsInNL());
     171             : 
     172       57095 :   if (!_fe_problem.defaultGhosting())
     173             :   {
     174       57021 :     auto & dof_map = _sys.get_dof_map();
     175       57021 :     dof_map.remove_algebraic_ghosting_functor(dof_map.default_algebraic_ghosting());
     176       57021 :     dof_map.set_implicit_neighbor_dofs(false);
     177             :   }
     178       57095 : }
     179             : 
     180       52802 : NonlinearSystemBase::~NonlinearSystemBase() = default;
     181             : 
     182             : void
     183       55205 : NonlinearSystemBase::preInit()
     184             : {
     185       55205 :   SolverSystem::preInit();
     186             : 
     187       55205 :   if (_fe_problem.hasDampers())
     188         158 :     setupDampers();
     189             : 
     190       55205 :   if (_residual_copy.get())
     191           0 :     _residual_copy->init(_sys.n_dofs(), false, SERIAL);
     192       55205 : }
     193             : 
     194             : void
     195          71 : NonlinearSystemBase::turnOffJacobian()
     196             : {
     197          71 :   system().set_basic_system_only();
     198          71 :   nonlinearSolver()->jacobian = NULL;
     199          71 : }
     200             : 
     201             : void
     202       54322 : NonlinearSystemBase::initialSetup()
     203             : {
     204       54322 :   TIME_SECTION("nlInitialSetup", 2, "Setting Up Nonlinear System");
     205             : 
     206       54322 :   SolverSystem::initialSetup();
     207             : 
     208             :   {
     209       54322 :     TIME_SECTION("kernelsInitialSetup", 2, "Setting Up Kernels/BCs/Constraints");
     210             : 
     211      114099 :     for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     212             :     {
     213       59777 :       _kernels.initialSetup(tid);
     214       59777 :       _nodal_kernels.initialSetup(tid);
     215       59777 :       _dirac_kernels.initialSetup(tid);
     216       59777 :       if (_doing_dg)
     217        1125 :         _dg_kernels.initialSetup(tid);
     218       59777 :       _interface_kernels.initialSetup(tid);
     219             : 
     220       59777 :       _element_dampers.initialSetup(tid);
     221       59777 :       _nodal_dampers.initialSetup(tid);
     222       59777 :       _integrated_bcs.initialSetup(tid);
     223             : 
     224       59777 :       if (_fe_problem.haveFV())
     225             :       {
     226        4063 :         std::vector<FVElementalKernel *> fv_elemental_kernels;
     227        4063 :         _fe_problem.theWarehouse()
     228        8126 :             .query()
     229        4063 :             .template condition<AttribSystem>("FVElementalKernel")
     230        4063 :             .template condition<AttribThread>(tid)
     231        4063 :             .queryInto(fv_elemental_kernels);
     232             : 
     233        7864 :         for (auto * fv_kernel : fv_elemental_kernels)
     234        3801 :           fv_kernel->initialSetup();
     235             : 
     236        4063 :         std::vector<FVFluxKernel *> fv_flux_kernels;
     237        4063 :         _fe_problem.theWarehouse()
     238        8126 :             .query()
     239        4063 :             .template condition<AttribSystem>("FVFluxKernel")
     240        4063 :             .template condition<AttribThread>(tid)
     241        4063 :             .queryInto(fv_flux_kernels);
     242             : 
     243        9227 :         for (auto * fv_kernel : fv_flux_kernels)
     244        5164 :           fv_kernel->initialSetup();
     245        4063 :       }
     246             :     }
     247             : 
     248       54322 :     _scalar_kernels.initialSetup();
     249       54322 :     _constraints.initialSetup();
     250       54322 :     _general_dampers.initialSetup();
     251       54322 :     _nodal_bcs.initialSetup();
     252       54322 :   }
     253             : 
     254             :   {
     255       54322 :     TIME_SECTION("mortarSetup", 2, "Initializing Mortar Interfaces");
     256             : 
     257      114062 :     auto create_mortar_functors = [this](const bool displaced)
     258             :     {
     259             :       // go over mortar interfaces and construct functors
     260      108644 :       const auto & mortar_interfaces = _fe_problem.getMortarInterfaces(displaced);
     261      109577 :       for (const auto & mortar_interface : mortar_interfaces)
     262             :       {
     263         933 :         const auto primary_secondary_boundary_pair = mortar_interface.first;
     264         933 :         if (!_constraints.hasActiveMortarConstraints(primary_secondary_boundary_pair, displaced))
     265          36 :           continue;
     266             : 
     267         897 :         const auto & mortar_generation_object = mortar_interface.second;
     268             : 
     269             :         auto & mortar_constraints =
     270         897 :             _constraints.getActiveMortarConstraints(primary_secondary_boundary_pair, displaced);
     271             : 
     272             :         auto & subproblem = displaced
     273         184 :                                 ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
     274         989 :                                 : static_cast<SubProblem &>(_fe_problem);
     275             : 
     276         897 :         auto & mortar_functors =
     277             :             displaced ? _displaced_mortar_functors : _undisplaced_mortar_functors;
     278             : 
     279         897 :         mortar_functors.emplace(primary_secondary_boundary_pair,
     280        1794 :                                 ComputeMortarFunctor(mortar_constraints,
     281             :                                                      mortar_generation_object,
     282             :                                                      subproblem,
     283             :                                                      _fe_problem,
     284             :                                                      displaced,
     285         897 :                                                      subproblem.assembly(0, number())));
     286             :       }
     287      108644 :     };
     288             : 
     289       54322 :     create_mortar_functors(false);
     290       54322 :     create_mortar_functors(true);
     291       54322 :   }
     292             : 
     293       54322 :   if (_automatic_scaling)
     294             :   {
     295         437 :     if (_off_diagonals_in_auto_scaling)
     296          66 :       _scaling_matrix = std::make_unique<OffDiagonalScalingMatrix<Number>>(_communicator);
     297             :     else
     298         371 :       _scaling_matrix = std::make_unique<DiagonalMatrix<Number>>(_communicator);
     299             :   }
     300             : 
     301       54322 :   if (_preconditioner)
     302       13149 :     _preconditioner->initialSetup();
     303       54322 : }
     304             : 
     305             : void
     306      261380 : NonlinearSystemBase::timestepSetup()
     307             : {
     308      261380 :   SolverSystem::timestepSetup();
     309             : 
     310      548148 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     311             :   {
     312      286768 :     _kernels.timestepSetup(tid);
     313      286768 :     _nodal_kernels.timestepSetup(tid);
     314      286768 :     _dirac_kernels.timestepSetup(tid);
     315      286768 :     if (_doing_dg)
     316        1659 :       _dg_kernels.timestepSetup(tid);
     317      286768 :     _interface_kernels.timestepSetup(tid);
     318      286768 :     _element_dampers.timestepSetup(tid);
     319      286768 :     _nodal_dampers.timestepSetup(tid);
     320      286768 :     _integrated_bcs.timestepSetup(tid);
     321             : 
     322      286768 :     if (_fe_problem.haveFV())
     323             :     {
     324       16269 :       std::vector<FVFluxBC *> bcs;
     325       16269 :       _fe_problem.theWarehouse()
     326       32538 :           .query()
     327       16269 :           .template condition<AttribSystem>("FVFluxBC")
     328       16269 :           .template condition<AttribThread>(tid)
     329       16269 :           .queryInto(bcs);
     330             : 
     331       16269 :       std::vector<FVInterfaceKernel *> iks;
     332       16269 :       _fe_problem.theWarehouse()
     333       32538 :           .query()
     334       16269 :           .template condition<AttribSystem>("FVInterfaceKernel")
     335       16269 :           .template condition<AttribThread>(tid)
     336       16269 :           .queryInto(iks);
     337             : 
     338       16269 :       std::vector<FVFluxKernel *> kernels;
     339       16269 :       _fe_problem.theWarehouse()
     340       32538 :           .query()
     341       16269 :           .template condition<AttribSystem>("FVFluxKernel")
     342       16269 :           .template condition<AttribThread>(tid)
     343       16269 :           .queryInto(kernels);
     344             : 
     345       32374 :       for (auto * bc : bcs)
     346       16105 :         bc->timestepSetup();
     347       16646 :       for (auto * ik : iks)
     348         377 :         ik->timestepSetup();
     349       36247 :       for (auto * kernel : kernels)
     350       19978 :         kernel->timestepSetup();
     351       16269 :     }
     352             :   }
     353      261380 :   _scalar_kernels.timestepSetup();
     354      261380 :   _constraints.timestepSetup();
     355      261380 :   _general_dampers.timestepSetup();
     356      261380 :   _nodal_bcs.timestepSetup();
     357      261380 : }
     358             : 
     359             : void
     360     1754478 : NonlinearSystemBase::customSetup(const ExecFlagType & exec_type)
     361             : {
     362     1754478 :   SolverSystem::customSetup(exec_type);
     363             : 
     364     3680723 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     365             :   {
     366     1926245 :     _kernels.customSetup(exec_type, tid);
     367     1926245 :     _nodal_kernels.customSetup(exec_type, tid);
     368     1926245 :     _dirac_kernels.customSetup(exec_type, tid);
     369     1926245 :     if (_doing_dg)
     370       11345 :       _dg_kernels.customSetup(exec_type, tid);
     371     1926245 :     _interface_kernels.customSetup(exec_type, tid);
     372     1926245 :     _element_dampers.customSetup(exec_type, tid);
     373     1926245 :     _nodal_dampers.customSetup(exec_type, tid);
     374     1926245 :     _integrated_bcs.customSetup(exec_type, tid);
     375             : 
     376     1926245 :     if (_fe_problem.haveFV())
     377             :     {
     378      119476 :       std::vector<FVFluxBC *> bcs;
     379      119476 :       _fe_problem.theWarehouse()
     380      238952 :           .query()
     381      119476 :           .template condition<AttribSystem>("FVFluxBC")
     382      119476 :           .template condition<AttribThread>(tid)
     383      119476 :           .queryInto(bcs);
     384             : 
     385      119476 :       std::vector<FVInterfaceKernel *> iks;
     386      119476 :       _fe_problem.theWarehouse()
     387      238952 :           .query()
     388      119476 :           .template condition<AttribSystem>("FVInterfaceKernel")
     389      119476 :           .template condition<AttribThread>(tid)
     390      119476 :           .queryInto(iks);
     391             : 
     392      119476 :       std::vector<FVFluxKernel *> kernels;
     393      119476 :       _fe_problem.theWarehouse()
     394      238952 :           .query()
     395      119476 :           .template condition<AttribSystem>("FVFluxKernel")
     396      119476 :           .template condition<AttribThread>(tid)
     397      119476 :           .queryInto(kernels);
     398             : 
     399      217248 :       for (auto * bc : bcs)
     400       97772 :         bc->customSetup(exec_type);
     401      160363 :       for (auto * ik : iks)
     402       40887 :         ik->customSetup(exec_type);
     403      285734 :       for (auto * kernel : kernels)
     404      166258 :         kernel->customSetup(exec_type);
     405      119476 :     }
     406             :   }
     407     1754478 :   _scalar_kernels.customSetup(exec_type);
     408     1754478 :   _constraints.customSetup(exec_type);
     409     1754478 :   _general_dampers.customSetup(exec_type);
     410     1754478 :   _nodal_bcs.customSetup(exec_type);
     411     1754478 : }
     412             : 
     413             : void
     414      313418 : NonlinearSystemBase::setupDM()
     415             : {
     416      313418 :   if (haveFieldSplitPreconditioner())
     417          95 :     Moose::PetscSupport::petscSetupDM(*this, _decomposition_split);
     418      313418 : }
     419             : 
     420             : void
     421       56696 : 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       56696 :   if (splits.size() && splits.size() != 1)
     425           0 :     mooseError("Only a single top-level split is allowed in a Problem's decomposition.");
     426             : 
     427       56696 :   if (splits.size())
     428             :   {
     429         104 :     _decomposition_split = splits[0];
     430         104 :     _have_decomposition = true;
     431             :   }
     432             :   else
     433       56592 :     _have_decomposition = false;
     434       56696 : }
     435             : 
     436             : void
     437         104 : NonlinearSystemBase::setupFieldDecomposition()
     438             : {
     439         104 :   if (!_have_decomposition)
     440           0 :     return;
     441             : 
     442         104 :   std::shared_ptr<Split> top_split = getSplit(_decomposition_split);
     443         104 :   top_split->setup(*this);
     444         104 : }
     445             : 
     446             : void
     447       76015 : NonlinearSystemBase::addKernel(const std::string & kernel_name,
     448             :                                const std::string & name,
     449             :                                InputParameters & parameters)
     450             : {
     451      159357 :   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       83542 :         _factory.create<KernelBase>(kernel_name, name, parameters, tid);
     456       83366 :     _kernels.addObject(kernel, tid);
     457       83346 :     postAddResidualObject(*kernel);
     458             :     // Add to theWarehouse, a centralized storage for all moose objects
     459       83342 :     _fe_problem.theWarehouse().add(kernel);
     460       83342 :   }
     461             : 
     462       75815 :   if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     463         120 :     _has_save_in = true;
     464       75815 :   if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     465          96 :     _has_diag_save_in = true;
     466       75815 : }
     467             : 
     468             : void
     469         758 : NonlinearSystemBase::addHDGKernel(const std::string & kernel_name,
     470             :                                   const std::string & name,
     471             :                                   InputParameters & parameters)
     472             : {
     473        1521 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     474             :   {
     475             :     // Create the kernel object via the factory and add to warehouse
     476         763 :     auto kernel = _factory.create<HDGKernel>(kernel_name, name, parameters, tid);
     477         763 :     _kernels.addObject(kernel, tid);
     478         763 :     _hybridized_kernels.addObject(kernel, tid);
     479             :     // Add to theWarehouse, a centralized storage for all moose objects
     480         763 :     _fe_problem.theWarehouse().add(kernel);
     481         763 :     postAddResidualObject(*kernel);
     482         763 :   }
     483         758 : }
     484             : 
     485             : void
     486         540 : NonlinearSystemBase::addNodalKernel(const std::string & kernel_name,
     487             :                                     const std::string & name,
     488             :                                     InputParameters & parameters)
     489             : {
     490        1177 :   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         637 :         _factory.create<NodalKernelBase>(kernel_name, name, parameters, tid);
     495         637 :     _nodal_kernels.addObject(kernel, tid);
     496             :     // Add to theWarehouse, a centralized storage for all moose objects
     497         637 :     _fe_problem.theWarehouse().add(kernel);
     498         637 :     postAddResidualObject(*kernel);
     499         637 :   }
     500             : 
     501         540 :   if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     502           0 :     _has_save_in = true;
     503         540 :   if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     504           0 :     _has_diag_save_in = true;
     505         540 : }
     506             : 
     507             : void
     508        1420 : NonlinearSystemBase::addScalarKernel(const std::string & kernel_name,
     509             :                                      const std::string & name,
     510             :                                      InputParameters & parameters)
     511             : {
     512             :   std::shared_ptr<ScalarKernelBase> kernel =
     513        1420 :       _factory.create<ScalarKernelBase>(kernel_name, name, parameters);
     514        1412 :   postAddResidualObject(*kernel);
     515             :   // Add to theWarehouse, a centralized storage for all moose objects
     516        1412 :   _fe_problem.theWarehouse().add(kernel);
     517        1412 :   _scalar_kernels.addObject(kernel);
     518        1412 : }
     519             : 
     520             : void
     521       75594 : NonlinearSystemBase::addBoundaryCondition(const std::string & bc_name,
     522             :                                           const std::string & name,
     523             :                                           InputParameters & parameters)
     524             : {
     525             :   // ThreadID
     526       75594 :   THREAD_ID tid = 0;
     527             : 
     528             :   // Create the object
     529             :   std::shared_ptr<BoundaryCondition> bc =
     530       75594 :       _factory.create<BoundaryCondition>(bc_name, name, parameters, tid);
     531       75541 :   postAddResidualObject(*bc);
     532             : 
     533             :   // Active BoundaryIDs for the object
     534       75541 :   const std::set<BoundaryID> & boundary_ids = bc->boundaryIDs();
     535       75541 :   auto bc_var = dynamic_cast<const MooseVariableFieldBase *>(&bc->variable());
     536       75541 :   _vars[tid].addBoundaryVar(boundary_ids, bc_var);
     537             : 
     538             :   // Cast to the various types of BCs
     539       75541 :   std::shared_ptr<NodalBCBase> nbc = std::dynamic_pointer_cast<NodalBCBase>(bc);
     540       75541 :   std::shared_ptr<IntegratedBCBase> ibc = std::dynamic_pointer_cast<IntegratedBCBase>(bc);
     541             : 
     542             :   // NodalBCBase
     543       75541 :   if (nbc)
     544             :   {
     545       67229 :     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       67225 :     _nodal_bcs.addObject(nbc);
     553             :     // Add to theWarehouse, a centralized storage for all moose objects
     554       67225 :     _fe_problem.theWarehouse().add(nbc);
     555       67225 :     _vars[tid].addBoundaryVars(boundary_ids, nbc->getCoupledVars());
     556             : 
     557       67225 :     if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     558          92 :       _has_nodalbc_save_in = true;
     559       67225 :     if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     560          20 :       _has_nodalbc_diag_save_in = true;
     561             : 
     562             :     // DirichletBCs that are preset
     563       67225 :     std::shared_ptr<DirichletBCBase> dbc = std::dynamic_pointer_cast<DirichletBCBase>(bc);
     564       67225 :     if (dbc && dbc->preset())
     565       57688 :       _preset_nodal_bcs.addObject(dbc);
     566             : 
     567       67225 :     std::shared_ptr<ADDirichletBCBase> addbc = std::dynamic_pointer_cast<ADDirichletBCBase>(bc);
     568       67225 :     if (addbc && addbc->preset())
     569        1548 :       _ad_preset_nodal_bcs.addObject(addbc);
     570       67225 :   }
     571             : 
     572             :   // IntegratedBCBase
     573        8312 :   else if (ibc)
     574             :   {
     575        8312 :     _integrated_bcs.addObject(ibc, tid);
     576             :     // Add to theWarehouse, a centralized storage for all moose objects
     577        8312 :     _fe_problem.theWarehouse().add(ibc);
     578        8312 :     _vars[tid].addBoundaryVars(boundary_ids, ibc->getCoupledVars());
     579             : 
     580        8312 :     if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     581          80 :       _has_save_in = true;
     582        8312 :     if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     583          56 :       _has_diag_save_in = true;
     584             : 
     585        8969 :     for (tid = 1; tid < libMesh::n_threads(); tid++)
     586             :     {
     587             :       // Create the object
     588         657 :       bc = _factory.create<BoundaryCondition>(bc_name, name, parameters, tid);
     589             : 
     590             :       // Give users opportunity to set some parameters
     591         657 :       postAddResidualObject(*bc);
     592             : 
     593             :       // Active BoundaryIDs for the object
     594         657 :       const std::set<BoundaryID> & boundary_ids = bc->boundaryIDs();
     595         657 :       _vars[tid].addBoundaryVar(boundary_ids, bc_var);
     596             : 
     597         657 :       ibc = std::static_pointer_cast<IntegratedBCBase>(bc);
     598             : 
     599         657 :       _integrated_bcs.addObject(ibc, tid);
     600         657 :       _vars[tid].addBoundaryVars(boundary_ids, ibc->getCoupledVars());
     601             :     }
     602             :   }
     603             : 
     604             :   else
     605           0 :     mooseError("Unknown BoundaryCondition type for object named ", bc->name());
     606       75537 : }
     607             : 
     608             : void
     609        1587 : NonlinearSystemBase::addConstraint(const std::string & c_name,
     610             :                                    const std::string & name,
     611             :                                    InputParameters & parameters)
     612             : {
     613        1587 :   std::shared_ptr<Constraint> constraint = _factory.create<Constraint>(c_name, name, parameters);
     614        1579 :   _constraints.addObject(constraint);
     615        1579 :   postAddResidualObject(*constraint);
     616             : 
     617        1579 :   if (constraint && constraint->addCouplingEntriesToJacobian())
     618        1567 :     addImplicitGeometricCouplingEntriesToJacobian(true);
     619        1579 : }
     620             : 
     621             : void
     622         866 : NonlinearSystemBase::addDiracKernel(const std::string & kernel_name,
     623             :                                     const std::string & name,
     624             :                                     InputParameters & parameters)
     625             : {
     626        1808 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     627             :   {
     628             :     std::shared_ptr<DiracKernelBase> kernel =
     629         950 :         _factory.create<DiracKernelBase>(kernel_name, name, parameters, tid);
     630         942 :     postAddResidualObject(*kernel);
     631         942 :     _dirac_kernels.addObject(kernel, tid);
     632             :     // Add to theWarehouse, a centralized storage for all moose objects
     633         942 :     _fe_problem.theWarehouse().add(kernel);
     634         942 :   }
     635         858 : }
     636             : 
     637             : void
     638        1314 : NonlinearSystemBase::addDGKernel(std::string dg_kernel_name,
     639             :                                  const std::string & name,
     640             :                                  InputParameters & parameters)
     641             : {
     642        2747 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
     643             :   {
     644        1433 :     auto dg_kernel = _factory.create<DGKernelBase>(dg_kernel_name, name, parameters, tid);
     645        1433 :     _dg_kernels.addObject(dg_kernel, tid);
     646             :     // Add to theWarehouse, a centralized storage for all moose objects
     647        1433 :     _fe_problem.theWarehouse().add(dg_kernel);
     648        1433 :     postAddResidualObject(*dg_kernel);
     649        1433 :   }
     650             : 
     651        1314 :   _doing_dg = true;
     652             : 
     653        1314 :   if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
     654          48 :     _has_save_in = true;
     655        1314 :   if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
     656          36 :     _has_diag_save_in = true;
     657        1314 : }
     658             : 
     659             : void
     660         856 : NonlinearSystemBase::addInterfaceKernel(std::string interface_kernel_name,
     661             :                                         const std::string & name,
     662             :                                         InputParameters & parameters)
     663             : {
     664        1787 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
     665             :   {
     666             :     std::shared_ptr<InterfaceKernelBase> interface_kernel =
     667         931 :         _factory.create<InterfaceKernelBase>(interface_kernel_name, name, parameters, tid);
     668         931 :     postAddResidualObject(*interface_kernel);
     669             : 
     670         931 :     const std::set<BoundaryID> & boundary_ids = interface_kernel->boundaryIDs();
     671         931 :     auto ik_var = dynamic_cast<const MooseVariableFieldBase *>(&interface_kernel->variable());
     672         931 :     _vars[tid].addBoundaryVar(boundary_ids, ik_var);
     673             : 
     674         931 :     _interface_kernels.addObject(interface_kernel, tid);
     675             :     // Add to theWarehouse, a centralized storage for all moose objects
     676         931 :     _fe_problem.theWarehouse().add(interface_kernel);
     677         931 :     _vars[tid].addBoundaryVars(boundary_ids, interface_kernel->getCoupledVars());
     678         931 :   }
     679         856 : }
     680             : 
     681             : void
     682         176 : NonlinearSystemBase::addDamper(const std::string & damper_name,
     683             :                                const std::string & name,
     684             :                                InputParameters & parameters)
     685             : {
     686         327 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
     687             :   {
     688         217 :     std::shared_ptr<Damper> damper = _factory.create<Damper>(damper_name, name, parameters, tid);
     689             : 
     690             :     // Attempt to cast to the damper types
     691         217 :     std::shared_ptr<ElementDamper> ed = std::dynamic_pointer_cast<ElementDamper>(damper);
     692         217 :     std::shared_ptr<NodalDamper> nd = std::dynamic_pointer_cast<NodalDamper>(damper);
     693         217 :     std::shared_ptr<GeneralDamper> gd = std::dynamic_pointer_cast<GeneralDamper>(damper);
     694             : 
     695         217 :     if (gd)
     696             :     {
     697          66 :       _general_dampers.addObject(gd);
     698          66 :       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         415 :   }
     707         176 : }
     708             : 
     709             : void
     710         376 : NonlinearSystemBase::addSplit(const std::string & split_name,
     711             :                               const std::string & name,
     712             :                               InputParameters & parameters)
     713             : {
     714         376 :   std::shared_ptr<Split> split = _factory.create<Split>(split_name, name, parameters);
     715         376 :   _splits.addObject(split);
     716             :   // Add to theWarehouse, a centralized storage for all moose objects
     717         376 :   _fe_problem.theWarehouse().add(split);
     718         376 : }
     719             : 
     720             : std::shared_ptr<Split>
     721         376 : NonlinearSystemBase::getSplit(const std::string & name)
     722             : {
     723         376 :   return _splits.getActiveObject(name);
     724             : }
     725             : 
     726             : bool
     727      285388 : NonlinearSystemBase::shouldEvaluatePreSMOResidual() const
     728             : {
     729      285388 :   if (_fe_problem.solverParams(number())._type == Moose::ST_LINEAR)
     730        9971 :     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      275417 :   if (_app.parameters().get<bool>("use_legacy_initial_residual_evaluation_behavior"))
     739           0 :     return true;
     740             : 
     741      275417 :   return _use_pre_smo_residual;
     742             : }
     743             : 
     744             : Real
     745      354122 : NonlinearSystemBase::referenceResidual() const
     746             : {
     747      354122 :   return usePreSMOResidual() ? preSMOResidual() : initialResidual();
     748             : }
     749             : 
     750             : Real
     751         152 : NonlinearSystemBase::preSMOResidual() const
     752             : {
     753         152 :   if (!shouldEvaluatePreSMOResidual())
     754           0 :     mooseError("pre-SMO residual is requested but not evaluated.");
     755             : 
     756         152 :   return _pre_smo_residual;
     757             : }
     758             : 
     759             : Real
     760      354234 : NonlinearSystemBase::initialResidual() const
     761             : {
     762      354234 :   return _initial_residual;
     763             : }
     764             : 
     765             : void
     766      282707 : NonlinearSystemBase::setInitialResidual(Real r)
     767             : {
     768      282707 :   _initial_residual = r;
     769      282707 : }
     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         124 : NonlinearSystemBase::computeResidualTag(NumericVector<Number> & residual, TagID tag_id)
     783             : {
     784         124 :   _nl_vector_tags.clear();
     785         124 :   _nl_vector_tags.insert(tag_id);
     786         124 :   _nl_vector_tags.insert(residualVectorTag());
     787             : 
     788         124 :   associateVectorToTag(residual, residualVectorTag());
     789             : 
     790         124 :   computeResidualTags(_nl_vector_tags);
     791             : 
     792         124 :   disassociateVectorFromTag(residual, residualVectorTag());
     793         124 : }
     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     3040556 : NonlinearSystemBase::computeResidualTags(const std::set<TagID> & tags)
     805             : {
     806             :   parallel_object_only();
     807             : 
     808     3040556 :   TIME_SECTION("nl::computeResidualTags", 5);
     809             : 
     810     3040556 :   _fe_problem.setCurrentNonlinearSystem(number());
     811     3040556 :   _fe_problem.setCurrentlyComputingResidual(true);
     812             : 
     813     3040556 :   bool required_residual = tags.find(residualVectorTag()) == tags.end() ? false : true;
     814             : 
     815     3040556 :   _n_residual_evaluations++;
     816             : 
     817             :   // not suppose to do anythin on matrix
     818     3040556 :   deactiveAllMatrixTags();
     819             : 
     820     3040556 :   FloatingPointExceptionGuard fpe_guard(_app);
     821             : 
     822     3040556 :   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     3040556 :     zeroTaggedVectors(tags);
     833     3040556 :     computeResidualInternal(tags);
     834     3040397 :     closeTaggedVectors(tags);
     835             : 
     836     3040397 :     if (required_residual)
     837             :     {
     838     3009988 :       auto & residual = getVector(residualVectorTag());
     839     3009988 :       if (!_time_integrators.empty())
     840             :       {
     841     5277986 :         for (auto & ti : _time_integrators)
     842     2647412 :           ti->postResidual(residual);
     843             :       }
     844             :       else
     845      379414 :         residual += *_Re_non_time;
     846     3009988 :       residual.close();
     847             :     }
     848     3040397 :     if (_fe_problem.computingScalingResidual())
     849             :       // We don't want to do nodal bcs or anything else
     850          50 :       return;
     851             : 
     852     3040347 :     computeNodalBCs(tags);
     853     3040347 :     closeTaggedVectors(tags);
     854             : 
     855             :     // If we are debugging residuals we need one more assignment to have the ghosted copy up to
     856             :     // date
     857     3040347 :     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     3040347 :     if (_has_nodalbc_save_in)
     866         157 :       _fe_problem.getAuxiliarySystem().solution().close();
     867     3040347 :     if (hasSaveIn())
     868         284 :       _fe_problem.getAuxiliarySystem().update();
     869             :   }
     870         117 :   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         117 :   }
     876             : 
     877             :   // not supposed to do anything on matrix
     878     3040464 :   activeAllMatrixTags();
     879             : 
     880     3040464 :   _fe_problem.setCurrentlyComputingResidual(false);
     881     3040564 : }
     882             : 
     883             : void
     884        3345 : NonlinearSystemBase::computeResidualAndJacobianTags(const std::set<TagID> & vector_tags,
     885             :                                                     const std::set<TagID> & matrix_tags)
     886             : {
     887             :   const bool required_residual =
     888        3345 :       vector_tags.find(residualVectorTag()) == vector_tags.end() ? false : true;
     889             : 
     890             :   try
     891             :   {
     892        3345 :     zeroTaggedVectors(vector_tags);
     893        3345 :     computeResidualAndJacobianInternal(vector_tags, matrix_tags);
     894        3345 :     closeTaggedVectors(vector_tags);
     895        3345 :     closeTaggedMatrices(matrix_tags);
     896             : 
     897        3345 :     if (required_residual)
     898             :     {
     899        3345 :       auto & residual = getVector(residualVectorTag());
     900        3345 :       if (!_time_integrators.empty())
     901             :       {
     902        3668 :         for (auto & ti : _time_integrators)
     903        1834 :           ti->postResidual(residual);
     904             :       }
     905             :       else
     906        1511 :         residual += *_Re_non_time;
     907        3345 :       residual.close();
     908             :     }
     909             : 
     910        3345 :     computeNodalBCsResidualAndJacobian();
     911        3345 :     closeTaggedVectors(vector_tags);
     912        3345 :     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        3345 : }
     921             : 
     922             : void
     923      235067 : NonlinearSystemBase::onTimestepBegin()
     924             : {
     925      470848 :   for (auto & ti : _time_integrators)
     926      235781 :     ti->preSolve();
     927      235067 :   if (_predictor.get())
     928         371 :     _predictor->timestepSetup();
     929      235067 : }
     930             : 
     931             : void
     932      286469 : NonlinearSystemBase::setInitialSolution()
     933             : {
     934      286469 :   deactiveAllMatrixTags();
     935             : 
     936      286469 :   NumericVector<Number> & initial_solution(solution());
     937      286469 :   if (_predictor.get())
     938             :   {
     939         371 :     if (_predictor->shouldApply())
     940             :     {
     941         219 :       TIME_SECTION("applyPredictor", 2, "Applying Predictor");
     942             : 
     943         219 :       _predictor->apply(initial_solution);
     944         219 :       _fe_problem.predictorCleanup(initial_solution);
     945         219 :     }
     946             :     else
     947         152 :       _console << " Skipping predictor this step" << std::endl;
     948             :   }
     949             : 
     950             :   // do nodal BC
     951             :   {
     952      286469 :     TIME_SECTION("initialBCs", 2, "Applying BCs To Initial Condition");
     953             : 
     954      286469 :     const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
     955    14015886 :     for (const auto & bnode : bnd_nodes)
     956             :     {
     957    13729417 :       BoundaryID boundary_id = bnode->_bnd_id;
     958    13729417 :       Node * node = bnode->_node;
     959             : 
     960    13729417 :       if (node->processor_id() == processor_id())
     961             :       {
     962             :         // reinit variables in nodes
     963    10271361 :         _fe_problem.reinitNodeFace(node, boundary_id, 0);
     964             : 
     965    10271361 :         if (_preset_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
     966             :         {
     967     3260118 :           const auto & preset_bcs = _preset_nodal_bcs.getActiveBoundaryObjects(boundary_id);
     968     7099617 :           for (const auto & preset_bc : preset_bcs)
     969     3839499 :             preset_bc->computeValue(initial_solution);
     970             :         }
     971    10271361 :         if (_ad_preset_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
     972             :         {
     973       32609 :           const auto & preset_bcs_res = _ad_preset_nodal_bcs.getActiveBoundaryObjects(boundary_id);
     974       68593 :           for (const auto & preset_bc : preset_bcs_res)
     975       35984 :             preset_bc->computeValue(initial_solution);
     976             :         }
     977             :       }
     978             :     }
     979      286469 :   }
     980             : 
     981      286469 :   _sys.solution->close();
     982      286469 :   update();
     983             : 
     984             :   // Set constraint secondary values
     985      286469 :   setConstraintSecondaryValues(initial_solution, false);
     986             : 
     987      286469 :   if (_fe_problem.getDisplacedProblem())
     988       32620 :     setConstraintSecondaryValues(initial_solution, true);
     989      286469 : }
     990             : 
     991             : void
     992         116 : NonlinearSystemBase::setPredictor(std::shared_ptr<Predictor> predictor)
     993             : {
     994         116 :   _predictor = predictor;
     995         116 : }
     996             : 
     997             : void
     998     5540300 : NonlinearSystemBase::subdomainSetup(SubdomainID subdomain, THREAD_ID tid)
     999             : {
    1000     5540300 :   SolverSystem::subdomainSetup();
    1001             : 
    1002     5540300 :   _kernels.subdomainSetup(subdomain, tid);
    1003     5540300 :   _nodal_kernels.subdomainSetup(subdomain, tid);
    1004     5540300 :   _element_dampers.subdomainSetup(subdomain, tid);
    1005     5540300 :   _nodal_dampers.subdomainSetup(subdomain, tid);
    1006     5540300 : }
    1007             : 
    1008             : NumericVector<Number> &
    1009       28513 : NonlinearSystemBase::getResidualTimeVector()
    1010             : {
    1011       28513 :   if (!_Re_time)
    1012             :   {
    1013       28411 :     _Re_time_tag = _fe_problem.addVectorTag("TIME");
    1014             : 
    1015             :     // Most applications don't need the expense of ghosting
    1016       28411 :     ParallelType ptype = _need_residual_ghosted ? GHOSTED : PARALLEL;
    1017       28411 :     _Re_time = &addVector(_Re_time_tag, false, ptype);
    1018             :   }
    1019         102 :   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       28513 :   return *_Re_time;
    1029             : }
    1030             : 
    1031             : NumericVector<Number> &
    1032       85795 : NonlinearSystemBase::getResidualNonTimeVector()
    1033             : {
    1034       85795 :   if (!_Re_non_time)
    1035             :   {
    1036       57095 :     _Re_non_time_tag = _fe_problem.addVectorTag("NONTIME");
    1037             : 
    1038             :     // Most applications don't need the expense of ghosting
    1039       57095 :     ParallelType ptype = _need_residual_ghosted ? GHOSTED : PARALLEL;
    1040       57095 :     _Re_non_time = &addVector(_Re_non_time_tag, false, ptype);
    1041             :   }
    1042       28700 :   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       85795 :   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       21781 : NonlinearSystemBase::enforceNodalConstraintsResidual(NumericVector<Number> & residual)
    1073             : {
    1074       21781 :   THREAD_ID tid = 0; // constraints are going to be done single-threaded
    1075       21781 :   residual.close();
    1076       21781 :   if (_constraints.hasActiveNodalConstraints())
    1077             :   {
    1078         547 :     const auto & ncs = _constraints.getActiveNodalConstraints();
    1079        1094 :     for (const auto & nc : ncs)
    1080             :     {
    1081         547 :       std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
    1082         547 :       std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
    1083             : 
    1084         547 :       if ((secondary_node_ids.size() > 0) && (primary_node_ids.size() > 0))
    1085             :       {
    1086         547 :         _fe_problem.reinitNodes(primary_node_ids, tid);
    1087         547 :         _fe_problem.reinitNodesNeighbor(secondary_node_ids, tid);
    1088         547 :         nc->computeResidual(residual);
    1089             :       }
    1090             :     }
    1091         547 :     _fe_problem.addCachedResidualDirectly(residual, tid);
    1092         547 :     residual.close();
    1093             :   }
    1094       21781 : }
    1095             : 
    1096             : void
    1097        3318 : NonlinearSystemBase::enforceNodalConstraintsJacobian()
    1098             : {
    1099        3318 :   if (!hasMatrix(systemMatrixTag()))
    1100           0 :     mooseError(" A system matrix is required");
    1101             : 
    1102        3318 :   auto & jacobian = getMatrix(systemMatrixTag());
    1103        3318 :   THREAD_ID tid = 0; // constraints are going to be done single-threaded
    1104             : 
    1105        3318 :   if (_constraints.hasActiveNodalConstraints())
    1106             :   {
    1107         108 :     const auto & ncs = _constraints.getActiveNodalConstraints();
    1108         216 :     for (const auto & nc : ncs)
    1109             :     {
    1110         108 :       std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
    1111         108 :       std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
    1112             : 
    1113         108 :       if ((secondary_node_ids.size() > 0) && (primary_node_ids.size() > 0))
    1114             :       {
    1115         108 :         _fe_problem.reinitNodes(primary_node_ids, tid);
    1116         108 :         _fe_problem.reinitNodesNeighbor(secondary_node_ids, tid);
    1117         108 :         nc->computeJacobian(jacobian);
    1118             :       }
    1119             :     }
    1120         108 :     _fe_problem.addCachedJacobian(tid);
    1121             :   }
    1122        3318 : }
    1123             : 
    1124             : void
    1125       96052 : NonlinearSystemBase::reinitNodeFace(const Node & secondary_node,
    1126             :                                     const BoundaryID secondary_boundary,
    1127             :                                     const PenetrationInfo & info,
    1128             :                                     const bool displaced)
    1129             : {
    1130      102528 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1131      147316 :                                 : static_cast<SubProblem &>(_fe_problem);
    1132             : 
    1133       96052 :   const Elem * primary_elem = info._elem;
    1134       96052 :   unsigned int primary_side = info._side_num;
    1135       96052 :   std::vector<Point> points;
    1136       96052 :   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       96052 :   _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       96052 :   _fe_problem.prepareAssembly(0);
    1150             : 
    1151       96052 :   _fe_problem.setNeighborSubdomainID(primary_elem, 0);
    1152             : 
    1153             :   //
    1154             :   // Reinit material on undisplaced mesh
    1155             :   //
    1156             : 
    1157             :   const Elem * const undisplaced_primary_elem =
    1158       96052 :       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       96052 :     if (displaced)
    1163             :     {
    1164             :       const Point reference_point =
    1165       51264 :           FEMap::inverse_map(primary_elem->dim(), primary_elem, points[0]);
    1166       51264 :       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       44788 :       return points[0];
    1172       96052 :   }();
    1173             : 
    1174       96052 :   _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       96052 :   _fe_problem.reinitMaterialsNeighbor(primary_elem->subdomain_id(), 0, /*swap_stateful=*/false);
    1180             : 
    1181             :   // Reinit points for constraint enforcement
    1182       96052 :   if (displaced)
    1183       51264 :     subproblem.reinitNeighborPhys(primary_elem, primary_side, points, 0);
    1184       96052 : }
    1185             : 
    1186             : void
    1187      319089 : 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       65240 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1195      351709 :                                 : static_cast<SubProblem &>(_fe_problem);
    1196      319089 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    1197             : 
    1198      319089 :   bool constraints_applied = false;
    1199             : 
    1200      374164 :   for (const auto & it : penetration_locators)
    1201             :   {
    1202       55075 :     PenetrationLocator & pen_loc = *(it.second);
    1203             : 
    1204       55075 :     std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    1205             : 
    1206       55075 :     BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    1207       55075 :     BoundaryID primary_boundary = pen_loc._primary_boundary;
    1208             : 
    1209       55075 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
    1210             :     {
    1211             :       const auto & constraints =
    1212        2725 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
    1213        2725 :       std::unordered_set<unsigned int> needed_mat_props;
    1214        5450 :       for (const auto & constraint : constraints)
    1215             :       {
    1216        2725 :         const auto & mp_deps = constraint->getMatPropDependencies();
    1217        2725 :         needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
    1218             :       }
    1219        2725 :       _fe_problem.setActiveMaterialProperties(needed_mat_props, /*tid=*/0);
    1220             : 
    1221       38424 :       for (unsigned int i = 0; i < secondary_nodes.size(); i++)
    1222             :       {
    1223       35699 :         dof_id_type secondary_node_num = secondary_nodes[i];
    1224       35699 :         Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    1225             : 
    1226       35699 :         if (secondary_node.processor_id() == processor_id())
    1227             :         {
    1228       27480 :           if (pen_loc._penetration_info[secondary_node_num])
    1229             :           {
    1230       27480 :             PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
    1231             : 
    1232       27480 :             reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
    1233             : 
    1234       54960 :             for (const auto & nfc : constraints)
    1235             :             {
    1236       27480 :               if (nfc->isExplicitConstraint())
    1237       25600 :                 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        3760 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    1243        1880 :                   nfc->primaryBoundary() != primary_boundary)
    1244           0 :                 continue;
    1245             : 
    1246        1880 :               if (nfc->shouldApply())
    1247             :               {
    1248        1880 :                 constraints_applied = true;
    1249        1880 :                 nfc->computeSecondaryValue(solution);
    1250             :               }
    1251             : 
    1252        1880 :               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        2725 :     }
    1266             :   }
    1267             : 
    1268             :   // go over NodeELemConstraints
    1269      319089 :   std::set<dof_id_type> unique_secondary_node_ids;
    1270             : 
    1271      715651 :   for (const auto & secondary_id : _mesh.meshSubdomains())
    1272             :   {
    1273     1065036 :     for (const auto & primary_id : _mesh.meshSubdomains())
    1274             :     {
    1275      668474 :       if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
    1276             :       {
    1277             :         const auto & constraints =
    1278         162 :             _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
    1279             : 
    1280             :         // get unique set of ids of all nodes on current block
    1281         162 :         unique_secondary_node_ids.clear();
    1282         162 :         const MeshBase & meshhelper = _mesh.getMesh();
    1283         324 :         for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
    1284       15606 :                                           meshhelper.active_subdomain_elements_end(secondary_id)))
    1285             :         {
    1286       44226 :           for (auto & n : elem->node_ref_range())
    1287       36666 :             unique_secondary_node_ids.insert(n.id());
    1288         162 :         }
    1289             : 
    1290       12636 :         for (auto secondary_node_id : unique_secondary_node_ids)
    1291             :         {
    1292       12474 :           Node & secondary_node = _mesh.nodeRef(secondary_node_id);
    1293             : 
    1294             :           // check if secondary node is on current processor
    1295       12474 :           if (secondary_node.processor_id() == processor_id())
    1296             :           {
    1297             :             // This reinits the variables that exist on the secondary node
    1298        9702 :             _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        9702 :             _fe_problem.prepareAssembly(0);
    1303             : 
    1304       20636 :             for (const auto & nec : constraints)
    1305             :             {
    1306       10934 :               if (nec->shouldApply())
    1307             :               {
    1308        4970 :                 constraints_applied = true;
    1309        4970 :                 nec->computeSecondaryValue(solution);
    1310             :               }
    1311             :             }
    1312             :           }
    1313             :         }
    1314             :       }
    1315             :     }
    1316             :   }
    1317             : 
    1318             :   // See if constraints were applied anywhere
    1319      319089 :   _communicator.max(constraints_applied);
    1320             : 
    1321      319089 :   if (constraints_applied)
    1322             :   {
    1323         654 :     solution.close();
    1324         654 :     update();
    1325             :   }
    1326      319089 : }
    1327             : 
    1328             : void
    1329       26262 : NonlinearSystemBase::constraintResiduals(NumericVector<Number> & residual, bool displaced)
    1330             : {
    1331             :   // Make sure the residual is in a good state
    1332       26262 :   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        8962 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1339       30743 :                                 : static_cast<SubProblem &>(_fe_problem);
    1340       26262 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    1341             : 
    1342             :   bool constraints_applied;
    1343       26262 :   bool residual_has_inserted_values = false;
    1344       26262 :   if (!_assemble_constraints_separately)
    1345       26262 :     constraints_applied = false;
    1346       48317 :   for (const auto & it : penetration_locators)
    1347             :   {
    1348       22055 :     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       22055 :     PenetrationLocator & pen_loc = *(it.second);
    1355             : 
    1356       22055 :     std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    1357             : 
    1358       22055 :     BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    1359       22055 :     BoundaryID primary_boundary = pen_loc._primary_boundary;
    1360             : 
    1361       22055 :     bool has_writable_variables(false);
    1362             : 
    1363       22055 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
    1364             :     {
    1365             :       const auto & constraints =
    1366       12822 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
    1367             : 
    1368       90570 :       for (unsigned int i = 0; i < secondary_nodes.size(); i++)
    1369             :       {
    1370       77748 :         dof_id_type secondary_node_num = secondary_nodes[i];
    1371       77748 :         Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    1372             : 
    1373       77748 :         if (secondary_node.processor_id() == processor_id())
    1374             :         {
    1375       64876 :           if (pen_loc._penetration_info[secondary_node_num])
    1376             :           {
    1377       64876 :             PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
    1378             : 
    1379       64876 :             reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
    1380             : 
    1381      129752 :             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      129752 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    1388       64876 :                   nfc->primaryBoundary() != primary_boundary)
    1389           0 :                 continue;
    1390             : 
    1391       64876 :               if (nfc->shouldApply())
    1392             :               {
    1393       39276 :                 constraints_applied = true;
    1394       39276 :                 nfc->computeResidual();
    1395             : 
    1396       39276 :                 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       39276 :                   const auto & secondary_var = nfc->variable();
    1403       39276 :                   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       39276 :                   std::vector<Number> values = {nfc->secondaryResidual()};
    1414       39276 :                   residual.insert(values, secondary_dofs);
    1415       39276 :                   residual_has_inserted_values = true;
    1416       39276 :                 }
    1417             :                 else
    1418           0 :                   _fe_problem.cacheResidual(0);
    1419       39276 :                 _fe_problem.cacheResidualNeighbor(0);
    1420             :               }
    1421       64876 :               if (nfc->hasWritableCoupledVariables())
    1422             :               {
    1423       25600 :                 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1424       25600 :                 has_writable_variables = true;
    1425       51200 :                 for (auto * var : nfc->getWritableCoupledVariables())
    1426             :                 {
    1427       25600 :                   if (var->isNodalDefined())
    1428       25600 :                     var->insert(_fe_problem.getAuxiliarySystem().solution());
    1429             :                 }
    1430       25600 :               }
    1431             :             }
    1432             :           }
    1433             :         }
    1434             :       }
    1435             :     }
    1436       22055 :     _communicator.max(has_writable_variables);
    1437             : 
    1438       22055 :     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        2200 :       _fe_problem.getAuxiliarySystem().solution().close();
    1444        2200 :       _fe_problem.getAuxiliarySystem().system().update();
    1445        2200 :       solutionOld().close();
    1446             :     }
    1447             : 
    1448       22055 :     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       26262 :   if (!_assemble_constraints_separately)
    1475             :   {
    1476       26262 :     _communicator.max(constraints_applied);
    1477             : 
    1478       26262 :     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        9956 :       _communicator.max(residual_has_inserted_values);
    1483        9956 :       if (residual_has_inserted_values)
    1484        9956 :         residual.close();
    1485             : 
    1486        9956 :       _fe_problem.addCachedResidualDirectly(residual, 0);
    1487        9956 :       residual.close();
    1488             : 
    1489        9956 :       if (_need_residual_ghosted)
    1490        9956 :         *_residual_ghosted = residual;
    1491             :     }
    1492             :   }
    1493             : 
    1494             :   // go over element-element constraint interface
    1495       26262 :   THREAD_ID tid = 0;
    1496       26262 :   const auto & element_pair_locators = subproblem.geomSearchData()._element_pair_locators;
    1497       26262 :   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       26262 :   std::set<dof_id_type> unique_secondary_node_ids;
    1543             : 
    1544       26262 :   constraints_applied = false;
    1545       26262 :   residual_has_inserted_values = false;
    1546       26262 :   bool has_writable_variables = false;
    1547       90553 :   for (const auto & secondary_id : _mesh.meshSubdomains())
    1548             :   {
    1549      273978 :     for (const auto & primary_id : _mesh.meshSubdomains())
    1550             :     {
    1551      209687 :       if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
    1552             :       {
    1553             :         const auto & constraints =
    1554         324 :             _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
    1555             : 
    1556             :         // get unique set of ids of all nodes on current block
    1557         324 :         unique_secondary_node_ids.clear();
    1558         324 :         const MeshBase & meshhelper = _mesh.getMesh();
    1559         648 :         for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
    1560       31212 :                                           meshhelper.active_subdomain_elements_end(secondary_id)))
    1561             :         {
    1562       88452 :           for (auto & n : elem->node_ref_range())
    1563       73332 :             unique_secondary_node_ids.insert(n.id());
    1564         324 :         }
    1565             : 
    1566       25272 :         for (auto secondary_node_id : unique_secondary_node_ids)
    1567             :         {
    1568       24948 :           Node & secondary_node = _mesh.nodeRef(secondary_node_id);
    1569             :           // check if secondary node is on current processor
    1570       24948 :           if (secondary_node.processor_id() == processor_id())
    1571             :           {
    1572             :             // This reinits the variables that exist on the secondary node
    1573       19404 :             _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       19404 :             _fe_problem.prepareAssembly(0);
    1578             : 
    1579       41272 :             for (const auto & nec : constraints)
    1580             :             {
    1581       21868 :               if (nec->shouldApply())
    1582             :               {
    1583        9940 :                 constraints_applied = true;
    1584        9940 :                 nec->computeResidual();
    1585             : 
    1586        9940 :                 if (nec->overwriteSecondaryResidual())
    1587             :                 {
    1588           0 :                   _fe_problem.setResidual(residual, 0);
    1589           0 :                   residual_has_inserted_values = true;
    1590             :                 }
    1591             :                 else
    1592        9940 :                   _fe_problem.cacheResidual(0);
    1593        9940 :                 _fe_problem.cacheResidualNeighbor(0);
    1594             :               }
    1595       21868 :               if (nec->hasWritableCoupledVariables())
    1596             :               {
    1597         308 :                 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1598         308 :                 has_writable_variables = true;
    1599         616 :                 for (auto * var : nec->getWritableCoupledVariables())
    1600             :                 {
    1601         308 :                   if (var->isNodalDefined())
    1602         308 :                     var->insert(_fe_problem.getAuxiliarySystem().solution());
    1603             :                 }
    1604         308 :               }
    1605             :             }
    1606       19404 :             _fe_problem.addCachedResidual(0);
    1607             :           }
    1608             :         }
    1609             :       }
    1610             :     }
    1611             :   }
    1612       26262 :   _communicator.max(constraints_applied);
    1613             : 
    1614       26262 :   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         324 :     _communicator.max(residual_has_inserted_values);
    1619         324 :     if (residual_has_inserted_values)
    1620           0 :       residual.close();
    1621             : 
    1622         324 :     _fe_problem.addCachedResidualDirectly(residual, 0);
    1623         324 :     residual.close();
    1624             : 
    1625         324 :     if (_need_residual_ghosted)
    1626         324 :       *_residual_ghosted = residual;
    1627             :   }
    1628       26262 :   _communicator.max(has_writable_variables);
    1629             : 
    1630       26262 :   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          18 :     _fe_problem.getAuxiliarySystem().solution().close();
    1636          18 :     _fe_problem.getAuxiliarySystem().system().update();
    1637          18 :     solutionOld().close();
    1638             :   }
    1639             : 
    1640             :   // We may have additional tagged vectors that also need to be accumulated
    1641       26262 :   _fe_problem.addCachedResidual(0);
    1642       26262 : }
    1643             : 
    1644             : void
    1645        4136 : NonlinearSystemBase::overwriteNodeFace(NumericVector<Number> & soln)
    1646             : {
    1647             :   // Overwrite results from integrator in case we have explicit dynamics contact constraints
    1648        4136 :   auto & subproblem = _fe_problem.getDisplacedProblem()
    1649        6336 :                           ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    1650        6336 :                           : static_cast<SubProblem &>(_fe_problem);
    1651        4136 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    1652             : 
    1653        6336 :   for (const auto & it : penetration_locators)
    1654             :   {
    1655        2200 :     PenetrationLocator & pen_loc = *(it.second);
    1656             : 
    1657        2200 :     const auto & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    1658        2200 :     const BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    1659        2200 :     const BoundaryID primary_boundary = pen_loc._primary_boundary;
    1660             : 
    1661        2200 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, true))
    1662             :     {
    1663             :       const auto & constraints =
    1664        2200 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, true);
    1665       35800 :       for (const auto i : index_range(secondary_nodes))
    1666             :       {
    1667       33600 :         const auto secondary_node_num = secondary_nodes[i];
    1668       33600 :         const Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    1669             : 
    1670       33600 :         if (secondary_node.processor_id() == processor_id())
    1671       25600 :           if (pen_loc._penetration_info[secondary_node_num])
    1672       51200 :             for (const auto & nfc : constraints)
    1673             :             {
    1674       25600 :               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       51200 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    1682       25600 :                   nfc->primaryBoundary() != primary_boundary)
    1683           0 :                 continue;
    1684             : 
    1685       25600 :               nfc->overwriteBoundaryVariables(soln, secondary_node);
    1686             :             }
    1687             :       }
    1688             :     }
    1689             :   }
    1690        4136 :   soln.close();
    1691        4136 : }
    1692             : 
    1693             : void
    1694     3129821 : NonlinearSystemBase::residualSetup()
    1695             : {
    1696     3129821 :   TIME_SECTION("residualSetup", 3);
    1697             : 
    1698     3129821 :   SolverSystem::residualSetup();
    1699             : 
    1700     6562811 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
    1701             :   {
    1702     3432990 :     _kernels.residualSetup(tid);
    1703     3432990 :     _nodal_kernels.residualSetup(tid);
    1704     3432990 :     _dirac_kernels.residualSetup(tid);
    1705     3432990 :     if (_doing_dg)
    1706       34019 :       _dg_kernels.residualSetup(tid);
    1707     3432990 :     _interface_kernels.residualSetup(tid);
    1708     3432990 :     _element_dampers.residualSetup(tid);
    1709     3432990 :     _nodal_dampers.residualSetup(tid);
    1710     3432990 :     _integrated_bcs.residualSetup(tid);
    1711             :   }
    1712     3129821 :   _scalar_kernels.residualSetup();
    1713     3129821 :   _constraints.residualSetup();
    1714     3129821 :   _general_dampers.residualSetup();
    1715     3129821 :   _nodal_bcs.residualSetup();
    1716             : 
    1717             :   // Avoid recursion
    1718     3129821 :   if (this == &_fe_problem.currentNonlinearSystem())
    1719     3043901 :     _fe_problem.residualSetup();
    1720     3129821 :   _app.solutionInvalidity().resetSolutionInvalidCurrentIteration();
    1721     3129821 : }
    1722             : 
    1723             : void
    1724     3040556 : NonlinearSystemBase::computeResidualInternal(const std::set<TagID> & tags)
    1725             : {
    1726             :   parallel_object_only();
    1727             : 
    1728     3040556 :   TIME_SECTION("computeResidualInternal", 3);
    1729             : 
    1730     3040556 :   residualSetup();
    1731             : 
    1732     3040556 :   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     3040556 :   std::vector<UserObject *> uos;
    1737     3040556 :   _fe_problem.theWarehouse()
    1738     6081112 :       .query()
    1739     3040556 :       .condition<AttribSystem>("UserObject")
    1740     3040556 :       .condition<AttribExecOns>(EXEC_PRE_KERNELS)
    1741     3040556 :       .queryInto(uos);
    1742     3040556 :   for (auto & uo : uos)
    1743           0 :     uo->residualSetup();
    1744     3040556 :   for (auto & uo : uos)
    1745             :   {
    1746           0 :     uo->initialize();
    1747           0 :     uo->execute();
    1748           0 :     uo->finalize();
    1749             :   }
    1750             : 
    1751             :   // reinit scalar variables
    1752     6376062 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    1753     3335506 :     _fe_problem.reinitScalars(tid);
    1754             : 
    1755             :   // residual contributions from the domain
    1756             :   PARALLEL_TRY
    1757             :   {
    1758     3040556 :     TIME_SECTION("Kernels", 3 /*, "Computing Kernels"*/);
    1759             : 
    1760     3040556 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    1761             : 
    1762     3040556 :     ComputeResidualThread cr(_fe_problem, tags);
    1763     3040556 :     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     3040534 :     if (_fe_problem.haveFV())
    1771             :     {
    1772             :       ComputeFVFluxResidualThread<FVRange> fvr(
    1773      144832 :           _fe_problem, this->number(), tags, /*on_displaced=*/false);
    1774      144832 :       FVRange faces(_fe_problem.mesh().ownedFaceInfoBegin(), _fe_problem.mesh().ownedFaceInfoEnd());
    1775      144832 :       Threads::parallel_reduce(faces, fvr);
    1776      144832 :     }
    1777     3040526 :     if (auto displaced_problem = _fe_problem.getDisplacedProblem();
    1778     3040526 :         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     3040526 :     }
    1786             : 
    1787     3040526 :     unsigned int n_threads = libMesh::n_threads();
    1788     6375996 :     for (unsigned int i = 0; i < n_threads;
    1789             :          i++) // Add any cached residuals that might be hanging around
    1790     3335470 :       _fe_problem.addCachedResidual(i);
    1791     3040526 :   }
    1792     3040526 :   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     3040409 :     if (_scalar_kernels.hasActiveObjects())
    1799             :     {
    1800       66325 :       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       66325 :       if (!tags.size() || tags.size() == _fe_problem.numVectorTags(Moose::VECTOR_TAG_RESIDUAL))
    1807       66306 :         scalar_kernel_warehouse = &_scalar_kernels;
    1808          19 :       else if (tags.size() == 1)
    1809             :         scalar_kernel_warehouse =
    1810          11 :             &(_scalar_kernels.getVectorTagObjectWarehouse(*(tags.begin()), 0));
    1811             :       else
    1812             :         // scalar_kernels is not threading
    1813           8 :         scalar_kernel_warehouse = &(_scalar_kernels.getVectorTagsObjectWarehouse(tags, 0));
    1814             : 
    1815       66325 :       bool have_scalar_contributions = false;
    1816       66325 :       const auto & scalars = scalar_kernel_warehouse->getActiveObjects();
    1817      244328 :       for (const auto & scalar_kernel : scalars)
    1818             :       {
    1819      178003 :         scalar_kernel->reinit();
    1820      178003 :         const std::vector<dof_id_type> & dof_indices = scalar_kernel->variable().dofIndices();
    1821      178003 :         const DofMap & dof_map = scalar_kernel->variable().dofMap();
    1822      178003 :         const dof_id_type first_dof = dof_map.first_dof();
    1823      178003 :         const dof_id_type end_dof = dof_map.end_dof();
    1824      208196 :         for (dof_id_type dof : dof_indices)
    1825             :         {
    1826      178580 :           if (dof >= first_dof && dof < end_dof)
    1827             :           {
    1828      148387 :             scalar_kernel->computeResidual();
    1829      148387 :             have_scalar_contributions = true;
    1830      148387 :             break;
    1831             :           }
    1832             :         }
    1833             :       }
    1834       66325 :       if (have_scalar_contributions)
    1835       57299 :         _fe_problem.addResidualScalar();
    1836       66325 :     }
    1837             :   }
    1838     3040409 :   PARALLEL_CATCH;
    1839             : 
    1840             :   // residual contributions from Block NodalKernels
    1841             :   PARALLEL_TRY
    1842             :   {
    1843     3040409 :     if (_nodal_kernels.hasActiveBlockObjects())
    1844             :     {
    1845       14423 :       TIME_SECTION("NodalKernels", 3 /*, "Computing NodalKernels"*/);
    1846             : 
    1847       14423 :       ComputeNodalKernelsThread cnk(_fe_problem, _nodal_kernels, tags);
    1848             : 
    1849       14423 :       const ConstNodeRange & range = _fe_problem.getCurrentAlgebraicNodeRange();
    1850             : 
    1851       14423 :       if (range.begin() != range.end())
    1852             :       {
    1853       14423 :         _fe_problem.reinitNode(*range.begin(), 0);
    1854             : 
    1855       14423 :         Threads::parallel_reduce(range, cnk);
    1856             : 
    1857       14423 :         unsigned int n_threads = libMesh::n_threads();
    1858       35712 :         for (unsigned int i = 0; i < n_threads;
    1859             :              i++) // Add any cached residuals that might be hanging around
    1860       21289 :           _fe_problem.addCachedResidual(i);
    1861             :       }
    1862       14423 :     }
    1863             :   }
    1864     3040409 :   PARALLEL_CATCH;
    1865             : 
    1866     3040409 :   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     3040359 :     if (_nodal_kernels.hasActiveBoundaryObjects())
    1876             :     {
    1877         977 :       TIME_SECTION("NodalKernelBCs", 3 /*, "Computing NodalKernelBCs"*/);
    1878             : 
    1879         977 :       ComputeNodalKernelBcsThread cnk(_fe_problem, _nodal_kernels, tags);
    1880             : 
    1881         977 :       const ConstBndNodeRange & bnd_node_range = _fe_problem.getCurrentAlgebraicBndNodeRange();
    1882             : 
    1883         977 :       Threads::parallel_reduce(bnd_node_range, cnk);
    1884             : 
    1885         977 :       unsigned int n_threads = libMesh::n_threads();
    1886        2040 :       for (unsigned int i = 0; i < n_threads;
    1887             :            i++) // Add any cached residuals that might be hanging around
    1888        1063 :         _fe_problem.addCachedResidual(i);
    1889         977 :     }
    1890             :   }
    1891     3040359 :   PARALLEL_CATCH;
    1892             : 
    1893     3040359 :   mortarConstraints(Moose::ComputeType::Residual, tags, {});
    1894             : 
    1895     3040359 :   if (_residual_copy.get())
    1896             :   {
    1897           0 :     _Re_non_time->close();
    1898           0 :     _Re_non_time->localize(*_residual_copy);
    1899             :   }
    1900             : 
    1901     3040359 :   if (_need_residual_ghosted)
    1902             :   {
    1903       12290 :     _Re_non_time->close();
    1904       12290 :     *_residual_ghosted = *_Re_non_time;
    1905       12290 :     _residual_ghosted->close();
    1906             :   }
    1907             : 
    1908     3040359 :   PARALLEL_TRY { computeDiracContributions(tags, false); }
    1909     3040347 :   PARALLEL_CATCH;
    1910             : 
    1911     3040347 :   if (_fe_problem._has_constraints)
    1912             :   {
    1913       21781 :     PARALLEL_TRY { enforceNodalConstraintsResidual(*_Re_non_time); }
    1914       21781 :     PARALLEL_CATCH;
    1915       21781 :     _Re_non_time->close();
    1916             :   }
    1917             : 
    1918             :   // Add in Residual contributions from other Constraints
    1919     3040347 :   if (_fe_problem._has_constraints)
    1920             :   {
    1921             :     PARALLEL_TRY
    1922             :     {
    1923             :       // Undisplaced Constraints
    1924       21781 :       constraintResiduals(*_Re_non_time, false);
    1925             : 
    1926             :       // Displaced Constraints
    1927       21781 :       if (_fe_problem.getDisplacedProblem())
    1928        4481 :         constraintResiduals(*_Re_non_time, true);
    1929             : 
    1930       21781 :       if (_fe_problem.computingNonlinearResid())
    1931       10129 :         _constraints.residualEnd();
    1932             :     }
    1933       21781 :     PARALLEL_CATCH;
    1934       21781 :     _Re_non_time->close();
    1935             :   }
    1936             : 
    1937             :   // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
    1938             :   // counters
    1939     3040347 :   _app.solutionInvalidity().syncIteration();
    1940     3040347 :   _app.solutionInvalidity().solutionInvalidAccumulation();
    1941     3040848 : }
    1942             : 
    1943             : void
    1944        3345 : NonlinearSystemBase::computeResidualAndJacobianInternal(const std::set<TagID> & vector_tags,
    1945             :                                                         const std::set<TagID> & matrix_tags)
    1946             : {
    1947        3345 :   TIME_SECTION("computeResidualAndJacobianInternal", 3);
    1948             : 
    1949             :   // Make matrix ready to use
    1950        3345 :   activeAllMatrixTags();
    1951             : 
    1952       10035 :   for (auto tag : matrix_tags)
    1953             :   {
    1954        6690 :     if (!hasMatrix(tag))
    1955        3345 :       continue;
    1956             : 
    1957        3345 :     auto & jacobian = getMatrix(tag);
    1958             :     // Necessary for speed
    1959        3345 :     if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&jacobian))
    1960             :     {
    1961        3345 :       LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
    1962             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    1963             :                                     PETSC_TRUE));
    1964        3345 :       if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    1965           0 :         LibmeshPetscCall(
    1966             :             MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
    1967        3345 :       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        3345 :   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        3345 :   std::vector<UserObject *> uos;
    1979        3345 :   _fe_problem.theWarehouse()
    1980        6690 :       .query()
    1981        3345 :       .condition<AttribSystem>("UserObject")
    1982        3345 :       .condition<AttribExecOns>(EXEC_PRE_KERNELS)
    1983        3345 :       .queryInto(uos);
    1984        3345 :   for (auto & uo : uos)
    1985           0 :     uo->residualSetup();
    1986        3345 :   for (auto & uo : uos)
    1987             :   {
    1988           0 :     uo->initialize();
    1989           0 :     uo->execute();
    1990           0 :     uo->finalize();
    1991             :   }
    1992             : 
    1993             :   // reinit scalar variables
    1994        7029 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    1995        3684 :     _fe_problem.reinitScalars(tid);
    1996             : 
    1997             :   // residual contributions from the domain
    1998             :   PARALLEL_TRY
    1999             :   {
    2000        3345 :     TIME_SECTION("Kernels", 3 /*, "Computing Kernels"*/);
    2001             : 
    2002        3345 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    2003             : 
    2004        3345 :     ComputeResidualAndJacobianThread crj(_fe_problem, vector_tags, matrix_tags);
    2005        3345 :     Threads::parallel_reduce(elem_range, crj);
    2006             : 
    2007             :     using FVRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
    2008        3345 :     if (_fe_problem.haveFV())
    2009             :     {
    2010             :       ComputeFVFluxRJThread<FVRange> fvrj(
    2011        1358 :           _fe_problem, this->number(), vector_tags, matrix_tags, /*on_displaced=*/false);
    2012        1358 :       FVRange faces(_fe_problem.mesh().ownedFaceInfoBegin(), _fe_problem.mesh().ownedFaceInfoEnd());
    2013        1358 :       Threads::parallel_reduce(faces, fvrj);
    2014        1358 :     }
    2015        3345 :     if (auto displaced_problem = _fe_problem.getDisplacedProblem();
    2016        3345 :         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        3345 :     }
    2024             : 
    2025        3345 :     mortarConstraints(Moose::ComputeType::ResidualAndJacobian, vector_tags, matrix_tags);
    2026             : 
    2027        3345 :     unsigned int n_threads = libMesh::n_threads();
    2028        7029 :     for (unsigned int i = 0; i < n_threads;
    2029             :          i++) // Add any cached residuals that might be hanging around
    2030             :     {
    2031        3684 :       _fe_problem.addCachedResidual(i);
    2032        3684 :       _fe_problem.addCachedJacobian(i);
    2033             :     }
    2034        3345 :   }
    2035        3345 :   PARALLEL_CATCH;
    2036        3345 : }
    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     3040347 : 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     3040347 :   if (_has_save_in)
    2068         284 :     _fe_problem.getAuxiliarySystem().solution().close();
    2069             : 
    2070             :   // Select nodal kernels
    2071             :   MooseObjectWarehouse<NodalBCBase> * nbc_warehouse;
    2072             : 
    2073     3040347 :   if (tags.size() == _fe_problem.numVectorTags(Moose::VECTOR_TAG_RESIDUAL) || !tags.size())
    2074     3004174 :     nbc_warehouse = &_nodal_bcs;
    2075       36173 :   else if (tags.size() == 1)
    2076       17334 :     nbc_warehouse = &(_nodal_bcs.getVectorTagObjectWarehouse(*(tags.begin()), 0));
    2077             :   else
    2078       18839 :     nbc_warehouse = &(_nodal_bcs.getVectorTagsObjectWarehouse(tags, 0));
    2079             : 
    2080             :   // Return early if there is no nodal kernel
    2081     3040347 :   if (!nbc_warehouse->size())
    2082      398127 :     return;
    2083             : 
    2084             :   PARALLEL_TRY
    2085             :   {
    2086     2642220 :     const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    2087             : 
    2088     2642220 :     if (!bnd_nodes.empty())
    2089             :     {
    2090     2641916 :       TIME_SECTION("NodalBCs", 3 /*, "Computing NodalBCs"*/);
    2091             : 
    2092   137416063 :       for (const auto & bnode : bnd_nodes)
    2093             :       {
    2094   134774147 :         BoundaryID boundary_id = bnode->_bnd_id;
    2095   134774147 :         Node * node = bnode->_node;
    2096             : 
    2097   235861401 :         if (node->processor_id() == processor_id() &&
    2098   101087254 :             nbc_warehouse->hasActiveBoundaryObjects(boundary_id))
    2099             :         {
    2100             :           // reinit variables in nodes
    2101    51802493 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
    2102             : 
    2103    51802493 :           const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id);
    2104   108580511 :           for (const auto & nbc : bcs)
    2105    56778018 :             if (nbc->shouldApply())
    2106    56776809 :               nbc->computeResidual();
    2107             :         }
    2108             :       }
    2109     2641916 :     }
    2110             :   }
    2111     2642220 :   PARALLEL_CATCH;
    2112             : 
    2113     2642220 :   if (_Re_time)
    2114     2337188 :     _Re_time->close();
    2115     2642220 :   _Re_non_time->close();
    2116             : }
    2117             : 
    2118             : void
    2119        3345 : NonlinearSystemBase::computeNodalBCsResidualAndJacobian()
    2120             : {
    2121             :   PARALLEL_TRY
    2122             :   {
    2123        3345 :     const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    2124             : 
    2125        3345 :     if (!bnd_nodes.empty())
    2126             :     {
    2127        3345 :       TIME_SECTION("NodalBCs", 3 /*, "Computing NodalBCs"*/);
    2128             : 
    2129       82175 :       for (const auto & bnode : bnd_nodes)
    2130             :       {
    2131       78830 :         BoundaryID boundary_id = bnode->_bnd_id;
    2132       78830 :         Node * node = bnode->_node;
    2133             : 
    2134       78830 :         if (node->processor_id() == processor_id())
    2135             :         {
    2136             :           // reinit variables in nodes
    2137       58446 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
    2138       58446 :           if (_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
    2139             :           {
    2140       12169 :             const auto & bcs = _nodal_bcs.getActiveBoundaryObjects(boundary_id);
    2141       24338 :             for (const auto & nbc : bcs)
    2142       12169 :               if (nbc->shouldApply())
    2143       12169 :                 nbc->computeResidualAndJacobian();
    2144             :           }
    2145             :         }
    2146             :       }
    2147        3345 :     }
    2148             :   }
    2149        3345 :   PARALLEL_CATCH;
    2150             : 
    2151             :   // Set the cached NodalBCBase values in the Jacobian matrix
    2152        3345 :   _fe_problem.assembly(0, number()).setCachedJacobian(Assembly::GlobalDataKey{});
    2153        3345 : }
    2154             : 
    2155             : void
    2156         625 : NonlinearSystemBase::getNodeDofs(dof_id_type node_id, std::vector<dof_id_type> & dofs)
    2157             : {
    2158         625 :   const Node & node = _mesh.nodeRef(node_id);
    2159         625 :   unsigned int s = number();
    2160         625 :   if (node.has_dofs(s))
    2161             :   {
    2162        1284 :     for (unsigned int v = 0; v < nVariables(); v++)
    2163        1284 :       for (unsigned int c = 0; c < node.n_comp(s, v); c++)
    2164         625 :         dofs.push_back(node.dof_number(s, v, c));
    2165             :   }
    2166         625 : }
    2167             : 
    2168             : void
    2169        4609 : NonlinearSystemBase::findImplicitGeometricCouplingEntries(
    2170             :     GeometricSearchData & geom_search_data,
    2171             :     std::unordered_map<dof_id_type, std::vector<dof_id_type>> & graph)
    2172             : {
    2173        4609 :   const auto & node_to_elem_map = _mesh.nodeToElemMap();
    2174        4609 :   const auto & nearest_node_locators = geom_search_data._nearest_node_locators;
    2175        6553 :   for (const auto & it : nearest_node_locators)
    2176             :   {
    2177        1944 :     std::vector<dof_id_type> & secondary_nodes = it.second->_secondary_nodes;
    2178             : 
    2179        9810 :     for (const auto & secondary_node : secondary_nodes)
    2180             :     {
    2181        7866 :       std::set<dof_id_type> unique_secondary_indices;
    2182        7866 :       std::set<dof_id_type> unique_primary_indices;
    2183             : 
    2184        7866 :       auto node_to_elem_pair = node_to_elem_map.find(secondary_node);
    2185        7866 :       if (node_to_elem_pair != node_to_elem_map.end())
    2186             :       {
    2187        7758 :         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       20868 :         for (const auto & cur_elem : elems)
    2191             :         {
    2192       13110 :           std::vector<dof_id_type> dof_indices;
    2193       13110 :           dofMap().dof_indices(_mesh.elemPtr(cur_elem), dof_indices);
    2194             : 
    2195       65550 :           for (const auto & dof : dof_indices)
    2196       52440 :             unique_secondary_indices.insert(dof);
    2197       13110 :         }
    2198             :       }
    2199             : 
    2200        7866 :       std::vector<dof_id_type> primary_nodes = it.second->_neighbor_nodes[secondary_node];
    2201             : 
    2202       44400 :       for (const auto & primary_node : primary_nodes)
    2203             :       {
    2204       36534 :         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       36534 :         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       95886 :         for (const auto & cur_elem : primary_node_elems)
    2211             :         {
    2212       59352 :           std::vector<dof_id_type> dof_indices;
    2213       59352 :           dofMap().dof_indices(_mesh.elemPtr(cur_elem), dof_indices);
    2214             : 
    2215      296760 :           for (const auto & dof : dof_indices)
    2216      237408 :             unique_primary_indices.insert(dof);
    2217       59352 :         }
    2218             :       }
    2219             : 
    2220       49602 :       for (const auto & secondary_id : unique_secondary_indices)
    2221      453432 :         for (const auto & primary_id : unique_primary_indices)
    2222             :         {
    2223      411696 :           graph[secondary_id].push_back(primary_id);
    2224      411696 :           graph[primary_id].push_back(secondary_id);
    2225             :         }
    2226        7866 :     }
    2227             :   }
    2228             : 
    2229             :   // handle node-to-node constraints
    2230        4609 :   const auto & ncs = _constraints.getActiveNodalConstraints();
    2231        4750 :   for (const auto & nc : ncs)
    2232             :   {
    2233         141 :     std::vector<dof_id_type> primary_dofs;
    2234         141 :     std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
    2235         282 :     for (const auto & node_id : primary_node_ids)
    2236             :     {
    2237         141 :       Node * node = _mesh.queryNodePtr(node_id);
    2238         141 :       if (node && node->processor_id() == this->processor_id())
    2239             :       {
    2240         126 :         getNodeDofs(node_id, primary_dofs);
    2241             :       }
    2242             :     }
    2243             : 
    2244         141 :     _communicator.allgather(primary_dofs);
    2245             : 
    2246         141 :     std::vector<dof_id_type> secondary_dofs;
    2247         141 :     std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
    2248         640 :     for (const auto & node_id : secondary_node_ids)
    2249             :     {
    2250         499 :       Node * node = _mesh.queryNodePtr(node_id);
    2251         499 :       if (node && node->processor_id() == this->processor_id())
    2252             :       {
    2253         499 :         getNodeDofs(node_id, secondary_dofs);
    2254             :       }
    2255             :     }
    2256             : 
    2257         141 :     _communicator.allgather(secondary_dofs);
    2258             : 
    2259         282 :     for (const auto & primary_id : primary_dofs)
    2260         778 :       for (const auto & secondary_id : secondary_dofs)
    2261             :       {
    2262         637 :         graph[primary_id].push_back(secondary_id);
    2263         637 :         graph[secondary_id].push_back(primary_id);
    2264             :       }
    2265         141 :   }
    2266             : 
    2267             :   // Make every entry sorted and unique
    2268       27059 :   for (auto & it : graph)
    2269             :   {
    2270       22450 :     std::vector<dof_id_type> & row = it.second;
    2271       22450 :     std::sort(row.begin(), row.end());
    2272       22450 :     std::vector<dof_id_type>::iterator uit = std::unique(row.begin(), row.end());
    2273       22450 :     row.resize(uit - row.begin());
    2274             :   }
    2275        4609 : }
    2276             : 
    2277             : void
    2278        3736 : NonlinearSystemBase::addImplicitGeometricCouplingEntries(GeometricSearchData & geom_search_data)
    2279             : {
    2280        3736 :   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        3736 :   auto & jacobian = getMatrix(systemMatrixTag());
    2286             : 
    2287        3736 :   std::unordered_map<dof_id_type, std::vector<dof_id_type>> graph;
    2288             : 
    2289        3736 :   findImplicitGeometricCouplingEntries(geom_search_data, graph);
    2290             : 
    2291       25382 :   for (const auto & it : graph)
    2292             :   {
    2293       21646 :     dof_id_type dof = it.first;
    2294       21646 :     const auto & row = it.second;
    2295             : 
    2296      253974 :     for (const auto & coupled_dof : row)
    2297      232328 :       jacobian.add(dof, coupled_dof, 0);
    2298             :   }
    2299        3736 : }
    2300             : 
    2301             : void
    2302        4289 : NonlinearSystemBase::constraintJacobians(const SparseMatrix<Number> & jacobian_to_view,
    2303             :                                          bool displaced)
    2304             : {
    2305        4289 :   if (!hasMatrix(systemMatrixTag()))
    2306           0 :     mooseError("A system matrix is required");
    2307             : 
    2308        4289 :   auto & jacobian = getMatrix(systemMatrixTag());
    2309             : 
    2310        4289 :   if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    2311           0 :     LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2312             :                                   MAT_NEW_NONZERO_ALLOCATION_ERR,
    2313             :                                   PETSC_FALSE));
    2314        4289 :   if (_fe_problem.ignoreZerosInJacobian())
    2315           0 :     LibmeshPetscCall(MatSetOption(
    2316             :         static_cast<PetscMatrix<Number> &>(jacobian).mat(), MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
    2317             : 
    2318        4289 :   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        1942 :   auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
    2325        5260 :                                 : static_cast<SubProblem &>(_fe_problem);
    2326        4289 :   const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
    2327             : 
    2328             :   bool constraints_applied;
    2329        4289 :   if (!_assemble_constraints_separately)
    2330        4289 :     constraints_applied = false;
    2331        6175 :   for (const auto & it : penetration_locators)
    2332             :   {
    2333        1886 :     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        1886 :     PenetrationLocator & pen_loc = *(it.second);
    2340             : 
    2341        1886 :     std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
    2342             : 
    2343        1886 :     BoundaryID secondary_boundary = pen_loc._secondary_boundary;
    2344        1886 :     BoundaryID primary_boundary = pen_loc._primary_boundary;
    2345             : 
    2346        1886 :     zero_rows.clear();
    2347        1886 :     if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
    2348             :     {
    2349             :       const auto & constraints =
    2350        1028 :           _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
    2351             : 
    2352        5138 :       for (const auto & secondary_node_num : secondary_nodes)
    2353             :       {
    2354        4110 :         Node & secondary_node = _mesh.nodeRef(secondary_node_num);
    2355             : 
    2356        4110 :         if (secondary_node.processor_id() == processor_id())
    2357             :         {
    2358        3696 :           if (pen_loc._penetration_info[secondary_node_num])
    2359             :           {
    2360        3696 :             PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
    2361             : 
    2362        3696 :             reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
    2363        3696 :             _fe_problem.reinitOffDiagScalars(0);
    2364             : 
    2365        7392 :             for (const auto & nfc : constraints)
    2366             :             {
    2367        3696 :               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        7392 :               if (nfc->secondaryBoundary() != secondary_boundary ||
    2374        3696 :                   nfc->primaryBoundary() != primary_boundary)
    2375           0 :                 continue;
    2376             : 
    2377        3696 :               nfc->_jacobian = &jacobian_to_view;
    2378             : 
    2379        3696 :               if (nfc->shouldApply())
    2380             :               {
    2381        3696 :                 constraints_applied = true;
    2382             : 
    2383        3696 :                 nfc->prepareShapes(nfc->variable().number());
    2384        3696 :                 nfc->prepareNeighborShapes(nfc->variable().number());
    2385             : 
    2386        3696 :                 nfc->computeJacobian();
    2387             : 
    2388        3696 :                 if (nfc->overwriteSecondaryJacobian())
    2389             :                 {
    2390             :                   // Add this variable's dof's row to be zeroed
    2391        3696 :                   zero_rows.push_back(nfc->variable().nodalDofIndex());
    2392             :                 }
    2393             : 
    2394        3696 :                 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        3696 :                     nfc->overwriteSecondaryJacobian() ? 1. : nfc->variable().scalingFactor();
    2402             : 
    2403             :                 // Cache the jacobian block for the secondary side
    2404        7392 :                 nfc->addJacobian(_fe_problem.assembly(0, number()),
    2405        3696 :                                  nfc->_Kee,
    2406             :                                  secondary_dofs,
    2407        3696 :                                  nfc->_connected_dof_indices,
    2408             :                                  scaling_factor);
    2409             : 
    2410             :                 // Cache Ken, Kne, Knn
    2411        3696 :                 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        7392 :                   nfc->addJacobian(_fe_problem.assembly(0, number()),
    2416        3696 :                                    nfc->_Ken,
    2417             :                                    secondary_dofs,
    2418        3696 :                                    nfc->primaryVariable().dofIndicesNeighbor(),
    2419             :                                    scaling_factor);
    2420             : 
    2421             :                   // Use _connected_dof_indices to get all the correct columns
    2422        7392 :                   nfc->addJacobian(_fe_problem.assembly(0, number()),
    2423        3696 :                                    nfc->_Kne,
    2424        3696 :                                    nfc->primaryVariable().dofIndicesNeighbor(),
    2425        3696 :                                    nfc->_connected_dof_indices,
    2426        3696 :                                    nfc->primaryVariable().scalingFactor());
    2427             : 
    2428             :                   // We've handled Ken and Kne, finally handle Knn
    2429        3696 :                   _fe_problem.cacheJacobianNeighbor(0);
    2430             :                 }
    2431             : 
    2432             :                 // Do the off-diagonals next
    2433        3696 :                 const std::vector<MooseVariableFEBase *> coupled_vars = nfc->getCoupledMooseVars();
    2434        7392 :                 for (const auto & jvar : coupled_vars)
    2435             :                 {
    2436             :                   // Only compute jacobians for nonlinear variables
    2437        3696 :                   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        3760 :                   if (nfc->variable().number() == jvar->number() ||
    2443         128 :                       !_fe_problem.areCoupled(
    2444          64 :                           nfc->variable().number(), jvar->number(), this->number()))
    2445        3632 :                     continue;
    2446             : 
    2447             :                   // Need to zero out the matrices first
    2448          64 :                   _fe_problem.prepareAssembly(0);
    2449             : 
    2450          64 :                   nfc->prepareShapes(nfc->variable().number());
    2451          64 :                   nfc->prepareNeighborShapes(jvar->number());
    2452             : 
    2453          64 :                   nfc->computeOffDiagJacobian(jvar->number());
    2454             : 
    2455             :                   // Cache the jacobian block for the secondary side
    2456         128 :                   nfc->addJacobian(_fe_problem.assembly(0, number()),
    2457          64 :                                    nfc->_Kee,
    2458             :                                    secondary_dofs,
    2459          64 :                                    nfc->_connected_dof_indices,
    2460             :                                    scaling_factor);
    2461             : 
    2462             :                   // Cache Ken, Kne, Knn
    2463          64 :                   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         128 :                     nfc->addJacobian(_fe_problem.assembly(0, number()),
    2468          64 :                                      nfc->_Ken,
    2469             :                                      secondary_dofs,
    2470          64 :                                      jvar->dofIndicesNeighbor(),
    2471             :                                      scaling_factor);
    2472             : 
    2473             :                     // Use _connected_dof_indices to get all the correct columns
    2474         128 :                     nfc->addJacobian(_fe_problem.assembly(0, number()),
    2475          64 :                                      nfc->_Kne,
    2476          64 :                                      nfc->variable().dofIndicesNeighbor(),
    2477          64 :                                      nfc->_connected_dof_indices,
    2478          64 :                                      nfc->variable().scalingFactor());
    2479             : 
    2480             :                     // We've handled Ken and Kne, finally handle Knn
    2481          64 :                     _fe_problem.cacheJacobianNeighbor(0);
    2482             :                   }
    2483             :                 }
    2484        3696 :               }
    2485             :             }
    2486             :           }
    2487             :         }
    2488             :       }
    2489             :     }
    2490        1886 :     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        4289 :   if (!_assemble_constraints_separately)
    2510             :   {
    2511             :     // See if constraints were applied anywhere
    2512        4289 :     _communicator.max(constraints_applied);
    2513             : 
    2514        4289 :     if (constraints_applied)
    2515             :     {
    2516         962 :       LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2517             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2518             :                                     PETSC_TRUE));
    2519             : 
    2520         962 :       jacobian.close();
    2521         962 :       jacobian.zero_rows(zero_rows, 0.0);
    2522         962 :       jacobian.close();
    2523         962 :       _fe_problem.addCachedJacobian(0);
    2524         962 :       jacobian.close();
    2525             :     }
    2526             :   }
    2527             : 
    2528        4289 :   THREAD_ID tid = 0;
    2529             :   // go over element-element constraint interface
    2530        4289 :   const auto & element_pair_locators = subproblem.geomSearchData()._element_pair_locators;
    2531        4289 :   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        4289 :   std::set<dof_id_type> unique_secondary_node_ids;
    2577        4289 :   constraints_applied = false;
    2578       18264 :   for (const auto & secondary_id : _mesh.meshSubdomains())
    2579             :   {
    2580       68016 :     for (const auto & primary_id : _mesh.meshSubdomains())
    2581             :     {
    2582       54041 :       if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
    2583             :       {
    2584             :         const auto & constraints =
    2585         162 :             _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
    2586             : 
    2587             :         // get unique set of ids of all nodes on current block
    2588         162 :         unique_secondary_node_ids.clear();
    2589         162 :         const MeshBase & meshhelper = _mesh.getMesh();
    2590         324 :         for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
    2591       15606 :                                           meshhelper.active_subdomain_elements_end(secondary_id)))
    2592             :         {
    2593       44226 :           for (auto & n : elem->node_ref_range())
    2594       36666 :             unique_secondary_node_ids.insert(n.id());
    2595         162 :         }
    2596             : 
    2597       12636 :         for (auto secondary_node_id : unique_secondary_node_ids)
    2598             :         {
    2599       12474 :           const Node & secondary_node = _mesh.nodeRef(secondary_node_id);
    2600             :           // check if secondary node is on current processor
    2601       12474 :           if (secondary_node.processor_id() == processor_id())
    2602             :           {
    2603             :             // This reinits the variables that exist on the secondary node
    2604        9702 :             _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        9702 :             _fe_problem.prepareAssembly(0);
    2609        9702 :             _fe_problem.reinitOffDiagScalars(0);
    2610             : 
    2611       20636 :             for (const auto & nec : constraints)
    2612             :             {
    2613       10934 :               if (nec->shouldApply())
    2614             :               {
    2615        4970 :                 constraints_applied = true;
    2616             : 
    2617        4970 :                 nec->_jacobian = &jacobian_to_view;
    2618        4970 :                 nec->prepareShapes(nec->variable().number());
    2619        4970 :                 nec->prepareNeighborShapes(nec->variable().number());
    2620             : 
    2621        4970 :                 nec->computeJacobian();
    2622             : 
    2623        4970 :                 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        4970 :                 std::vector<dof_id_type> secondary_dofs(1, nec->variable().nodalDofIndex());
    2630             : 
    2631             :                 // Cache the jacobian block for the secondary side
    2632        9940 :                 nec->addJacobian(_fe_problem.assembly(0, number()),
    2633        4970 :                                  nec->_Kee,
    2634             :                                  secondary_dofs,
    2635        4970 :                                  nec->_connected_dof_indices,
    2636        4970 :                                  nec->variable().scalingFactor());
    2637             : 
    2638             :                 // Cache the jacobian block for the primary side
    2639        9940 :                 nec->addJacobian(_fe_problem.assembly(0, number()),
    2640        4970 :                                  nec->_Kne,
    2641        4970 :                                  nec->primaryVariable().dofIndicesNeighbor(),
    2642        4970 :                                  nec->_connected_dof_indices,
    2643        4970 :                                  nec->primaryVariable().scalingFactor());
    2644             : 
    2645        4970 :                 _fe_problem.cacheJacobian(0);
    2646        4970 :                 _fe_problem.cacheJacobianNeighbor(0);
    2647             : 
    2648             :                 // Do the off-diagonals next
    2649        4970 :                 const std::vector<MooseVariableFEBase *> coupled_vars = nec->getCoupledMooseVars();
    2650       10010 :                 for (const auto & jvar : coupled_vars)
    2651             :                 {
    2652             :                   // Only compute jacobians for nonlinear variables
    2653        5040 :                   if (jvar->kind() != Moose::VAR_SOLVER)
    2654          70 :                     continue;
    2655             : 
    2656             :                   // Only compute Jacobian entries if this coupling is being used by the
    2657             :                   // preconditioner
    2658        5530 :                   if (nec->variable().number() == jvar->number() ||
    2659        1120 :                       !_fe_problem.areCoupled(
    2660         560 :                           nec->variable().number(), jvar->number(), this->number()))
    2661        4410 :                     continue;
    2662             : 
    2663             :                   // Need to zero out the matrices first
    2664         560 :                   _fe_problem.prepareAssembly(0);
    2665             : 
    2666         560 :                   nec->prepareShapes(nec->variable().number());
    2667         560 :                   nec->prepareNeighborShapes(jvar->number());
    2668             : 
    2669         560 :                   nec->computeOffDiagJacobian(jvar->number());
    2670             : 
    2671             :                   // Cache the jacobian block for the secondary side
    2672        1120 :                   nec->addJacobian(_fe_problem.assembly(0, number()),
    2673         560 :                                    nec->_Kee,
    2674             :                                    secondary_dofs,
    2675         560 :                                    nec->_connected_dof_indices,
    2676         560 :                                    nec->variable().scalingFactor());
    2677             : 
    2678             :                   // Cache the jacobian block for the primary side
    2679        1120 :                   nec->addJacobian(_fe_problem.assembly(0, number()),
    2680         560 :                                    nec->_Kne,
    2681         560 :                                    nec->variable().dofIndicesNeighbor(),
    2682         560 :                                    nec->_connected_dof_indices,
    2683         560 :                                    nec->variable().scalingFactor());
    2684             : 
    2685         560 :                   _fe_problem.cacheJacobian(0);
    2686         560 :                   _fe_problem.cacheJacobianNeighbor(0);
    2687             :                 }
    2688        4970 :               }
    2689             :             }
    2690             :           }
    2691             :         }
    2692             :       }
    2693             :     }
    2694             :   }
    2695             :   // See if constraints were applied anywhere
    2696        4289 :   _communicator.max(constraints_applied);
    2697             : 
    2698        4289 :   if (constraints_applied)
    2699             :   {
    2700         162 :     LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    2701             :                                   MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2702             :                                   PETSC_TRUE));
    2703             : 
    2704         162 :     jacobian.close();
    2705         162 :     jacobian.zero_rows(zero_rows, 0.0);
    2706         162 :     jacobian.close();
    2707         162 :     _fe_problem.addCachedJacobian(0);
    2708         162 :     jacobian.close();
    2709             :   }
    2710        4289 : }
    2711             : 
    2712             : void
    2713      476965 : NonlinearSystemBase::computeScalarKernelsJacobians(const std::set<TagID> & tags)
    2714             : {
    2715             :   MooseObjectWarehouse<ScalarKernelBase> * scalar_kernel_warehouse;
    2716             : 
    2717      476965 :   if (!tags.size() || tags.size() == _fe_problem.numMatrixTags())
    2718      468100 :     scalar_kernel_warehouse = &_scalar_kernels;
    2719        8865 :   else if (tags.size() == 1)
    2720        7726 :     scalar_kernel_warehouse = &(_scalar_kernels.getMatrixTagObjectWarehouse(*(tags.begin()), 0));
    2721             :   else
    2722        1139 :     scalar_kernel_warehouse = &(_scalar_kernels.getMatrixTagsObjectWarehouse(tags, 0));
    2723             : 
    2724             :   // Compute the diagonal block for scalar variables
    2725      476965 :   if (scalar_kernel_warehouse->hasActiveObjects())
    2726             :   {
    2727       15751 :     const auto & scalars = scalar_kernel_warehouse->getActiveObjects();
    2728             : 
    2729       15751 :     _fe_problem.reinitScalars(/*tid=*/0);
    2730             : 
    2731       15751 :     _fe_problem.reinitOffDiagScalars(/*_tid*/ 0);
    2732             : 
    2733       15751 :     bool have_scalar_contributions = false;
    2734       56566 :     for (const auto & kernel : scalars)
    2735             :     {
    2736       40815 :       kernel->reinit();
    2737       40815 :       const std::vector<dof_id_type> & dof_indices = kernel->variable().dofIndices();
    2738       40815 :       const DofMap & dof_map = kernel->variable().dofMap();
    2739       40815 :       const dof_id_type first_dof = dof_map.first_dof();
    2740       40815 :       const dof_id_type end_dof = dof_map.end_dof();
    2741       46908 :       for (dof_id_type dof : dof_indices)
    2742             :       {
    2743       40857 :         if (dof >= first_dof && dof < end_dof)
    2744             :         {
    2745       34764 :           kernel->computeJacobian();
    2746       34764 :           _fe_problem.addJacobianOffDiagScalar(kernel->variable().number());
    2747       34764 :           have_scalar_contributions = true;
    2748       34764 :           break;
    2749             :         }
    2750             :       }
    2751             :     }
    2752             : 
    2753       15751 :     if (have_scalar_contributions)
    2754       13840 :       _fe_problem.addJacobianScalar();
    2755             :   }
    2756      476965 : }
    2757             : 
    2758             : void
    2759      491724 : NonlinearSystemBase::jacobianSetup()
    2760             : {
    2761      491724 :   SolverSystem::jacobianSetup();
    2762             : 
    2763     1032827 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
    2764             :   {
    2765      541103 :     _kernels.jacobianSetup(tid);
    2766      541103 :     _nodal_kernels.jacobianSetup(tid);
    2767      541103 :     _dirac_kernels.jacobianSetup(tid);
    2768      541103 :     if (_doing_dg)
    2769        2751 :       _dg_kernels.jacobianSetup(tid);
    2770      541103 :     _interface_kernels.jacobianSetup(tid);
    2771      541103 :     _element_dampers.jacobianSetup(tid);
    2772      541103 :     _nodal_dampers.jacobianSetup(tid);
    2773      541103 :     _integrated_bcs.jacobianSetup(tid);
    2774             :   }
    2775      491724 :   _scalar_kernels.jacobianSetup();
    2776      491724 :   _constraints.jacobianSetup();
    2777      491724 :   _general_dampers.jacobianSetup();
    2778      491724 :   _nodal_bcs.jacobianSetup();
    2779             : 
    2780             :   // Avoid recursion
    2781      491724 :   if (this == &_fe_problem.currentNonlinearSystem())
    2782      476965 :     _fe_problem.jacobianSetup();
    2783      491724 :   _app.solutionInvalidity().resetSolutionInvalidCurrentIteration();
    2784      491724 : }
    2785             : 
    2786             : void
    2787      476965 : NonlinearSystemBase::computeJacobianInternal(const std::set<TagID> & tags)
    2788             : {
    2789      476965 :   TIME_SECTION("computeJacobianInternal", 3);
    2790             : 
    2791      476965 :   _fe_problem.setCurrentNonlinearSystem(number());
    2792             : 
    2793             :   // Make matrix ready to use
    2794      476965 :   activeAllMatrixTags();
    2795             : 
    2796     1423622 :   for (auto tag : tags)
    2797             :   {
    2798      946657 :     if (!hasMatrix(tag))
    2799      468100 :       continue;
    2800             : 
    2801      478557 :     auto & jacobian = getMatrix(tag);
    2802             :     // Necessary for speed
    2803      478557 :     if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&jacobian))
    2804             :     {
    2805      477361 :       LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
    2806             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    2807             :                                     PETSC_TRUE));
    2808      477361 :       if (!_fe_problem.errorOnJacobianNonzeroReallocation())
    2809       12233 :         LibmeshPetscCall(
    2810             :             MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
    2811      477361 :       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      476965 :   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      476965 :   std::vector<UserObject *> uos;
    2823      476965 :   _fe_problem.theWarehouse()
    2824      953930 :       .query()
    2825      476965 :       .condition<AttribSystem>("UserObject")
    2826      476965 :       .condition<AttribExecOns>(EXEC_PRE_KERNELS)
    2827      476965 :       .queryInto(uos);
    2828      476965 :   for (auto & uo : uos)
    2829           0 :     uo->jacobianSetup();
    2830      476965 :   for (auto & uo : uos)
    2831             :   {
    2832           0 :     uo->initialize();
    2833           0 :     uo->execute();
    2834           0 :     uo->finalize();
    2835             :   }
    2836             : 
    2837             :   // reinit scalar variables
    2838     1001936 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    2839      524971 :     _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      476965 :     computeScalarKernelsJacobians(tags);
    2847             : 
    2848             :     // Block restricted Nodal Kernels
    2849      476965 :     if (_nodal_kernels.hasActiveBlockObjects())
    2850             :     {
    2851        3653 :       ComputeNodalKernelJacobiansThread cnkjt(_fe_problem, *this, _nodal_kernels, tags);
    2852        3653 :       const ConstNodeRange & range = _fe_problem.getCurrentAlgebraicNodeRange();
    2853        3653 :       Threads::parallel_reduce(range, cnkjt);
    2854             : 
    2855        3653 :       unsigned int n_threads = libMesh::n_threads();
    2856        8488 :       for (unsigned int i = 0; i < n_threads;
    2857             :            i++) // Add any cached jacobians that might be hanging around
    2858        4835 :         _fe_problem.assembly(i, number()).addCachedJacobian(Assembly::GlobalDataKey{});
    2859        3653 :     }
    2860             : 
    2861             :     using FVRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
    2862      476965 :     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       35190 :           _fe_problem, this->number(), tags, /*on_displaced=*/false);
    2868       35190 :       FVRange faces(_fe_problem.mesh().ownedFaceInfoBegin(), _fe_problem.mesh().ownedFaceInfoEnd());
    2869       35190 :       Threads::parallel_reduce(faces, fvj);
    2870       35190 :     }
    2871      476965 :     if (auto displaced_problem = _fe_problem.getDisplacedProblem();
    2872      476965 :         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      476965 :     }
    2880             : 
    2881      476965 :     mortarConstraints(Moose::ComputeType::Jacobian, {}, tags);
    2882             : 
    2883             :     // Get our element range for looping over
    2884      476965 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    2885             : 
    2886      476965 :     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         594 :       ComputeJacobianForScalingThread cj(_fe_problem, tags);
    2894         594 :       Threads::parallel_reduce(elem_range, cj);
    2895         594 :       unsigned int n_threads = libMesh::n_threads();
    2896        1248 :       for (unsigned int i = 0; i < n_threads;
    2897             :            i++) // Add any Jacobian contributions still hanging around
    2898         654 :         _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         594 :       _fe_problem.checkExceptionAndStopSolve();
    2905             : 
    2906         594 :       closeTaggedMatrices(tags);
    2907             : 
    2908         594 :       return;
    2909         594 :     }
    2910             : 
    2911      476371 :     switch (_fe_problem.coupling())
    2912             :     {
    2913      394639 :       case Moose::COUPLING_DIAG:
    2914             :       {
    2915      394639 :         ComputeJacobianThread cj(_fe_problem, tags);
    2916      394639 :         Threads::parallel_reduce(elem_range, cj);
    2917             : 
    2918      394631 :         unsigned int n_threads = libMesh::n_threads();
    2919      830898 :         for (unsigned int i = 0; i < n_threads;
    2920             :              i++) // Add any Jacobian contributions still hanging around
    2921      436267 :           _fe_problem.addCachedJacobian(i);
    2922             : 
    2923             :         // Boundary restricted Nodal Kernels
    2924      394631 :         if (_nodal_kernels.hasActiveBoundaryObjects())
    2925             :         {
    2926          43 :           ComputeNodalKernelBCJacobiansThread cnkjt(_fe_problem, *this, _nodal_kernels, tags);
    2927          43 :           const ConstBndNodeRange & bnd_range = _fe_problem.getCurrentAlgebraicBndNodeRange();
    2928             : 
    2929          43 :           Threads::parallel_reduce(bnd_range, cnkjt);
    2930          43 :           unsigned int n_threads = libMesh::n_threads();
    2931          90 :           for (unsigned int i = 0; i < n_threads;
    2932             :                i++) // Add any cached jacobians that might be hanging around
    2933          47 :             _fe_problem.assembly(i, number()).addCachedJacobian(Assembly::GlobalDataKey{});
    2934          43 :         }
    2935      394631 :       }
    2936      394631 :       break;
    2937             : 
    2938       81732 :       default:
    2939             :       case Moose::COUPLING_CUSTOM:
    2940             :       {
    2941       81732 :         ComputeFullJacobianThread cj(_fe_problem, tags);
    2942       81732 :         Threads::parallel_reduce(elem_range, cj);
    2943       81732 :         unsigned int n_threads = libMesh::n_threads();
    2944             : 
    2945      169769 :         for (unsigned int i = 0; i < n_threads; i++)
    2946       88041 :           _fe_problem.addCachedJacobian(i);
    2947             : 
    2948             :         // Boundary restricted Nodal Kernels
    2949       81728 :         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       81732 :       }
    2961       81728 :       break;
    2962             :     }
    2963             : 
    2964      476359 :     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      952157 :     if ((_fe_problem.restoreOriginalNonzeroPattern() || first) &&
    2970      475802 :         _add_implicit_geometric_coupling_entries_to_jacobian)
    2971             :     {
    2972        2765 :       first = false;
    2973        2765 :       addImplicitGeometricCouplingEntries(_fe_problem.geomSearchData());
    2974             : 
    2975        2765 :       if (_fe_problem.getDisplacedProblem())
    2976         971 :         addImplicitGeometricCouplingEntries(_fe_problem.getDisplacedProblem()->geomSearchData());
    2977             :     }
    2978             :   }
    2979      476355 :   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      476265 :     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        3318 :       auto & system_matrix = getMatrix(systemMatrixTag());
    2991             : #if PETSC_RELEASE_GREATER_EQUALS(3, 23, 0)
    2992             :       SparseMatrix<Number> * view_jac_ptr;
    2993        3318 :       std::unique_ptr<SparseMatrix<Number>> hash_copy;
    2994        3318 :       if (system_matrix.use_hash_table())
    2995             :       {
    2996        2098 :         hash_copy = libMesh::cast_ref<PetscMatrix<Number> &>(system_matrix).copy_from_hash();
    2997        2098 :         view_jac_ptr = hash_copy.get();
    2998             :       }
    2999             :       else
    3000        1220 :         view_jac_ptr = &system_matrix;
    3001        3318 :       auto & jacobian_to_view = *view_jac_ptr;
    3002             : #else
    3003             :       auto & jacobian_to_view = system_matrix;
    3004             : #endif
    3005        3318 :       if (&jacobian_to_view == &system_matrix)
    3006        1220 :         system_matrix.close();
    3007             : 
    3008             :       // Nodal Constraints
    3009        3318 :       enforceNodalConstraintsJacobian();
    3010             : 
    3011             :       // Undisplaced Constraints
    3012        3318 :       constraintJacobians(jacobian_to_view, false);
    3013             : 
    3014             :       // Displaced Constraints
    3015        3318 :       if (_fe_problem.getDisplacedProblem())
    3016         971 :         constraintJacobians(jacobian_to_view, true);
    3017        3318 :     }
    3018             :   }
    3019      476265 :   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      476265 :   if (_has_diag_save_in)
    3024         170 :     _fe_problem.getAuxiliarySystem().solution().close();
    3025             : 
    3026             :   PARALLEL_TRY
    3027             :   {
    3028             :     MooseObjectWarehouse<NodalBCBase> * nbc_warehouse;
    3029             :     // Select nodal kernels
    3030      476265 :     if (tags.size() == _fe_problem.numMatrixTags() || !tags.size())
    3031      467410 :       nbc_warehouse = &_nodal_bcs;
    3032        8855 :     else if (tags.size() == 1)
    3033        7716 :       nbc_warehouse = &(_nodal_bcs.getMatrixTagObjectWarehouse(*(tags.begin()), 0));
    3034             :     else
    3035        1139 :       nbc_warehouse = &(_nodal_bcs.getMatrixTagsObjectWarehouse(tags, 0));
    3036             : 
    3037      476265 :     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      390916 :       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      390916 :       std::map<std::string, std::set<unsigned int>> bc_involved_vars;
    3050      390916 :       const std::set<BoundaryID> & all_boundary_ids = _mesh.getBoundaryIDs();
    3051     1961466 :       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     1570550 :         if (nbc_warehouse->hasActiveBoundaryObjects(bid))
    3056             :         {
    3057      774059 :           const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(bid);
    3058     1623334 :           for (const auto & bc : bcs)
    3059             :           {
    3060             :             const std::vector<MooseVariableFEBase *> & coupled_moose_vars =
    3061      849275 :                 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      849275 :             std::set<unsigned int> & var_set = bc_involved_vars[bc->name()];
    3066      902419 :             for (const auto & coupled_var : coupled_moose_vars)
    3067       53144 :               if (coupled_var->kind() == Moose::VAR_SOLVER)
    3068       51896 :                 var_set.insert(coupled_var->number());
    3069             : 
    3070      849275 :             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      820159 :       for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    3079      429243 :         _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      390916 :       auto & coupling_entries = _fe_problem.couplingEntries(/*_tid=*/0, this->number());
    3087             : 
    3088             :       // Compute Jacobians for NodalBCBases
    3089      390916 :       const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    3090    20315239 :       for (const auto & bnode : bnd_nodes)
    3091             :       {
    3092    19924323 :         BoundaryID boundary_id = bnode->_bnd_id;
    3093    19924323 :         Node * node = bnode->_node;
    3094             : 
    3095    29247365 :         if (nbc_warehouse->hasActiveBoundaryObjects(boundary_id) &&
    3096     9323042 :             node->processor_id() == processor_id())
    3097             :         {
    3098     7100955 :           _fe_problem.reinitNodeFace(node, boundary_id, 0);
    3099             : 
    3100     7100955 :           const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id);
    3101    15094443 :           for (const auto & bc : bcs)
    3102             :           {
    3103             :             // Get the set of involved MOOSE vars for this BC
    3104     7993488 :             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    20100880 :             for (const auto & it : coupling_entries)
    3111             :             {
    3112    12107392 :               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    12107392 :               if ((bc->variable().number() == ivar) && var_set.count(jvar) && bc->shouldApply())
    3119     8075855 :                 bc->computeOffDiagJacobian(jvar);
    3120             :             }
    3121             : 
    3122     7993488 :             const auto & coupled_scalar_vars = bc->getCoupledMooseScalarVars();
    3123     7993815 :             for (const auto & jvariable : coupled_scalar_vars)
    3124         327 :               if (hasScalarVariable(jvariable->name()))
    3125         327 :                 bc->computeOffDiagJacobianScalar(jvariable->number());
    3126             :           }
    3127             :         }
    3128             :       } // end loop over boundary nodes
    3129             : 
    3130             :       // Set the cached NodalBCBase values in the Jacobian matrix
    3131      390916 :       _fe_problem.assembly(0, number()).setCachedJacobian(Assembly::GlobalDataKey{});
    3132      390916 :     }
    3133             :   }
    3134      476265 :   PARALLEL_CATCH;
    3135             : 
    3136      476265 :   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      476265 :   if (_has_nodalbc_diag_save_in)
    3141          21 :     _fe_problem.getAuxiliarySystem().solution().close();
    3142             : 
    3143      476265 :   if (hasDiagSaveIn())
    3144         170 :     _fe_problem.getAuxiliarySystem().update();
    3145             : 
    3146             :   // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
    3147             :   // counters
    3148      476265 :   _app.solutionInvalidity().syncIteration();
    3149      476265 :   _app.solutionInvalidity().solutionInvalidAccumulation();
    3150      477641 : }
    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      476965 : NonlinearSystemBase::computeJacobianTags(const std::set<TagID> & tags)
    3177             : {
    3178      476965 :   TIME_SECTION("computeJacobianTags", 5);
    3179             : 
    3180      476965 :   FloatingPointExceptionGuard fpe_guard(_app);
    3181             : 
    3182             :   try
    3183             :   {
    3184      476965 :     computeJacobianInternal(tags);
    3185             :   }
    3186          94 :   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          90 :   }
    3192      476957 : }
    3193             : 
    3194             : void
    3195         209 : NonlinearSystemBase::computeJacobianBlocks(std::vector<JacobianBlock *> & blocks)
    3196             : {
    3197         209 :   _nl_matrix_tags.clear();
    3198             : 
    3199         209 :   auto & tags = _fe_problem.getMatrixTags();
    3200         627 :   for (auto & tag : tags)
    3201         418 :     _nl_matrix_tags.insert(tag.second);
    3202             : 
    3203         209 :   computeJacobianBlocks(blocks, _nl_matrix_tags);
    3204         209 : }
    3205             : 
    3206             : void
    3207         569 : NonlinearSystemBase::computeJacobianBlocks(std::vector<JacobianBlock *> & blocks,
    3208             :                                            const std::set<TagID> & tags)
    3209             : {
    3210         569 :   TIME_SECTION("computeJacobianBlocks", 3);
    3211         569 :   FloatingPointExceptionGuard fpe_guard(_app);
    3212             : 
    3213        2018 :   for (unsigned int i = 0; i < blocks.size(); i++)
    3214             :   {
    3215        1449 :     SparseMatrix<Number> & jacobian = blocks[i]->_jacobian;
    3216             : 
    3217        1449 :     LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
    3218             :                                   MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
    3219             :                                   PETSC_TRUE));
    3220        1449 :     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        1449 :     jacobian.zero();
    3226             :   }
    3227             : 
    3228        1195 :   for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
    3229         626 :     _fe_problem.reinitScalars(tid);
    3230             : 
    3231             :   PARALLEL_TRY
    3232             :   {
    3233         569 :     const ConstElemRange & elem_range = _fe_problem.getCurrentAlgebraicElementRange();
    3234         569 :     ComputeJacobianBlocksThread cjb(_fe_problem, blocks, tags);
    3235         569 :     Threads::parallel_reduce(elem_range, cjb);
    3236         569 :   }
    3237         569 :   PARALLEL_CATCH;
    3238             : 
    3239        2018 :   for (unsigned int i = 0; i < blocks.size(); i++)
    3240        1449 :     blocks[i]->_jacobian.close();
    3241             : 
    3242        2018 :   for (unsigned int i = 0; i < blocks.size(); i++)
    3243             :   {
    3244        1449 :     libMesh::System & precond_system = blocks[i]->_precond_system;
    3245        1449 :     SparseMatrix<Number> & jacobian = blocks[i]->_jacobian;
    3246             : 
    3247        1449 :     unsigned int ivar = blocks[i]->_ivar;
    3248        1449 :     unsigned int jvar = blocks[i]->_jvar;
    3249             : 
    3250             :     // Dirichlet BCs
    3251        1449 :     std::vector<numeric_index_type> zero_rows;
    3252             :     PARALLEL_TRY
    3253             :     {
    3254        1449 :       const ConstBndNodeRange & bnd_nodes = _fe_problem.getCurrentAlgebraicBndNodeRange();
    3255       47453 :       for (const auto & bnode : bnd_nodes)
    3256             :       {
    3257       46004 :         BoundaryID boundary_id = bnode->_bnd_id;
    3258       46004 :         Node * node = bnode->_node;
    3259             : 
    3260       46004 :         if (_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
    3261             :         {
    3262       39824 :           const auto & bcs = _nodal_bcs.getActiveBoundaryObjects(boundary_id);
    3263             : 
    3264       39824 :           if (node->processor_id() == processor_id())
    3265             :           {
    3266       30748 :             _fe_problem.reinitNodeFace(node, boundary_id, 0);
    3267             : 
    3268      152150 :             for (const auto & bc : bcs)
    3269      121402 :               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       46216 :                 zero_rows.push_back(node->dof_number(precond_system.number(), 0, 0));
    3274             :               }
    3275             :           }
    3276             :         }
    3277             :       }
    3278             :     }
    3279        1449 :     PARALLEL_CATCH;
    3280             : 
    3281        1449 :     jacobian.close();
    3282             : 
    3283             :     // This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
    3284        1449 :     if (ivar == jvar)
    3285        1342 :       jacobian.zero_rows(zero_rows, 1.0);
    3286             :     else
    3287         107 :       jacobian.zero_rows(zero_rows, 0.0);
    3288             : 
    3289        1449 :     jacobian.close();
    3290        1449 :   }
    3291         569 : }
    3292             : 
    3293             : void
    3294      335546 : NonlinearSystemBase::updateActive(THREAD_ID tid)
    3295             : {
    3296      335546 :   _element_dampers.updateActive(tid);
    3297      335546 :   _nodal_dampers.updateActive(tid);
    3298      335546 :   _integrated_bcs.updateActive(tid);
    3299      335546 :   _dg_kernels.updateActive(tid);
    3300      335546 :   _interface_kernels.updateActive(tid);
    3301      335546 :   _dirac_kernels.updateActive(tid);
    3302      335546 :   _kernels.updateActive(tid);
    3303      335546 :   _nodal_kernels.updateActive(tid);
    3304      335546 :   if (tid == 0)
    3305             :   {
    3306      306062 :     _general_dampers.updateActive();
    3307      306062 :     _nodal_bcs.updateActive();
    3308      306062 :     _preset_nodal_bcs.updateActive();
    3309      306062 :     _ad_preset_nodal_bcs.updateActive();
    3310      306062 :     _constraints.updateActive();
    3311      306062 :     _scalar_kernels.updateActive();
    3312             :   }
    3313      335546 : }
    3314             : 
    3315             : Real
    3316        1394 : NonlinearSystemBase::computeDamping(const NumericVector<Number> & solution,
    3317             :                                     const NumericVector<Number> & update)
    3318             : {
    3319             :   // Default to no damping
    3320        1394 :   Real damping = 1.0;
    3321        1394 :   bool has_active_dampers = false;
    3322             : 
    3323             :   try
    3324             :   {
    3325        1394 :     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        1344 :     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        1288 :     if (_general_dampers.hasActiveObjects())
    3355             :     {
    3356             :       PARALLEL_TRY
    3357             :       {
    3358         386 :         TIME_SECTION("computeDamping::general", 3, "Computing General Damping");
    3359             : 
    3360         386 :         has_active_dampers = true;
    3361         386 :         const auto & gdampers = _general_dampers.getActiveObjects();
    3362         772 :         for (const auto & damper : gdampers)
    3363             :         {
    3364         386 :           Real gd_damping = damper->computeDamping(solution, update);
    3365             :           try
    3366             :           {
    3367         386 :             damper->checkMinDamping(gd_damping);
    3368             :           }
    3369           8 :           catch (MooseException & e)
    3370             :           {
    3371           8 :             _fe_problem.setException(e.what());
    3372           8 :           }
    3373         386 :           damping = std::min(gd_damping, damping);
    3374             :         }
    3375         386 :       }
    3376         386 :       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        1394 :   _communicator.min(damping);
    3387             : 
    3388        1394 :   if (has_active_dampers && damping < 1.0)
    3389         977 :     _console << " Damping factor: " << damping << std::endl;
    3390             : 
    3391        1394 :   return damping;
    3392             : }
    3393             : 
    3394             : void
    3395     3516718 : NonlinearSystemBase::computeDiracContributions(const std::set<TagID> & tags, bool is_jacobian)
    3396             : {
    3397     3516718 :   _fe_problem.clearDiracInfo();
    3398             : 
    3399     3516718 :   std::set<const Elem *> dirac_elements;
    3400             : 
    3401     3516718 :   if (_dirac_kernels.hasActiveObjects())
    3402             :   {
    3403       35854 :     TIME_SECTION("computeDirac", 3, "Computing DiracKernels");
    3404             : 
    3405             :     // TODO: Need a threading fix... but it's complicated!
    3406       74756 :     for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
    3407             :     {
    3408       38918 :       const auto & dkernels = _dirac_kernels.getActiveObjects(tid);
    3409       90924 :       for (const auto & dkernel : dkernels)
    3410             :       {
    3411       52022 :         dkernel->clearPoints();
    3412       52022 :         dkernel->addPoints();
    3413             :       }
    3414             :     }
    3415             : 
    3416       35838 :     ComputeDiracThread cd(_fe_problem, tags, is_jacobian);
    3417             : 
    3418       35838 :     _fe_problem.getDiracElements(dirac_elements);
    3419             : 
    3420       35838 :     DistElemRange range(dirac_elements.begin(), dirac_elements.end(), 1);
    3421             :     // TODO: Make Dirac work thread!
    3422             :     // Threads::parallel_reduce(range, cd);
    3423             : 
    3424       35838 :     cd(range);
    3425       35838 :   }
    3426     3516702 : }
    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         333 : NonlinearSystemBase::residualGhosted()
    3439             : {
    3440         333 :   _need_residual_ghosted = true;
    3441         333 :   if (!_residual_ghosted)
    3442             :   {
    3443             :     // The first time we realize we need a ghosted residual vector,
    3444             :     // we add it.
    3445         265 :     _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         265 :     if (_Re_time)
    3454             :     {
    3455          48 :       const auto vector_name = _subproblem.vectorTagName(_Re_time_tag);
    3456          48 :       _Re_time = &system().add_vector(vector_name, false, GHOSTED);
    3457          48 :     }
    3458         265 :     if (_Re_non_time)
    3459             :     {
    3460         265 :       const auto vector_name = _subproblem.vectorTagName(_Re_non_time_tag);
    3461         265 :       _Re_non_time = &system().add_vector(vector_name, false, GHOSTED);
    3462         265 :     }
    3463             :   }
    3464         333 :   return *_residual_ghosted;
    3465             : }
    3466             : 
    3467             : void
    3468       61920 : NonlinearSystemBase::augmentSparsity(SparsityPattern::Graph & sparsity,
    3469             :                                      std::vector<dof_id_type> & n_nz,
    3470             :                                      std::vector<dof_id_type> & n_oz)
    3471             : {
    3472       61920 :   if (_add_implicit_geometric_coupling_entries_to_jacobian)
    3473             :   {
    3474         840 :     _fe_problem.updateGeomSearch();
    3475             : 
    3476         840 :     std::unordered_map<dof_id_type, std::vector<dof_id_type>> graph;
    3477             : 
    3478         840 :     findImplicitGeometricCouplingEntries(_fe_problem.geomSearchData(), graph);
    3479             : 
    3480         840 :     if (_fe_problem.getDisplacedProblem())
    3481          33 :       findImplicitGeometricCouplingEntries(_fe_problem.getDisplacedProblem()->geomSearchData(),
    3482             :                                            graph);
    3483             : 
    3484         840 :     const dof_id_type first_dof_on_proc = dofMap().first_dof(processor_id());
    3485         840 :     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         840 :     const dof_id_type n_dofs_on_proc = dofMap().n_local_dofs();
    3489         840 :     const dof_id_type n_dofs_not_on_proc = dofMap().n_dofs() - dofMap().n_local_dofs();
    3490             : 
    3491        1626 :     for (const auto & git : graph)
    3492             :     {
    3493         786 :       dof_id_type dof = git.first;
    3494         786 :       dof_id_type local_dof = dof - first_dof_on_proc;
    3495             : 
    3496         786 :       if (dof < first_dof_on_proc || dof >= end_dof_on_proc)
    3497         126 :         continue;
    3498             : 
    3499         660 :       const auto & row = git.second;
    3500             : 
    3501         660 :       SparsityPattern::Row & sparsity_row = sparsity[local_dof];
    3502             : 
    3503         660 :       unsigned int original_row_length = sparsity_row.size();
    3504             : 
    3505         660 :       sparsity_row.insert(sparsity_row.end(), row.begin(), row.end());
    3506             : 
    3507        1320 :       SparsityPattern::sort_row(
    3508         660 :           sparsity_row.begin(), sparsity_row.begin() + original_row_length, sparsity_row.end());
    3509             : 
    3510             :       // Fix up nonzero arrays
    3511        4332 :       for (const auto & coupled_dof : row)
    3512             :       {
    3513        3672 :         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        3060 :           if (n_nz[local_dof] < n_dofs_on_proc)
    3521        3060 :             n_nz[local_dof]++;
    3522             :         }
    3523             :       }
    3524             :     }
    3525         840 :   }
    3526       61920 : }
    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       13492 : NonlinearSystemBase::setPreconditioner(std::shared_ptr<MoosePreconditioner> pc)
    3554             : {
    3555       13492 :   if (_preconditioner.get() != nullptr)
    3556           7 :     mooseError("More than one active Preconditioner detected");
    3557             : 
    3558       13485 :   _preconditioner = pc;
    3559       13485 : }
    3560             : 
    3561             : MoosePreconditioner const *
    3562       49740 : NonlinearSystemBase::getPreconditioner() const
    3563             : {
    3564       49740 :   return _preconditioner.get();
    3565             : }
    3566             : 
    3567             : void
    3568         320 : NonlinearSystemBase::setupDampers()
    3569             : {
    3570         320 :   _increment_vec = &_sys.add_vector("u_increment", true, GHOSTED);
    3571         320 : }
    3572             : 
    3573             : void
    3574        1752 : NonlinearSystemBase::reinitIncrementAtQpsForDampers(THREAD_ID /*tid*/,
    3575             :                                                     const std::set<MooseVariable *> & damped_vars)
    3576             : {
    3577        3526 :   for (const auto & var : damped_vars)
    3578        1774 :     var->computeIncrementAtQps(*_increment_vec);
    3579        1752 : }
    3580             : 
    3581             : void
    3582        7440 : NonlinearSystemBase::reinitIncrementAtNodeForDampers(THREAD_ID /*tid*/,
    3583             :                                                      const std::set<MooseVariable *> & damped_vars)
    3584             : {
    3585       14880 :   for (const auto & var : damped_vars)
    3586        7440 :     var->computeIncrementAtNode(*_increment_vec);
    3587        7440 : }
    3588             : 
    3589             : void
    3590       39593 : NonlinearSystemBase::checkKernelCoverage(const std::set<SubdomainID> & mesh_subdomains) const
    3591             : {
    3592             :   // Obtain all blocks and variables covered by all kernels
    3593       39593 :   std::set<SubdomainID> input_subdomains;
    3594       39593 :   std::set<std::string> kernel_variables;
    3595             : 
    3596       39593 :   bool global_kernels_exist = false;
    3597       39593 :   global_kernels_exist |= _scalar_kernels.hasActiveObjects();
    3598       39593 :   global_kernels_exist |= _nodal_kernels.hasActiveObjects();
    3599             : 
    3600       39593 :   _kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3601       39593 :   _dg_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3602       39593 :   _nodal_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3603       39593 :   _scalar_kernels.subdomainsCovered(input_subdomains, kernel_variables);
    3604       39593 :   _constraints.subdomainsCovered(input_subdomains, kernel_variables);
    3605             : 
    3606       39593 :   if (_fe_problem.haveFV())
    3607             :   {
    3608        3314 :     std::vector<FVElementalKernel *> fv_elemental_kernels;
    3609        3314 :     _fe_problem.theWarehouse()
    3610        6628 :         .query()
    3611        3314 :         .template condition<AttribSystem>("FVElementalKernel")
    3612        3314 :         .queryInto(fv_elemental_kernels);
    3613             : 
    3614        7135 :     for (auto fv_kernel : fv_elemental_kernels)
    3615             :     {
    3616        3821 :       if (fv_kernel->blockRestricted())
    3617        1910 :         for (auto block_id : fv_kernel->blockIDs())
    3618        1070 :           input_subdomains.insert(block_id);
    3619             :       else
    3620        2981 :         global_kernels_exist = true;
    3621        3821 :       kernel_variables.insert(fv_kernel->variable().name());
    3622             : 
    3623             :       // Check for lagrange multiplier
    3624        3821 :       if (dynamic_cast<FVScalarLagrangeMultiplierConstraint *>(fv_kernel))
    3625         126 :         kernel_variables.insert(dynamic_cast<FVScalarLagrangeMultiplierConstraint *>(fv_kernel)
    3626         252 :                                     ->lambdaVariable()
    3627         126 :                                     .name());
    3628             :     }
    3629             : 
    3630        3314 :     std::vector<FVFluxKernel *> fv_flux_kernels;
    3631        3314 :     _fe_problem.theWarehouse()
    3632        6628 :         .query()
    3633        3314 :         .template condition<AttribSystem>("FVFluxKernel")
    3634        3314 :         .queryInto(fv_flux_kernels);
    3635             : 
    3636        8316 :     for (auto fv_kernel : fv_flux_kernels)
    3637             :     {
    3638        5002 :       if (fv_kernel->blockRestricted())
    3639        2262 :         for (auto block_id : fv_kernel->blockIDs())
    3640        1204 :           input_subdomains.insert(block_id);
    3641             :       else
    3642        3944 :         global_kernels_exist = true;
    3643        5002 :       kernel_variables.insert(fv_kernel->variable().name());
    3644             :     }
    3645             : 
    3646        3314 :     std::vector<FVInterfaceKernel *> fv_interface_kernels;
    3647        3314 :     _fe_problem.theWarehouse()
    3648        6628 :         .query()
    3649        3314 :         .template condition<AttribSystem>("FVInterfaceKernel")
    3650        3314 :         .queryInto(fv_interface_kernels);
    3651             : 
    3652        3607 :     for (auto fvik : fv_interface_kernels)
    3653         293 :       if (auto scalar_fvik = dynamic_cast<FVScalarLagrangeMultiplierInterface *>(fvik))
    3654          13 :         kernel_variables.insert(scalar_fvik->lambdaVariable().name());
    3655             : 
    3656        3314 :     std::vector<FVFluxBC *> fv_flux_bcs;
    3657        3314 :     _fe_problem.theWarehouse()
    3658        6628 :         .query()
    3659        3314 :         .template condition<AttribSystem>("FVFluxBC")
    3660        3314 :         .queryInto(fv_flux_bcs);
    3661             : 
    3662        5264 :     for (auto fvbc : fv_flux_bcs)
    3663        1950 :       if (auto scalar_fvbc = dynamic_cast<FVBoundaryScalarLagrangeMultiplierConstraint *>(fvbc))
    3664          13 :         kernel_variables.insert(scalar_fvbc->lambdaVariable().name());
    3665        3314 :   }
    3666             : 
    3667             :   // Check kernel coverage of subdomains (blocks) in your mesh
    3668       39593 :   if (!global_kernels_exist)
    3669             :   {
    3670       35856 :     std::set<SubdomainID> difference;
    3671       35856 :     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       36076 :     for (const auto & id : _mesh.interiorLowerDBlocks())
    3679         220 :       difference.erase(id);
    3680       36076 :     for (const auto & id : _mesh.boundaryLowerDBlocks())
    3681         220 :       difference.erase(id);
    3682             : 
    3683       35856 :     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       35848 :   }
    3705             : 
    3706             :   // Check kernel use of variables
    3707       39585 :   std::set<VariableName> variables(getVariableNames().begin(), getVariableNames().end());
    3708             : 
    3709       39585 :   std::set<VariableName> difference;
    3710       39585 :   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       39585 :   std::set<VariableName> vars(difference);
    3718       39921 :   for (auto & var_name : vars)
    3719             :   {
    3720         336 :     auto blks = getSubdomainsForVar(var_name);
    3721         688 :     for (const auto & id : blks)
    3722         352 :       if (_mesh.interiorLowerDBlocks().count(id) > 0 || _mesh.boundaryLowerDBlocks().count(id) > 0)
    3723         352 :         difference.erase(var_name);
    3724         336 :   }
    3725             : 
    3726       39585 :   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       39577 : }
    3737             : 
    3738             : bool
    3739       26648 : NonlinearSystemBase::containsTimeKernel()
    3740             : {
    3741       26648 :   auto & time_kernels = _kernels.getVectorTagObjectWarehouse(timeVectorTag(), 0);
    3742             : 
    3743       26648 :   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       25340 : NonlinearSystemBase::needBoundaryMaterialOnSide(BoundaryID bnd_id, THREAD_ID tid) const
    3760             : {
    3761       25340 :   return _integrated_bcs.hasActiveBoundaryObjects(bnd_id, tid);
    3762             : }
    3763             : 
    3764             : bool
    3765        1203 : NonlinearSystemBase::needInterfaceMaterialOnSide(BoundaryID bnd_id, THREAD_ID tid) const
    3766             : {
    3767        1203 :   return _interface_kernels.hasActiveBoundaryObjects(bnd_id, tid);
    3768             : }
    3769             : 
    3770             : bool
    3771       11309 : NonlinearSystemBase::needSubdomainMaterialOnSide(SubdomainID /*subdomain_id*/,
    3772             :                                                  THREAD_ID /*tid*/) const
    3773             : {
    3774       11309 :   return _doing_dg;
    3775             : }
    3776             : 
    3777             : bool
    3778           0 : NonlinearSystemBase::doingDG() const
    3779             : {
    3780           0 :   return _doing_dg;
    3781             : }
    3782             : 
    3783             : void
    3784         506 : NonlinearSystemBase::setPreviousNewtonSolution(const NumericVector<Number> & soln)
    3785             : {
    3786         506 :   if (hasVector(Moose::PREVIOUS_NL_SOLUTION_TAG))
    3787         506 :     getVector(Moose::PREVIOUS_NL_SOLUTION_TAG) = soln;
    3788         506 : }
    3789             : 
    3790             : void
    3791     3520669 : 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     3529370 :     for (auto & map_pr : _undisplaced_mortar_functors)
    3800        8701 :       map_pr.second(compute_type, vector_tags, matrix_tags);
    3801             : 
    3802     3525030 :     for (auto & map_pr : _displaced_mortar_functors)
    3803        4361 :       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     3520669 : }
    3813             : 
    3814             : void
    3815         431 : NonlinearSystemBase::setupScalingData()
    3816             : {
    3817         431 :   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         431 :   const auto n_vars = system().n_vars();
    3822             : 
    3823         431 :   if (_scaling_group_variables.empty())
    3824             :   {
    3825         420 :     _var_to_group_var.reserve(n_vars);
    3826         420 :     _num_scaling_groups = n_vars;
    3827             : 
    3828        1109 :     for (const auto var_number : make_range(n_vars))
    3829         689 :       _var_to_group_var.emplace(var_number, var_number);
    3830             :   }
    3831             :   else
    3832             :   {
    3833          11 :     std::set<unsigned int> var_numbers, var_numbers_covered, var_numbers_not_covered;
    3834          44 :     for (const auto var_number : make_range(n_vars))
    3835          33 :       var_numbers.insert(var_number);
    3836             : 
    3837          11 :     _num_scaling_groups = _scaling_group_variables.size();
    3838             : 
    3839          22 :     for (const auto group_index : index_range(_scaling_group_variables))
    3840          44 :       for (const auto & var_name : _scaling_group_variables[group_index])
    3841             :       {
    3842          33 :         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          33 :             hasVariable(var_name)
    3850          22 :                 ? static_cast<MooseVariableBase &>(getVariable(0, var_name))
    3851          55 :                 : static_cast<MooseVariableBase &>(getScalarVariable(0, var_name));
    3852          33 :         auto map_pair = _var_to_group_var.emplace(var.number(), group_index);
    3853          33 :         if (!map_pair.second)
    3854           0 :           mooseError("Variable ", var_name, " is contained in multiple scaling grouplings");
    3855          33 :         var_numbers_covered.insert(var.number());
    3856             :       }
    3857             : 
    3858          11 :     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          11 :     _num_scaling_groups = _scaling_group_variables.size() + var_numbers_not_covered.size();
    3865             : 
    3866          11 :     auto index = static_cast<unsigned int>(_scaling_group_variables.size());
    3867          11 :     for (auto var_number : var_numbers_not_covered)
    3868           0 :       _var_to_group_var.emplace(var_number, index++);
    3869          11 :   }
    3870             : 
    3871         431 :   _variable_autoscaled.resize(n_vars, true);
    3872         431 :   const auto & number_to_var_map = _vars[0].numberToVariableMap();
    3873             : 
    3874         431 :   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         431 :   _auto_scaling_initd = true;
    3883             : }
    3884             : 
    3885             : bool
    3886        1326 : NonlinearSystemBase::computeScaling()
    3887             : {
    3888        1326 :   if (_compute_scaling_once && _computed_scaling)
    3889         682 :     return true;
    3890             : 
    3891         644 :   _console << "\nPerforming automatic scaling calculation\n" << std::endl;
    3892             : 
    3893         644 :   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         644 :   assembleScalingVector();
    3898             : 
    3899             :   // container for repeated access of element global dof indices
    3900         644 :   std::vector<dof_id_type> dof_indices;
    3901             : 
    3902         644 :   if (!_auto_scaling_initd)
    3903         431 :     setupScalingData();
    3904             : 
    3905         644 :   std::vector<Real> inverse_scaling_factors(_num_scaling_groups, 0);
    3906         644 :   std::vector<Real> resid_inverse_scaling_factors(_num_scaling_groups, 0);
    3907         644 :   std::vector<Real> jac_inverse_scaling_factors(_num_scaling_groups, 0);
    3908         644 :   auto & dof_map = dofMap();
    3909             : 
    3910             :   // what types of scaling do we want?
    3911         644 :   bool jac_scaling = _resid_vs_jac_scaling_param < 1. - TOLERANCE;
    3912         644 :   bool resid_scaling = _resid_vs_jac_scaling_param > TOLERANCE;
    3913             : 
    3914         644 :   const NumericVector<Number> & scaling_residual = RHS();
    3915             : 
    3916         644 :   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         594 :       auto init_vector = NumericVector<Number>::build(this->comm());
    3926         594 :       init_vector->init(system().n_dofs(), system().n_local_dofs(), /*fast=*/false, PARALLEL);
    3927             : 
    3928         594 :       _scaling_matrix->clear();
    3929         594 :       _scaling_matrix->init(*init_vector);
    3930         594 :     }
    3931             : 
    3932         594 :     _fe_problem.computingScalingJacobian(true);
    3933             :     // Dispatch to derived classes to ensure that we use the correct matrix tag
    3934         594 :     computeScalingJacobian();
    3935         594 :     _fe_problem.computingScalingJacobian(false);
    3936             :   }
    3937             : 
    3938         644 :   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         644 :   if (_fe_problem.getFailNextNonlinearConvergenceCheck())
    3950           0 :     return false;
    3951             : 
    3952      227723 :   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     4509906 :                               &scaling_residual](const auto & dof_indices, const auto var_number)
    3959             :   {
    3960     1133513 :     for (auto dof_index : dof_indices)
    3961      905790 :       if (dof_map.local_index(dof_index))
    3962             :       {
    3963      901029 :         if (jac_scaling)
    3964             :         {
    3965             :           // For now we will use the diagonal for determining scaling
    3966      896912 :           auto mat_value = (*_scaling_matrix)(dof_index, dof_index);
    3967      896912 :           auto & factor = jac_inverse_scaling_factors[_var_to_group_var[var_number]];
    3968      896912 :           factor = std::max(factor, std::abs(mat_value));
    3969             :         }
    3970      901029 :         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      227723 :   };
    3978             : 
    3979             :   // Compute our scaling factors for the spatial field variables
    3980       81684 :   for (const auto & elem : _fe_problem.getCurrentAlgebraicElementRange())
    3981      309617 :     for (const auto i : make_range(system().n_vars()))
    3982      228577 :       if (_variable_autoscaled[i] && system().variable_type(i).family != SCALAR)
    3983             :       {
    3984      227633 :         dof_map.dof_indices(elem, dof_indices, i);
    3985      227633 :         examine_dof_indices(dof_indices, i);
    3986             :       }
    3987             : 
    3988        1689 :   for (const auto i : make_range(system().n_vars()))
    3989        1045 :     if (_variable_autoscaled[i] && system().variable_type(i).family == SCALAR)
    3990             :     {
    3991          90 :       dof_map.SCALAR_dof_indices(dof_indices, i);
    3992          90 :       examine_dof_indices(dof_indices, i);
    3993             :     }
    3994             : 
    3995         644 :   if (resid_scaling)
    3996          50 :     _communicator.max(resid_inverse_scaling_factors);
    3997         644 :   if (jac_scaling)
    3998         594 :     _communicator.max(jac_inverse_scaling_factors);
    3999             : 
    4000         644 :   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         644 :   else if (jac_scaling)
    4020         594 :     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        1667 :   for (auto & scaling_factor : inverse_scaling_factors)
    4028        1023 :     if (scaling_factor == 0)
    4029          40 :       scaling_factor = 1;
    4030             : 
    4031             :   // Now flatten the group scaling factors to the individual variable scaling factors
    4032         644 :   std::vector<Real> flattened_inverse_scaling_factors(system().n_vars());
    4033        1689 :   for (const auto i : index_range(flattened_inverse_scaling_factors))
    4034        1045 :     flattened_inverse_scaling_factors[i] = inverse_scaling_factors[_var_to_group_var[i]];
    4035             : 
    4036             :   // Now set the scaling factors for the variables
    4037         644 :   applyScalingFactors(flattened_inverse_scaling_factors);
    4038         644 :   if (auto displaced_problem = _fe_problem.getDisplacedProblem().get())
    4039          62 :     displaced_problem->systemBaseNonlinear(number()).applyScalingFactors(
    4040             :         flattened_inverse_scaling_factors);
    4041             : 
    4042         644 :   _computed_scaling = true;
    4043         644 :   return true;
    4044         644 : }
    4045             : 
    4046             : void
    4047      287113 : NonlinearSystemBase::assembleScalingVector()
    4048             : {
    4049      287113 :   if (!hasVector("scaling_factors"))
    4050             :     // No variables have indicated they need scaling
    4051      286599 :     return;
    4052             : 
    4053         514 :   auto & scaling_vector = getVector("scaling_factors");
    4054             : 
    4055         514 :   const auto & lm_mesh = _mesh.getMesh();
    4056         514 :   const auto & dof_map = dofMap();
    4057             : 
    4058         514 :   const auto & field_variables = _vars[0].fieldVariables();
    4059         514 :   const auto & scalar_variables = _vars[0].scalars();
    4060             : 
    4061         514 :   std::vector<dof_id_type> dof_indices;
    4062             : 
    4063         514 :   for (const Elem * const elem :
    4064       23884 :        as_range(lm_mesh.active_local_elements_begin(), lm_mesh.active_local_elements_end()))
    4065       28472 :     for (const auto * const field_var : field_variables)
    4066             :     {
    4067       17044 :       const auto & factors = field_var->arrayScalingFactor();
    4068       34088 :       for (const auto i : make_range(field_var->count()))
    4069             :       {
    4070       17044 :         dof_map.dof_indices(elem, dof_indices, field_var->number() + i);
    4071       70840 :         for (const auto dof : dof_indices)
    4072       53796 :           scaling_vector.set(dof, factors[i]);
    4073             :       }
    4074         514 :     }
    4075             : 
    4076         620 :   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         106 :     dof_map.SCALAR_dof_indices(dof_indices, scalar_var->number());
    4081         212 :     for (const auto dof : dof_indices)
    4082         106 :       scaling_vector.set(dof, scalar_var->scalingFactor());
    4083             :   }
    4084             : 
    4085             :   // Parallel assemble
    4086         514 :   scaling_vector.close();
    4087             : 
    4088         514 :   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         514 : }
    4092             : 
    4093             : bool
    4094      286469 : NonlinearSystemBase::preSolve()
    4095             : {
    4096             :   // Clear the iteration counters
    4097      286469 :   _current_l_its.clear();
    4098      286469 :   _current_nl_its = 0;
    4099             : 
    4100             :   // Initialize the solution vector using a predictor and known values from nodal bcs
    4101      286469 :   setInitialSolution();
    4102             : 
    4103             :   // Now that the initial solution has ben set, potentially perform a residual/Jacobian evaluation
    4104             :   // to determine variable scaling factors
    4105      286469 :   if (_automatic_scaling)
    4106             :   {
    4107        1326 :     const bool scaling_succeeded = computeScaling();
    4108        1326 :     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      286469 :   assembleScalingVector();
    4115             : 
    4116      286469 :   return true;
    4117             : }
    4118             : 
    4119             : void
    4120        5118 : NonlinearSystemBase::destroyColoring()
    4121             : {
    4122        5118 :   if (matrixFromColoring())
    4123          99 :     LibmeshPetscCall(MatFDColoringDestroy(&_fdcoloring));
    4124        5118 : }

Generated by: LCOV version 1.14