https://mooseframework.inl.gov
NonlinearSystemBase.C
Go to the documentation of this file.
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"
23 #include "ComputeFVFluxThread.h"
24 #include "ComputeJacobianThread.h"
28 #include "ComputeDiracThread.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"
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"
69 #include "ADKernel.h"
70 #include "ADDirichletBCBase.h"
71 #include "Moose.h"
72 #include "ConsoleStream.h"
73 #include "MooseError.h"
74 #include "FVElementalKernel.h"
77 #include "FVFluxKernel.h"
78 #include "FVBoundaryCondition.h"
79 #include "FVInterfaceKernel.h"
81 #include "GeneralUserObject.h"
83 #include "HDGKernel.h"
85 
86 // libMesh
87 #include "libmesh/nonlinear_solver.h"
88 #include "libmesh/quadrature_gauss.h"
89 #include "libmesh/dense_vector.h"
90 #include "libmesh/boundary_info.h"
91 #include "libmesh/petsc_matrix.h"
92 #include "libmesh/petsc_vector.h"
93 #include "libmesh/petsc_nonlinear_solver.h"
94 #include "libmesh/numeric_vector.h"
95 #include "libmesh/mesh.h"
96 #include "libmesh/dense_subvector.h"
97 #include "libmesh/dense_submatrix.h"
98 #include "libmesh/dof_map.h"
99 #include "libmesh/sparse_matrix.h"
100 #include "libmesh/petsc_matrix.h"
101 #include "libmesh/default_coupling.h"
102 #include "libmesh/diagonal_matrix.h"
103 #include "libmesh/fe_interface.h"
104 #include "libmesh/petsc_solver_exception.h"
105 
106 #include <ios>
107 #include <type_traits>
108 
109 #include "petscsnes.h"
110 #include <PetscDMMoose.h>
111 EXTERN_C_BEGIN
112 extern PetscErrorCode DMCreate_Moose(DM);
113 EXTERN_C_END
114 
115 using namespace libMesh;
116 
117 namespace
118 {
119 template <typename T>
120 void
121 appendFVSetupObjects(TheWarehouse & warehouse,
122  const std::string & system_name,
123  const unsigned int system_number,
124  const THREAD_ID tid,
125  std::vector<SetupInterface *> & results)
126 {
127  static_assert(std::is_base_of_v<MooseObject, T>);
128  static_assert(std::is_base_of_v<SetupInterface, T>);
129 
130  std::vector<T *> objects;
131  warehouse.query()
132  .template condition<AttribSystem>(system_name)
133  .template condition<AttribSysNum>(system_number)
134  .template condition<AttribThread>(tid)
135  .queryInto(objects);
136 
137  for (auto * object : objects)
138  results.push_back(object);
139 }
140 }
141 
143  System & sys,
144  const std::string & name)
145  : SolverSystem(fe_problem, fe_problem, name, Moose::VAR_SOLVER),
146  PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "NonlinearSystemBase"),
147  _sys(sys),
148  _last_nl_rnorm(0.),
149  _current_nl_its(0),
150  _residual_ghosted(NULL),
151  _Re_time_tag(-1),
152  _Re_time(NULL),
153  _Re_non_time_tag(-1),
154  _Re_non_time(NULL),
155  _scalar_kernels(/*threaded=*/false),
156  _nodal_bcs(/*threaded=*/false),
157  _preset_nodal_bcs(/*threaded=*/false),
158  _ad_preset_nodal_bcs(/*threaded=*/false),
159 #ifdef MOOSE_KOKKOS_ENABLED
160  _kokkos_kernels(/*threaded=*/false),
161  _kokkos_integrated_bcs(/*threaded=*/false),
162  _kokkos_nodal_bcs(/*threaded=*/false),
163  _kokkos_preset_nodal_bcs(/*threaded=*/false),
164  _kokkos_nodal_kernels(/*threaded=*/false),
165 #endif
166  _general_dampers(/*threaded=*/false),
167  _splits(/*threaded=*/false),
168  _increment_vec(NULL),
169  _use_finite_differenced_preconditioner(false),
170  _fdcoloring(nullptr),
171  _fsp(nullptr),
172  _add_implicit_geometric_coupling_entries_to_jacobian(false),
173  _assemble_constraints_separately(false),
174  _need_residual_ghosted(false),
175  _debugging_residuals(false),
176  _doing_dg(false),
177  _n_iters(0),
178  _n_linear_iters(0),
179  _n_residual_evaluations(0),
180  _final_residual(0.),
181  _computing_pre_smo_residual(false),
182  _pre_smo_residual(0),
183  _initial_residual(0),
184  _use_pre_smo_residual(false),
185  _print_all_var_norms(false),
186  _has_save_in(false),
187  _has_diag_save_in(false),
188  _has_nodalbc_save_in(false),
189  _has_nodalbc_diag_save_in(false),
190  _computed_scaling(false),
191  _compute_scaling_once(true),
192  _resid_vs_jac_scaling_param(0),
193  _off_diagonals_in_auto_scaling(false),
194  _auto_scaling_initd(false)
195 {
197  // Don't need to add the matrix - it already exists (for now)
199 
200  // The time matrix tag is not normally used - but must be added to the system
201  // in case it is so that objects can have 'time' in their matrix tags by default
202  _fe_problem.addMatrixTag("TIME");
203 
204  _Re_tag = _fe_problem.addVectorTag("RESIDUAL");
205 
207 
209  {
210  auto & dof_map = _sys.get_dof_map();
211  dof_map.remove_algebraic_ghosting_functor(dof_map.default_algebraic_ghosting());
212  dof_map.set_implicit_neighbor_dofs(false);
213  }
214 }
215 
217 
218 void
220 {
222 
223  if (_fe_problem.hasDampers())
224  setupDampers();
225 
226  if (_residual_copy.get())
227  _residual_copy->init(_sys.n_dofs(), false, SERIAL);
228 
229 #ifdef MOOSE_KOKKOS_ENABLED
232 #endif
233 }
234 
235 void
237 {
238  // reinit is called on meshChanged() in FEProblemBase. We could implement meshChanged() instead.
239  // Subdomains might have changed
240  for (auto & functor : _displaced_mortar_functors)
241  functor.second.setupMortarMaterials();
242  for (auto & functor : _undisplaced_mortar_functors)
243  functor.second.setupMortarMaterials();
244 }
245 
246 void
248 {
250  nonlinearSolver()->jacobian = NULL;
251 }
252 
253 std::vector<SetupInterface *>
255 {
256  std::vector<SetupInterface *> fv_objects;
257  auto & warehouse = _fe_problem.theWarehouse();
258 
259  appendFVSetupObjects<FVElementalKernel>(
260  warehouse, "FVElementalKernel", number(), tid, fv_objects);
261  appendFVSetupObjects<FVFluxKernel>(warehouse, "FVFluxKernel", number(), tid, fv_objects);
262  appendFVSetupObjects<FVBoundaryCondition>(warehouse, "FVDirichletBC", number(), tid, fv_objects);
263  appendFVSetupObjects<FVBoundaryCondition>(warehouse, "FVFluxBC", number(), tid, fv_objects);
264  appendFVSetupObjects<FVInterfaceKernel>(
265  warehouse, "FVInterfaceKernel", number(), tid, fv_objects);
266 
267  return fv_objects;
268 }
269 
270 void
272 {
273  TIME_SECTION("nlInitialSetup", 2, "Setting Up Nonlinear System");
274 
276 
277  {
278  TIME_SECTION("kernelsInitialSetup", 2, "Setting Up Kernels/BCs/Constraints");
279 
280  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
281  {
282  _kernels.initialSetup(tid);
285  if (_doing_dg)
288 
292 
293  if (_fe_problem.haveFV())
294  for (auto * fv_object : getFVSetupObjects(tid))
295  fv_object->initialSetup();
296  }
297 
304 
305 #ifdef MOOSE_KOKKOS_ENABLED
310 #endif
311  }
312 
313  {
314  TIME_SECTION("mortarSetup", 2, "Initializing Mortar Interfaces");
315 
316  auto create_mortar_functors = [this](const bool displaced)
317  {
318  // go over mortar interfaces and construct functors
319  const auto & mortar_interfaces = _fe_problem.getMortarInterfaces(displaced);
320  for (const auto & [primary_secondary_boundary_pair, interface_config] : mortar_interfaces)
321  {
322  if (!_constraints.hasActiveMortarConstraints(primary_secondary_boundary_pair, displaced))
323  continue;
324 
325  auto & mortar_constraints =
326  _constraints.getActiveMortarConstraints(primary_secondary_boundary_pair, displaced);
327 
328  auto & subproblem = displaced
329  ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
330  : static_cast<SubProblem &>(_fe_problem);
331 
332  auto & mortar_functors =
334 
335  mortar_functors.emplace(primary_secondary_boundary_pair,
336  ComputeMortarFunctor(mortar_constraints,
337  *interface_config.amg,
338  subproblem,
339  _fe_problem,
340  displaced,
341  subproblem.assembly(0, number())));
342  }
343  };
344 
345  create_mortar_functors(false);
346  create_mortar_functors(true);
347  }
348 
349  if (_automatic_scaling)
350  {
352  _scaling_matrix = std::make_unique<OffDiagonalScalingMatrix<Number>>(_communicator);
353  else
354  _scaling_matrix = std::make_unique<DiagonalMatrix<Number>>(_communicator);
355  }
356 
357  if (_preconditioner)
358  _preconditioner->initialSetup();
359 }
360 
361 void
363 {
365 
366  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
367  {
368  _kernels.timestepSetup(tid);
371  if (_doing_dg)
377 
378  if (_fe_problem.haveFV())
379  for (auto * fv_object : getFVSetupObjects(tid))
380  fv_object->timestepSetup();
381  }
388 
389 #ifdef MOOSE_KOKKOS_ENABLED
394 #endif
395 }
396 
397 void
399 {
400  SolverSystem::customSetup(exec_type);
401 
402  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
403  {
404  _kernels.customSetup(exec_type, tid);
405  _nodal_kernels.customSetup(exec_type, tid);
406  _dirac_kernels.customSetup(exec_type, tid);
407  if (_doing_dg)
408  _dg_kernels.customSetup(exec_type, tid);
409  _interface_kernels.customSetup(exec_type, tid);
410  _element_dampers.customSetup(exec_type, tid);
411  _nodal_dampers.customSetup(exec_type, tid);
412  _integrated_bcs.customSetup(exec_type, tid);
413 
414  if (_fe_problem.haveFV())
415  for (auto * fv_object : getFVSetupObjects(tid))
416  fv_object->customSetup(exec_type);
417  }
418  _scalar_kernels.customSetup(exec_type);
419  _constraints.customSetup(exec_type);
420  _general_dampers.customSetup(exec_type);
421  _nodal_bcs.customSetup(exec_type);
422  _preset_nodal_bcs.customSetup(exec_type);
424 
425 #ifdef MOOSE_KOKKOS_ENABLED
426  _kokkos_kernels.customSetup(exec_type);
429  _kokkos_nodal_bcs.customSetup(exec_type);
430 #endif
431 }
432 
433 void
435 {
436  if (_fsp)
437  _fsp->setupDM();
438 }
439 
440 void
441 NonlinearSystemBase::addKernel(const std::string & kernel_name,
442  const std::string & name,
443  InputParameters & parameters)
444 {
445  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
446  {
447  // Create the kernel object via the factory and add to warehouse
448  std::shared_ptr<KernelBase> kernel =
449  _factory.create<KernelBase>(kernel_name, name, parameters, tid);
450  _kernels.addObject(kernel, tid);
451  postAddResidualObject(*kernel);
452  // Add to theWarehouse, a centralized storage for all moose objects
453  _fe_problem.theWarehouse().add(kernel);
454  }
455 
456  if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
457  _has_save_in = true;
458  if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
459  _has_diag_save_in = true;
460 }
461 
462 void
463 NonlinearSystemBase::addHDGKernel(const std::string & kernel_name,
464  const std::string & name,
465  InputParameters & parameters)
466 {
467  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
468  {
469  // Create the kernel object via the factory and add to warehouse
470  auto kernel = _factory.create<HDGKernel>(kernel_name, name, parameters, tid);
471  _kernels.addObject(kernel, tid);
472  _hybridized_kernels.addObject(kernel, tid);
473  // Add to theWarehouse, a centralized storage for all moose objects
474  _fe_problem.theWarehouse().add(kernel);
475  postAddResidualObject(*kernel);
476  }
477 }
478 
479 void
480 NonlinearSystemBase::addNodalKernel(const std::string & kernel_name,
481  const std::string & name,
482  InputParameters & parameters)
483 {
484  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
485  {
486  // Create the kernel object via the factory and add to the warehouse
487  std::shared_ptr<NodalKernelBase> kernel =
488  _factory.create<NodalKernelBase>(kernel_name, name, parameters, tid);
489  _nodal_kernels.addObject(kernel, tid);
490  // Add to theWarehouse, a centralized storage for all moose objects
491  _fe_problem.theWarehouse().add(kernel);
492  postAddResidualObject(*kernel);
493  }
494 
495  if (parameters.have_parameter<std::vector<AuxVariableName>>("save_in") &&
496  parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
497  _has_save_in = true;
498  if (parameters.have_parameter<std::vector<AuxVariableName>>("save_in") &&
499  parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
500  _has_diag_save_in = true;
501 }
502 
503 void
504 NonlinearSystemBase::addScalarKernel(const std::string & kernel_name,
505  const std::string & name,
506  InputParameters & parameters)
507 {
508  std::shared_ptr<ScalarKernelBase> kernel =
509  _factory.create<ScalarKernelBase>(kernel_name, name, parameters);
510  postAddResidualObject(*kernel);
511  // Add to theWarehouse, a centralized storage for all moose objects
512  _fe_problem.theWarehouse().add(kernel);
513  _scalar_kernels.addObject(kernel);
514 }
515 
516 void
517 NonlinearSystemBase::addBoundaryCondition(const std::string & bc_name,
518  const std::string & name,
519  InputParameters & parameters)
520 {
521  // ThreadID
522  THREAD_ID tid = 0;
523 
524  // Create the object
525  std::shared_ptr<BoundaryCondition> bc =
526  _factory.create<BoundaryCondition>(bc_name, name, parameters, tid);
528 
529  // Active BoundaryIDs for the object
530  const std::set<BoundaryID> & boundary_ids = bc->boundaryIDs();
531  auto bc_var = dynamic_cast<const MooseVariableFieldBase *>(&bc->variable());
532  _vars[tid].addBoundaryVar(boundary_ids, bc_var);
533 
534  // Cast to the various types of BCs
535  std::shared_ptr<NodalBCBase> nbc = std::dynamic_pointer_cast<NodalBCBase>(bc);
536  std::shared_ptr<IntegratedBCBase> ibc = std::dynamic_pointer_cast<IntegratedBCBase>(bc);
537 
538  // NodalBCBase
539  if (nbc)
540  {
541  if (nbc->checkNodalVar() && !nbc->variable().isNodal())
542  mooseError("Trying to use nodal boundary condition '",
543  nbc->name(),
544  "' on a non-nodal variable '",
545  nbc->variable().name(),
546  "'.");
547 
548  _nodal_bcs.addObject(nbc);
549  // Add to theWarehouse, a centralized storage for all moose objects
551  _vars[tid].addBoundaryVars(boundary_ids, nbc->getCoupledVars());
552 
553  if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
554  _has_nodalbc_save_in = true;
555  if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
557 
558  // DirichletBCs that are preset
559  std::shared_ptr<DirichletBCBase> dbc = std::dynamic_pointer_cast<DirichletBCBase>(bc);
560  if (dbc && dbc->preset())
562 
563  std::shared_ptr<ADDirichletBCBase> addbc = std::dynamic_pointer_cast<ADDirichletBCBase>(bc);
564  if (addbc && addbc->preset())
566  }
567 
568  // IntegratedBCBase
569  else if (ibc)
570  {
571  _integrated_bcs.addObject(ibc, tid);
572  // Add to theWarehouse, a centralized storage for all moose objects
574  _vars[tid].addBoundaryVars(boundary_ids, ibc->getCoupledVars());
575 
576  if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
577  _has_save_in = true;
578  if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
579  _has_diag_save_in = true;
580 
581  for (tid = 1; tid < libMesh::n_threads(); tid++)
582  {
583  // Create the object
584  bc = _factory.create<BoundaryCondition>(bc_name, name, parameters, tid);
585 
586  // Give users opportunity to set some parameters
588 
589  // Active BoundaryIDs for the object
590  const std::set<BoundaryID> & boundary_ids = bc->boundaryIDs();
591  _vars[tid].addBoundaryVar(boundary_ids, bc_var);
592 
593  ibc = std::static_pointer_cast<IntegratedBCBase>(bc);
594 
595  _integrated_bcs.addObject(ibc, tid);
596  _vars[tid].addBoundaryVars(boundary_ids, ibc->getCoupledVars());
597  }
598  }
599 
600  else
601  mooseError("Unknown BoundaryCondition type for object named ", bc->name());
602 }
603 
604 void
605 NonlinearSystemBase::addConstraint(const std::string & c_name,
606  const std::string & name,
607  InputParameters & parameters)
608 {
609  std::shared_ptr<Constraint> constraint = _factory.create<Constraint>(c_name, name, parameters);
610  _constraints.addObject(constraint);
611  postAddResidualObject(*constraint);
612 
614  if (constraint && constraint->addCouplingEntriesToJacobian())
616 }
617 
618 void
619 NonlinearSystemBase::addDiracKernel(const std::string & kernel_name,
620  const std::string & name,
621  InputParameters & parameters)
622 {
623  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
624  {
625  std::shared_ptr<DiracKernelBase> kernel =
626  _factory.create<DiracKernelBase>(kernel_name, name, parameters, tid);
627  postAddResidualObject(*kernel);
628  _dirac_kernels.addObject(kernel, tid);
629  // Add to theWarehouse, a centralized storage for all moose objects
630  _fe_problem.theWarehouse().add(kernel);
631  }
632 }
633 
634 void
635 NonlinearSystemBase::addDGKernel(std::string dg_kernel_name,
636  const std::string & name,
637  InputParameters & parameters)
638 {
639  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
640  {
641  auto dg_kernel = _factory.create<DGKernelBase>(dg_kernel_name, name, parameters, tid);
642  _dg_kernels.addObject(dg_kernel, tid);
643  // Add to theWarehouse, a centralized storage for all moose objects
644  _fe_problem.theWarehouse().add(dg_kernel);
645  postAddResidualObject(*dg_kernel);
646  }
647 
648  _doing_dg = true;
649 
650  if (parameters.get<std::vector<AuxVariableName>>("save_in").size() > 0)
651  _has_save_in = true;
652  if (parameters.get<std::vector<AuxVariableName>>("diag_save_in").size() > 0)
653  _has_diag_save_in = true;
654 }
655 
656 void
657 NonlinearSystemBase::addInterfaceKernel(std::string interface_kernel_name,
658  const std::string & name,
659  InputParameters & parameters)
660 {
661  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
662  {
663  std::shared_ptr<InterfaceKernelBase> interface_kernel =
664  _factory.create<InterfaceKernelBase>(interface_kernel_name, name, parameters, tid);
665  postAddResidualObject(*interface_kernel);
666 
667  const std::set<BoundaryID> & boundary_ids = interface_kernel->boundaryIDs();
668  auto ik_var = dynamic_cast<const MooseVariableFieldBase *>(&interface_kernel->variable());
669  _vars[tid].addBoundaryVar(boundary_ids, ik_var);
670 
671  _interface_kernels.addObject(interface_kernel, tid);
672  // Add to theWarehouse, a centralized storage for all moose objects
673  _fe_problem.theWarehouse().add(interface_kernel);
674  _vars[tid].addBoundaryVars(boundary_ids, interface_kernel->getCoupledVars());
675  }
676 }
677 
678 void
679 NonlinearSystemBase::addDamper(const std::string & damper_name,
680  const std::string & name,
681  InputParameters & parameters)
682 {
683  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
684  {
685  std::shared_ptr<Damper> damper = _factory.create<Damper>(damper_name, name, parameters, tid);
686 
687  // Attempt to cast to the damper types
688  std::shared_ptr<ElementDamper> ed = std::dynamic_pointer_cast<ElementDamper>(damper);
689  std::shared_ptr<NodalDamper> nd = std::dynamic_pointer_cast<NodalDamper>(damper);
690  std::shared_ptr<GeneralDamper> gd = std::dynamic_pointer_cast<GeneralDamper>(damper);
691 
692  if (gd)
693  {
695  break; // not threaded
696  }
697  else if (ed)
698  _element_dampers.addObject(ed, tid);
699  else if (nd)
700  _nodal_dampers.addObject(nd, tid);
701  else
702  mooseError("Invalid damper type");
703  }
704 }
705 
706 void
707 NonlinearSystemBase::addSplit(const std::string & split_name,
708  const std::string & name,
709  InputParameters & parameters)
710 {
711  std::shared_ptr<Split> split = _factory.create<Split>(split_name, name, parameters);
713  // Add to theWarehouse, a centralized storage for all moose objects
715 }
716 
717 std::shared_ptr<Split>
718 NonlinearSystemBase::getSplit(const std::string & name)
719 {
720  return _splits.getActiveObject(name);
721 }
722 
723 bool
725 {
727  return false;
728 
729  // The legacy behavior (#10464) _always_ performs the pre-SMO residual evaluation
730  // regardless of whether it is needed.
731  //
732  // This is not ideal and has been fixed by #23472. This legacy option ensures a smooth transition
733  // to the new behavior. Modules and Apps that want to migrate to the new behavior should set this
734  // parameter to false.
735  if (_app.parameters().get<bool>("use_legacy_initial_residual_evaluation_behavior"))
736  return true;
737 
738  return _use_pre_smo_residual;
739 }
740 
741 Real
743 {
745 }
746 
747 Real
749 {
751  mooseError("pre-SMO residual is requested but not evaluated.");
752 
753  return _pre_smo_residual;
754 }
755 
756 Real
758 {
759  return _initial_residual;
760 }
761 
762 void
764 {
765  _initial_residual = r;
766 }
767 
768 void
769 NonlinearSystemBase::zeroVectorForResidual(const std::string & vector_name)
770 {
771  for (unsigned int i = 0; i < _vecs_to_zero_for_residual.size(); ++i)
772  if (vector_name == _vecs_to_zero_for_residual[i])
773  return;
774 
775  _vecs_to_zero_for_residual.push_back(vector_name);
776 }
777 
778 void
780 {
781  _nl_vector_tags.clear();
782  _nl_vector_tags.insert(tag_id);
784 
786 
788 
790 }
791 
792 void
794 {
795  mooseDeprecated(" Please use computeResidualTag");
796 
797  computeResidualTag(residual, tag_id);
798 }
799 
800 void
801 NonlinearSystemBase::computeResidualTags(const std::set<TagID> & tags)
802 {
803  parallel_object_only();
804 
805  TIME_SECTION("nl::computeResidualTags", 5);
806 
809 
810  bool required_residual = tags.find(residualVectorTag()) == tags.end() ? false : true;
811 
813 
814  // not suppose to do anythin on matrix
816 
818 
819  for (const auto & numeric_vec : _vecs_to_zero_for_residual)
820  if (hasVector(numeric_vec))
821  {
822  NumericVector<Number> & vec = getVector(numeric_vec);
823  vec.close();
824  vec.zero();
825  }
826 
827  try
828  {
829  zeroTaggedVectors(tags);
831  closeTaggedVectors(tags);
832 
833  if (required_residual)
834  {
835  auto & residual = getVector(residualVectorTag());
836  if (!_time_integrators.empty())
837  {
838  for (auto & ti : _time_integrators)
839  ti->postResidual(residual);
840  }
841  else
842  residual += *_Re_non_time;
843  residual.close();
844  }
846  // We don't want to do nodal bcs or anything else
847  return;
848 
850  closeTaggedVectors(tags);
851 
852  // If we are debugging residuals we need one more assignment to have the ghosted copy up to
853  // date
854  if (_need_residual_ghosted && _debugging_residuals && required_residual)
855  {
856  auto & residual = getVector(residualVectorTag());
857 
858  *_residual_ghosted = residual;
860  }
861  // Need to close and update the aux system in case residuals were saved to it.
864  if (hasSaveIn())
866  }
867  catch (MooseException & e)
868  {
869  // The buck stops here, we have already handled the exception by
870  // calling stopSolve(), it is now up to PETSc to return a
871  // "diverged" reason during the next solve.
872  }
873 
874  // not supposed to do anything on matrix
876 
878 }
879 
880 void
881 NonlinearSystemBase::computeResidualAndJacobianTags(const std::set<TagID> & vector_tags,
882  const std::set<TagID> & matrix_tags)
883 {
884  const bool required_residual =
885  vector_tags.find(residualVectorTag()) == vector_tags.end() ? false : true;
886 
887  try
888  {
889  zeroTaggedVectors(vector_tags);
890  computeResidualAndJacobianInternal(vector_tags, matrix_tags);
891  closeTaggedVectors(vector_tags);
892  closeTaggedMatrices(matrix_tags);
893 
894  if (required_residual)
895  {
896  auto & residual = getVector(residualVectorTag());
897  if (!_time_integrators.empty())
898  {
899  for (auto & ti : _time_integrators)
900  ti->postResidual(residual);
901  }
902  else
903  residual += *_Re_non_time;
904  residual.close();
905  }
906 
907  computeNodalBCsResidualAndJacobian(vector_tags, matrix_tags);
908  closeTaggedVectors(vector_tags);
909  closeTaggedMatrices(matrix_tags);
910  }
911  catch (MooseException & e)
912  {
913  // The buck stops here, we have already handled the exception by
914  // calling stopSolve(), it is now up to PETSc to return a
915  // "diverged" reason during the next solve.
916  }
917 }
918 
919 void
921 {
922  for (auto & ti : _time_integrators)
923  ti->preSolve();
924  if (_predictor.get())
925  _predictor->timestepSetup();
926 }
927 
928 void
930 {
932 
933  NumericVector<Number> & initial_solution(solution());
934  if (_predictor.get())
935  {
936  if (_predictor->shouldApply())
937  {
938  TIME_SECTION("applyPredictor", 2, "Applying Predictor");
939 
940  _predictor->apply(initial_solution);
941  _fe_problem.predictorCleanup(initial_solution);
942  }
943  else
944  _console << " Skipping predictor this step" << std::endl;
945  }
946 
947  // do nodal BC
948  {
949  TIME_SECTION("initialBCs", 2, "Applying BCs To Initial Condition");
950 
952  for (const auto & bnode : bnd_nodes)
953  {
954  BoundaryID boundary_id = bnode->_bnd_id;
955  Node * node = bnode->_node;
956 
957  if (node->processor_id() == processor_id())
958  {
959  bool has_preset_nodal_bcs = _preset_nodal_bcs.hasActiveBoundaryObjects(boundary_id);
960  bool has_ad_preset_nodal_bcs = _ad_preset_nodal_bcs.hasActiveBoundaryObjects(boundary_id);
961 
962  // reinit variables in nodes
963  if (has_preset_nodal_bcs || has_ad_preset_nodal_bcs)
964  _fe_problem.reinitNodeFace(node, boundary_id, 0);
965 
966  if (has_preset_nodal_bcs)
967  {
968  const auto & preset_bcs = _preset_nodal_bcs.getActiveBoundaryObjects(boundary_id);
969  for (const auto & preset_bc : preset_bcs)
970  preset_bc->computeValue(initial_solution);
971  }
972  if (has_ad_preset_nodal_bcs)
973  {
974  const auto & preset_bcs_res = _ad_preset_nodal_bcs.getActiveBoundaryObjects(boundary_id);
975  for (const auto & preset_bc : preset_bcs_res)
976  preset_bc->computeValue(initial_solution);
977  }
978  }
979  }
980  }
981 
982 #ifdef MOOSE_KOKKOS_ENABLED
985 #endif
986 
987  _sys.solution->close();
988  update();
989 
990  // Set constraint secondary values
991  setConstraintSecondaryValues(initial_solution, false);
992 
994  setConstraintSecondaryValues(initial_solution, true);
995 }
996 
997 void
998 NonlinearSystemBase::setPredictor(std::shared_ptr<Predictor> predictor)
999 {
1000  _predictor = predictor;
1001 }
1002 
1003 void
1005 {
1007 
1008  _kernels.subdomainSetup(subdomain, tid);
1009  _nodal_kernels.subdomainSetup(subdomain, tid);
1010  _element_dampers.subdomainSetup(subdomain, tid);
1011  _nodal_dampers.subdomainSetup(subdomain, tid);
1012 }
1013 
1016 {
1017  if (!_Re_time)
1018  {
1020 
1021  // Most applications don't need the expense of ghosting
1023  _Re_time = &addVector(_Re_time_tag, false, ptype);
1024  }
1025  else if (_need_residual_ghosted && _Re_time->type() == PARALLEL)
1026  {
1027  const auto vector_name = _subproblem.vectorTagName(_Re_time_tag);
1028 
1029  // If an application changes its mind, the libMesh API lets us
1030  // change the vector.
1031  _Re_time = &system().add_vector(vector_name, false, GHOSTED);
1032  }
1033 
1034  return *_Re_time;
1035 }
1036 
1039 {
1040  if (!_Re_non_time)
1041  {
1043 
1044  // Most applications don't need the expense of ghosting
1046  _Re_non_time = &addVector(_Re_non_time_tag, false, ptype);
1047  }
1049  {
1050  const auto vector_name = _subproblem.vectorTagName(_Re_non_time_tag);
1051 
1052  // If an application changes its mind, the libMesh API lets us
1053  // change the vector.
1054  _Re_non_time = &system().add_vector(vector_name, false, GHOSTED);
1055  }
1056 
1057  return *_Re_non_time;
1058 }
1059 
1062 {
1063  mooseDeprecated("Please use getVector()");
1064  switch (tag)
1065  {
1066  case 0:
1067  return getResidualNonTimeVector();
1068 
1069  case 1:
1070  return getResidualTimeVector();
1071 
1072  default:
1073  mooseError("The required residual vector is not available");
1074  }
1075 }
1076 
1077 void
1079 {
1080  THREAD_ID tid = 0; // constraints are going to be done single-threaded
1081  residual.close();
1083  {
1084  const auto & ncs = _constraints.getActiveNodalConstraints();
1085  for (const auto & nc : ncs)
1086  {
1087  std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
1088  std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
1089 
1090  if ((secondary_node_ids.size() > 0) && (primary_node_ids.size() > 0))
1091  {
1092  _fe_problem.reinitNodes(primary_node_ids, tid);
1093  _fe_problem.reinitNodesNeighbor(secondary_node_ids, tid);
1094  nc->computeResidual(residual);
1095  }
1096  }
1097  _fe_problem.addCachedResidualDirectly(residual, tid);
1098  residual.close();
1099  }
1100 }
1101 
1102 bool
1104 {
1105  if (!hasMatrix(systemMatrixTag()))
1106  mooseError(" A system matrix is required");
1107 
1108  THREAD_ID tid = 0; // constraints are going to be done single-threaded
1109 
1111  {
1112  const auto & ncs = _constraints.getActiveNodalConstraints();
1113  for (const auto & nc : ncs)
1114  {
1115  std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
1116  std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
1117 
1118  if ((secondary_node_ids.size() > 0) && (primary_node_ids.size() > 0))
1119  {
1120  _fe_problem.reinitNodes(primary_node_ids, tid);
1121  _fe_problem.reinitNodesNeighbor(secondary_node_ids, tid);
1122  nc->computeJacobian(jacobian_to_view);
1123  }
1124  }
1126 
1127  return true;
1128  }
1129  else
1130  return false;
1131 }
1132 
1133 void
1135  const BoundaryID secondary_boundary,
1136  const PenetrationInfo & info,
1137  const bool displaced)
1138 {
1139  auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
1140  : static_cast<SubProblem &>(_fe_problem);
1141 
1142  const Elem * primary_elem = info._elem;
1143  unsigned int primary_side = info._side_num;
1144  std::vector<Point> points;
1145  points.push_back(info._closest_point);
1146 
1147  // *These next steps MUST be done in this order!*
1148  // ADL: This is a Chesterton's fence situation. I don't know which calls exactly the above comment
1149  // is referring to. If I had to guess I would guess just the reinitNodeFace and prepareAssembly
1150  // calls since the former will size the variable's dof indices and then the latter will resize the
1151  // residual/Jacobian based off the variable's cached dof indices size
1152 
1153  // This reinits the variables that exist on the secondary node
1154  _fe_problem.reinitNodeFace(&secondary_node, secondary_boundary, 0);
1155 
1156  // This will set aside residual and jacobian space for the variables that have dofs on
1157  // the secondary node
1159 
1160  _fe_problem.setNeighborSubdomainID(primary_elem, 0);
1161 
1162  //
1163  // Reinit material on undisplaced mesh
1164  //
1165 
1166  const Elem * const undisplaced_primary_elem =
1167  displaced ? _mesh.elemPtr(primary_elem->id()) : primary_elem;
1168  const Point undisplaced_primary_physical_point =
1169  [&points, displaced, primary_elem, undisplaced_primary_elem]()
1170  {
1171  if (displaced)
1172  {
1173  const Point reference_point =
1174  FEMap::inverse_map(primary_elem->dim(), primary_elem, points[0]);
1175  return FEMap::map(primary_elem->dim(), undisplaced_primary_elem, reference_point);
1176  }
1177  else
1178  // If our penetration locator is on the reference mesh, then our undisplaced
1179  // physical point is simply the point coming from the penetration locator
1180  return points[0];
1181  }();
1182 
1184  undisplaced_primary_elem, primary_side, {undisplaced_primary_physical_point}, 0);
1185  // Stateful material properties are only initialized for neighbor material data for internal faces
1186  // for discontinuous Galerkin methods or for conforming interfaces for interface kernels. We don't
1187  // have either of those use cases here where we likely have disconnected meshes
1188  _fe_problem.reinitMaterialsNeighbor(primary_elem->subdomain_id(), 0, /*swap_stateful=*/false);
1189 
1190  // Reinit points for constraint enforcement
1191  if (displaced)
1192  subproblem.reinitNeighborPhys(primary_elem, primary_side, points, 0);
1193 }
1194 
1195 void
1197 {
1198 
1199  if (displaced)
1200  mooseAssert(_fe_problem.getDisplacedProblem(),
1201  "If we're calling this method with displaced = true, then we better well have a "
1202  "displaced problem");
1203  auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
1204  : static_cast<SubProblem &>(_fe_problem);
1205  const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
1206 
1207  bool constraints_applied = false;
1208 
1209  for (const auto & it : penetration_locators)
1210  {
1211  PenetrationLocator & pen_loc = *(it.second);
1212 
1213  std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
1214 
1215  BoundaryID secondary_boundary = pen_loc._secondary_boundary;
1216  BoundaryID primary_boundary = pen_loc._primary_boundary;
1217 
1218  if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
1219  {
1220  const auto & constraints =
1221  _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
1222  std::unordered_set<unsigned int> needed_mat_props;
1223  for (const auto & constraint : constraints)
1224  {
1225  const auto & mp_deps = constraint->getMatPropDependencies();
1226  needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
1227  }
1228  _fe_problem.setActiveMaterialProperties(needed_mat_props, /*tid=*/0);
1229 
1230  for (unsigned int i = 0; i < secondary_nodes.size(); i++)
1231  {
1232  dof_id_type secondary_node_num = secondary_nodes[i];
1233  Node & secondary_node = _mesh.nodeRef(secondary_node_num);
1234 
1235  if (secondary_node.processor_id() == processor_id())
1236  {
1237  if (pen_loc._penetration_info[secondary_node_num])
1238  {
1239  PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
1240 
1241  reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
1242 
1243  for (const auto & nfc : constraints)
1244  {
1245  if (nfc->isExplicitConstraint())
1246  continue;
1247  // Return if this constraint does not correspond to the primary-secondary pair
1248  // prepared by the outer loops.
1249  // This continue statement is required when, e.g. one secondary surface constrains
1250  // more than one primary surface.
1251  if (nfc->secondaryBoundary() != secondary_boundary ||
1252  nfc->primaryBoundary() != primary_boundary)
1253  continue;
1254 
1255  if (nfc->shouldApply())
1256  {
1257  constraints_applied = true;
1258  nfc->computeSecondaryValue(solution);
1259  }
1260 
1261  if (nfc->hasWritableCoupledVariables())
1262  {
1263  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1264  for (auto * var : nfc->getWritableCoupledVariables())
1265  {
1266  if (var->isNodalDefined())
1267  var->insert(_fe_problem.getAuxiliarySystem().solution());
1268  }
1269  }
1270  }
1271  }
1272  }
1273  }
1274  }
1275  }
1276 
1277  // go over NodeELemConstraints
1278  std::set<dof_id_type> unique_secondary_node_ids;
1279 
1280  for (const auto & secondary_id : _mesh.meshSubdomains())
1281  {
1282  for (const auto & primary_id : _mesh.meshSubdomains())
1283  {
1284  if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
1285  {
1286  const auto & constraints =
1287  _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
1288 
1289  // get unique set of ids of all nodes on current block
1290  unique_secondary_node_ids.clear();
1291  const MeshBase & meshhelper = _mesh.getMesh();
1292  for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
1293  meshhelper.active_subdomain_elements_end(secondary_id)))
1294  {
1295  for (auto & n : elem->node_ref_range())
1296  unique_secondary_node_ids.insert(n.id());
1297  }
1298 
1299  for (auto secondary_node_id : unique_secondary_node_ids)
1300  {
1301  Node & secondary_node = _mesh.nodeRef(secondary_node_id);
1302 
1303  // check if secondary node is on current processor
1304  if (secondary_node.processor_id() == processor_id())
1305  {
1306  // This reinits the variables that exist on the secondary node
1307  _fe_problem.reinitNodeFace(&secondary_node, secondary_id, 0);
1308 
1309  // This will set aside residual and jacobian space for the variables that have dofs
1310  // on the secondary node
1312 
1313  for (const auto & nec : constraints)
1314  {
1315  if (nec->shouldApply())
1316  {
1317  constraints_applied = true;
1318  nec->computeSecondaryValue(solution);
1319  }
1320  }
1321  }
1322  }
1323  }
1324  }
1325  }
1326 
1327  // See if constraints were applied anywhere
1328  _communicator.max(constraints_applied);
1329 
1330  if (constraints_applied)
1331  {
1332  solution.close();
1333  update();
1334  }
1335 }
1336 
1337 void
1339 {
1340  // Make sure the residual is in a good state
1341  residual.close();
1342 
1343  if (displaced)
1344  mooseAssert(_fe_problem.getDisplacedProblem(),
1345  "If we're calling this method with displaced = true, then we better well have a "
1346  "displaced problem");
1347  auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
1348  : static_cast<SubProblem &>(_fe_problem);
1349  const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
1350 
1351  bool constraints_applied;
1352  bool residual_has_inserted_values = false;
1354  constraints_applied = false;
1355  for (const auto & it : penetration_locators)
1356  {
1358  {
1359  // Reset the constraint_applied flag before each new constraint, as they need to be
1360  // assembled separately
1361  constraints_applied = false;
1362  }
1363  PenetrationLocator & pen_loc = *(it.second);
1364 
1365  std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
1366 
1367  BoundaryID secondary_boundary = pen_loc._secondary_boundary;
1368  BoundaryID primary_boundary = pen_loc._primary_boundary;
1369 
1370  bool has_writable_variables(false);
1371 
1372  if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
1373  {
1374  const auto & constraints =
1375  _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
1376 
1377  for (unsigned int i = 0; i < secondary_nodes.size(); i++)
1378  {
1379  dof_id_type secondary_node_num = secondary_nodes[i];
1380  Node & secondary_node = _mesh.nodeRef(secondary_node_num);
1381 
1382  if (secondary_node.processor_id() == processor_id())
1383  {
1384  if (pen_loc._penetration_info[secondary_node_num])
1385  {
1386  PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
1387 
1388  reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
1389 
1390  for (const auto & nfc : constraints)
1391  {
1392  // Return if this constraint does not correspond to the primary-secondary pair
1393  // prepared by the outer loops.
1394  // This continue statement is required when, e.g. one secondary surface constrains
1395  // more than one primary surface.
1396  if (nfc->secondaryBoundary() != secondary_boundary ||
1397  nfc->primaryBoundary() != primary_boundary)
1398  continue;
1399 
1400  if (nfc->shouldApply())
1401  {
1402  constraints_applied = true;
1403  nfc->computeResidual();
1404 
1405  if (nfc->overwriteSecondaryResidual())
1406  {
1407  // The below will actually overwrite the residual for every single dof that
1408  // lives on the node. We definitely don't want to do that!
1409  // _fe_problem.setResidual(residual, 0);
1410 
1411  const auto & secondary_var = nfc->variable();
1412  const auto & secondary_dofs = secondary_var.dofIndices();
1413  mooseAssert(secondary_dofs.size() == secondary_var.count(),
1414  "We are on a node so there should only be one dof per variable (for "
1415  "an ArrayVariable we should have a number of dofs equal to the "
1416  "number of components");
1417 
1418  // Assume that if the user is overwriting the secondary residual, then they are
1419  // supplying residuals that do not correspond to their other physics
1420  // (e.g. Kernels), hence we should not apply a scalingFactor that is normally
1421  // based on the order of their other physics (e.g. Kernels)
1422  std::vector<Number> values = {nfc->secondaryResidual()};
1423  residual.insert(values, secondary_dofs);
1424  residual_has_inserted_values = true;
1425  }
1426  else
1429  }
1430  if (nfc->hasWritableCoupledVariables())
1431  {
1432  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1433  has_writable_variables = true;
1434  for (auto * var : nfc->getWritableCoupledVariables())
1435  {
1436  if (var->isNodalDefined())
1437  var->insert(_fe_problem.getAuxiliarySystem().solution());
1438  }
1439  }
1440  }
1441  }
1442  }
1443  }
1444  }
1445  _communicator.max(has_writable_variables);
1446 
1447  if (has_writable_variables)
1448  {
1449  // Explicit contact dynamic constraints write to auxiliary variables and update the old
1450  // displacement solution on the constraint boundaries. Close solutions and update system
1451  // accordingly.
1454  solutionOld().close();
1455  }
1456 
1458  {
1459  // Make sure that secondary contribution to primary are assembled, and ghosts have been
1460  // exchanged, as current primaries might become secondaries on next iteration and will need to
1461  // contribute their former secondaries' contributions to the future primaries. See if
1462  // constraints were applied anywhere
1463  _communicator.max(constraints_applied);
1464 
1465  if (constraints_applied)
1466  {
1467  // If any of the above constraints inserted values in the residual, it needs to be
1468  // assembled before adding the cached residuals below.
1469  _communicator.max(residual_has_inserted_values);
1470  if (residual_has_inserted_values)
1471  {
1472  residual.close();
1473  residual_has_inserted_values = false;
1474  }
1476  residual.close();
1477 
1479  *_residual_ghosted = residual;
1480  }
1481  }
1482  }
1484  {
1485  _communicator.max(constraints_applied);
1486 
1487  if (constraints_applied)
1488  {
1489  // If any of the above constraints inserted values in the residual, it needs to be assembled
1490  // before adding the cached residuals below.
1491  _communicator.max(residual_has_inserted_values);
1492  if (residual_has_inserted_values)
1493  residual.close();
1494 
1496  residual.close();
1497 
1499  *_residual_ghosted = residual;
1500  }
1501  }
1502 
1503  // go over element-element constraint interface
1504  THREAD_ID tid = 0;
1505  const auto & element_pair_locators = subproblem.geomSearchData()._element_pair_locators;
1506  for (const auto & it : element_pair_locators)
1507  {
1508  ElementPairLocator & elem_pair_loc = *(it.second);
1509 
1510  if (_constraints.hasActiveElemElemConstraints(it.first, displaced))
1511  {
1512  // ElemElemConstraint objects
1513  const auto & element_constraints =
1514  _constraints.getActiveElemElemConstraints(it.first, displaced);
1515 
1516  // go over pair elements
1517  const std::list<std::pair<const Elem *, const Elem *>> & elem_pairs =
1518  elem_pair_loc.getElemPairs();
1519  for (const auto & pr : elem_pairs)
1520  {
1521  const Elem * elem1 = pr.first;
1522  const Elem * elem2 = pr.second;
1523 
1524  if (elem1->processor_id() != processor_id())
1525  continue;
1526 
1527  const ElementPairInfo & info = elem_pair_loc.getElemPairInfo(pr);
1528 
1529  // for each element process constraints on the
1530  for (const auto & ec : element_constraints)
1531  {
1532  _fe_problem.setCurrentSubdomainID(elem1, tid);
1533  subproblem.reinitElemPhys(elem1, info._elem1_constraint_q_point, tid);
1534  _fe_problem.setNeighborSubdomainID(elem2, tid);
1535  subproblem.reinitNeighborPhys(elem2, info._elem2_constraint_q_point, tid);
1536 
1537  ec->prepareShapes(ec->variable().number());
1538  ec->prepareNeighborShapes(ec->variable().number());
1539 
1540  ec->reinit(info);
1541  ec->computeResidual();
1544  }
1546  }
1547  }
1548  }
1549 
1550  // go over NodeElemConstraints
1551  std::set<dof_id_type> unique_secondary_node_ids;
1552 
1553  constraints_applied = false;
1554  residual_has_inserted_values = false;
1555  bool has_writable_variables = false;
1556  for (const auto & secondary_id : _mesh.meshSubdomains())
1557  {
1558  for (const auto & primary_id : _mesh.meshSubdomains())
1559  {
1560  if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
1561  {
1562  const auto & constraints =
1563  _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
1564 
1565  // get unique set of ids of all nodes on current block
1566  unique_secondary_node_ids.clear();
1567  const MeshBase & meshhelper = _mesh.getMesh();
1568  for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
1569  meshhelper.active_subdomain_elements_end(secondary_id)))
1570  {
1571  for (auto & n : elem->node_ref_range())
1572  unique_secondary_node_ids.insert(n.id());
1573  }
1574 
1575  for (auto secondary_node_id : unique_secondary_node_ids)
1576  {
1577  Node & secondary_node = _mesh.nodeRef(secondary_node_id);
1578  // check if secondary node is on current processor
1579  if (secondary_node.processor_id() == processor_id())
1580  {
1581  // This reinits the variables that exist on the secondary node
1582  _fe_problem.reinitNodeFace(&secondary_node, secondary_id, 0);
1583 
1584  // This will set aside residual and jacobian space for the variables that have dofs
1585  // on the secondary node
1587 
1588  for (const auto & nec : constraints)
1589  {
1590  if (nec->shouldApply())
1591  {
1592  constraints_applied = true;
1593  nec->computeResidual();
1594 
1595  if (nec->overwriteSecondaryResidual())
1596  {
1597  _fe_problem.setResidual(residual, 0);
1598  residual_has_inserted_values = true;
1599  }
1600  else
1603  }
1604  if (nec->hasWritableCoupledVariables())
1605  {
1606  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1607  has_writable_variables = true;
1608  for (auto * var : nec->getWritableCoupledVariables())
1609  {
1610  if (var->isNodalDefined())
1611  var->insert(_fe_problem.getAuxiliarySystem().solution());
1612  }
1613  }
1614  }
1616  }
1617  }
1618  }
1619  }
1620  }
1621  _communicator.max(constraints_applied);
1622 
1623  if (constraints_applied)
1624  {
1625  // If any of the above constraints inserted values in the residual, it needs to be assembled
1626  // before adding the cached residuals below.
1627  _communicator.max(residual_has_inserted_values);
1628  if (residual_has_inserted_values)
1629  residual.close();
1630 
1632  residual.close();
1633 
1635  *_residual_ghosted = residual;
1636  }
1637  _communicator.max(has_writable_variables);
1638 
1639  if (has_writable_variables)
1640  {
1641  // Explicit contact dynamic constraints write to auxiliary variables and update the old
1642  // displacement solution on the constraint boundaries. Close solutions and update system
1643  // accordingly.
1646  solutionOld().close();
1647  }
1648 
1649  // We may have additional tagged vectors that also need to be accumulated
1651 }
1652 
1653 void
1655 {
1656  // Overwrite results from integrator in case we have explicit dynamics contact constraints
1658  ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
1659  : static_cast<SubProblem &>(_fe_problem);
1660  const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
1661 
1662  for (const auto & it : penetration_locators)
1663  {
1664  PenetrationLocator & pen_loc = *(it.second);
1665 
1666  const auto & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
1667  const BoundaryID secondary_boundary = pen_loc._secondary_boundary;
1668  const BoundaryID primary_boundary = pen_loc._primary_boundary;
1669 
1670  if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, true))
1671  {
1672  const auto & constraints =
1673  _constraints.getActiveNodeFaceConstraints(secondary_boundary, true);
1674  for (const auto i : index_range(secondary_nodes))
1675  {
1676  const auto secondary_node_num = secondary_nodes[i];
1677  const Node & secondary_node = _mesh.nodeRef(secondary_node_num);
1678 
1679  if (secondary_node.processor_id() == processor_id())
1680  if (pen_loc._penetration_info[secondary_node_num])
1681  for (const auto & nfc : constraints)
1682  {
1683  if (!nfc->isExplicitConstraint())
1684  continue;
1685 
1686  // Return if this constraint does not correspond to the primary-secondary pair
1687  // prepared by the outer loops.
1688  // This continue statement is required when, e.g. one secondary surface constrains
1689  // more than one primary surface.
1690  if (nfc->secondaryBoundary() != secondary_boundary ||
1691  nfc->primaryBoundary() != primary_boundary)
1692  continue;
1693 
1694  nfc->overwriteBoundaryVariables(soln, secondary_node);
1695  }
1696  }
1697  }
1698  }
1699  soln.close();
1700 }
1701 
1702 void
1704 {
1705  TIME_SECTION("residualSetup", 3);
1706 
1708 
1709  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
1710  {
1711  _kernels.residualSetup(tid);
1714  if (_doing_dg)
1720  }
1727 
1728 #ifdef MOOSE_KOKKOS_ENABLED
1733 #endif
1734 
1735  // Avoid recursion
1736  if (this == &_fe_problem.currentNonlinearSystem())
1738 }
1739 
1740 void
1742 {
1743  parallel_object_only();
1744 
1745  TIME_SECTION("computeResidualInternal", 3);
1746 
1747  residualSetup();
1748 
1749  // Residual contributions from UOs - for now this is used for ray tracing
1750  // and ray kernels that contribute to the residual (think line sources)
1751  std::vector<GeneralUserObject *> uos;
1753  .query()
1754  .condition<AttribSystem>("UserObject")
1755  .condition<AttribExecOns>(EXEC_PRE_KERNELS)
1756  .queryInto(uos);
1757  for (auto & uo : uos)
1758  uo->residualSetup();
1759  for (auto & uo : uos)
1760  {
1761  uo->initialize();
1762  uo->execute();
1763  uo->finalize();
1764  }
1765 
1766  // reinit scalar variables
1767  for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
1769 
1770 #ifdef MOOSE_KOKKOS_ENABLED
1772  computeKokkosResidual(tags);
1773 #endif
1774 
1775  // residual contributions from the domain
1776  PARALLEL_TRY
1777  {
1778  TIME_SECTION("Kernels", 3 /*, "Computing Kernels"*/);
1779 
1781 
1783  Threads::parallel_reduce(elem_range, cr);
1784 
1785  // We pass face information directly to FV residual objects for their evaluation. Consequently
1786  // we must make sure to do separate threaded loops for 1) undisplaced face information objects
1787  // and undisplaced residual objects and 2) displaced face information objects and displaced
1788  // residual objects
1790  if (_fe_problem.haveFV())
1791  {
1793  _fe_problem, this->number(), tags, /*on_displaced=*/false);
1795  Threads::parallel_reduce(faces, fvr);
1796  }
1798  displaced_problem && displaced_problem->haveFV())
1799  {
1801  _fe_problem, this->number(), tags, /*on_displaced=*/true);
1802  FVRange faces(displaced_problem->mesh().ownedFaceInfoBegin(),
1803  displaced_problem->mesh().ownedFaceInfoEnd());
1804  Threads::parallel_reduce(faces, fvr);
1805  }
1806 
1807  unsigned int n_threads = libMesh::n_threads();
1808  for (unsigned int i = 0; i < n_threads;
1809  i++) // Add any cached residuals that might be hanging around
1811  }
1812  PARALLEL_CATCH;
1813 
1814  // residual contributions from the scalar kernels
1815  PARALLEL_TRY
1816  {
1817  // do scalar kernels (not sure how to thread this)
1819  {
1820  TIME_SECTION("ScalarKernels", 3 /*, "Computing ScalarKernels"*/);
1821 
1822  MooseObjectWarehouse<ScalarKernelBase> * scalar_kernel_warehouse;
1823  // This code should be refactored once we can do tags for scalar
1824  // kernels
1825  // Should redo this based on Warehouse
1826  if (!tags.size() || tags.size() == _fe_problem.numVectorTags(Moose::VECTOR_TAG_RESIDUAL))
1827  scalar_kernel_warehouse = &_scalar_kernels;
1828  else if (tags.size() == 1)
1829  scalar_kernel_warehouse =
1830  &(_scalar_kernels.getVectorTagObjectWarehouse(*(tags.begin()), 0));
1831  else
1832  // scalar_kernels is not threading
1833  scalar_kernel_warehouse = &(_scalar_kernels.getVectorTagsObjectWarehouse(tags, 0));
1834 
1835  bool have_scalar_contributions = false;
1836  const auto & scalars = scalar_kernel_warehouse->getActiveObjects();
1837  for (const auto & scalar_kernel : scalars)
1838  {
1839  scalar_kernel->reinit();
1840  const std::vector<dof_id_type> & dof_indices = scalar_kernel->variable().dofIndices();
1841  const DofMap & dof_map = scalar_kernel->variable().dofMap();
1842  const dof_id_type first_dof = dof_map.first_dof();
1843  const dof_id_type end_dof = dof_map.end_dof();
1844  for (dof_id_type dof : dof_indices)
1845  {
1846  if (dof >= first_dof && dof < end_dof)
1847  {
1848  scalar_kernel->computeResidual();
1849  have_scalar_contributions = true;
1850  break;
1851  }
1852  }
1853  }
1854  if (have_scalar_contributions)
1856  }
1857  }
1858  PARALLEL_CATCH;
1859 
1860  // residual contributions from Block NodalKernels
1861  PARALLEL_TRY
1862  {
1864  {
1865  TIME_SECTION("NodalKernels", 3 /*, "Computing NodalKernels"*/);
1866 
1868 
1870 
1871  if (range.begin() != range.end())
1872  {
1873  _fe_problem.reinitNode(*range.begin(), 0);
1874 
1875  Threads::parallel_reduce(range, cnk);
1876 
1877  unsigned int n_threads = libMesh::n_threads();
1878  for (unsigned int i = 0; i < n_threads;
1879  i++) // Add any cached residuals that might be hanging around
1881  }
1882  }
1883  }
1884  PARALLEL_CATCH;
1885 
1887  // We computed the volumetric objects. We can return now before we get into
1888  // any strongly enforced constraint conditions or penalty-type objects
1889  // (DGKernels, IntegratedBCs, InterfaceKernels, Constraints)
1890  return;
1891 
1892  // residual contributions from boundary NodalKernels
1893  PARALLEL_TRY
1894  {
1896  {
1897  TIME_SECTION("NodalKernelBCs", 3 /*, "Computing NodalKernelBCs"*/);
1898 
1900 
1902 
1903  Threads::parallel_reduce(bnd_node_range, cnk);
1904 
1905  unsigned int n_threads = libMesh::n_threads();
1906  for (unsigned int i = 0; i < n_threads;
1907  i++) // Add any cached residuals that might be hanging around
1909  }
1910  }
1911  PARALLEL_CATCH;
1912 
1914 
1915  if (_residual_copy.get())
1916  {
1917  _Re_non_time->close();
1919  }
1920 
1922  {
1923  _Re_non_time->close();
1926  }
1927 
1928  PARALLEL_TRY { computeDiracContributions(tags, false); }
1929  PARALLEL_CATCH;
1930 
1932  {
1933  PARALLEL_TRY { enforceNodalConstraintsResidual(*_Re_non_time); }
1934  PARALLEL_CATCH;
1935  _Re_non_time->close();
1936  }
1937 
1938  // Add in Residual contributions from other Constraints
1940  {
1941  PARALLEL_TRY
1942  {
1943  // Undisplaced Constraints
1945 
1946  // Displaced Constraints
1949 
1952  }
1953  PARALLEL_CATCH;
1954  _Re_non_time->close();
1955  }
1956 
1957  // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
1958  // counters
1961 }
1962 
1963 void
1965  const std::set<TagID> & matrix_tags)
1966 {
1967  TIME_SECTION("computeResidualAndJacobianInternal", 3);
1968 
1969  // Make matrix ready to use
1971 
1972  for (auto tag : matrix_tags)
1973  {
1974  if (!hasMatrix(tag))
1975  continue;
1976 
1977  auto & jacobian = getMatrix(tag);
1978  // Necessary for speed
1979  if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&jacobian))
1980  {
1981  LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
1982  MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
1983  PETSC_TRUE));
1985  LibmeshPetscCall(
1986  MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
1988  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
1989  MAT_IGNORE_ZERO_ENTRIES,
1990  PETSC_TRUE));
1991  }
1992  }
1993 
1994  residualSetup();
1995 
1996  // Residual contributions from UOs - for now this is used for ray tracing
1997  // and ray kernels that contribute to the residual (think line sources)
1998  std::vector<UserObject *> uos;
2000  .query()
2001  .condition<AttribSystem>("UserObject")
2002  .condition<AttribExecOns>(EXEC_PRE_KERNELS)
2003  .queryInto(uos);
2004  for (auto & uo : uos)
2005  uo->residualSetup();
2006  for (auto & uo : uos)
2007  {
2008  uo->initialize();
2009  uo->execute();
2010  uo->finalize();
2011  }
2012 
2013  // reinit scalar variables
2014  for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
2016 
2017 #ifdef MOOSE_KOKKOS_ENABLED
2019  computeKokkosResidualAndJacobian(vector_tags, matrix_tags);
2020 #endif
2021 
2022  // residual contributions from the domain
2023  PARALLEL_TRY
2024  {
2025  TIME_SECTION("Kernels", 3 /*, "Computing Kernels"*/);
2026 
2028 
2029  ComputeResidualAndJacobianThread crj(_fe_problem, vector_tags, matrix_tags);
2030  Threads::parallel_reduce(elem_range, crj);
2031 
2033  if (_fe_problem.haveFV())
2034  {
2036  _fe_problem, this->number(), vector_tags, matrix_tags, /*on_displaced=*/false);
2038  Threads::parallel_reduce(faces, fvrj);
2039  }
2041  displaced_problem && displaced_problem->haveFV())
2042  {
2044  _fe_problem, this->number(), vector_tags, matrix_tags, /*on_displaced=*/true);
2045  FVRange faces(displaced_problem->mesh().ownedFaceInfoBegin(),
2046  displaced_problem->mesh().ownedFaceInfoEnd());
2047  Threads::parallel_reduce(faces, fvr);
2048  }
2049 
2051 
2052  unsigned int n_threads = libMesh::n_threads();
2053  for (unsigned int i = 0; i < n_threads;
2054  i++) // Add any cached residuals that might be hanging around
2055  {
2058  }
2059  }
2060  PARALLEL_CATCH;
2061 }
2062 
2063 void
2065 {
2066  _nl_vector_tags.clear();
2067 
2068  const auto & residual_vector_tags = _fe_problem.getVectorTags(Moose::VECTOR_TAG_RESIDUAL);
2069  for (const auto & residual_vector_tag : residual_vector_tags)
2070  _nl_vector_tags.insert(residual_vector_tag._id);
2071 
2075 }
2076 
2077 void
2079  const std::set<TagID> & tags)
2080 {
2082 
2084 
2086 }
2087 
2088 void
2090 {
2091 #ifdef MOOSE_KOKKOS_ENABLED
2094 #endif
2095 
2096  // We need to close the diag_save_in variables on the aux system before NodalBCBases clear the
2097  // dofs on boundary nodes
2098  if (_has_save_in)
2100 
2101  // Select nodal kernels
2102  MooseObjectWarehouse<NodalBCBase> * nbc_warehouse;
2103 
2104  if (tags.size() == _fe_problem.numVectorTags(Moose::VECTOR_TAG_RESIDUAL) || !tags.size())
2105  nbc_warehouse = &_nodal_bcs;
2106  else if (tags.size() == 1)
2107  nbc_warehouse = &(_nodal_bcs.getVectorTagObjectWarehouse(*(tags.begin()), 0));
2108  else
2109  nbc_warehouse = &(_nodal_bcs.getVectorTagsObjectWarehouse(tags, 0));
2110 
2111  // Return early if there is no nodal kernel
2112  if (!nbc_warehouse->hasActiveObjects())
2113  return;
2114 
2115  PARALLEL_TRY
2116  {
2118 
2119  if (!bnd_nodes.empty())
2120  {
2121  TIME_SECTION("NodalBCs", 3 /*, "Computing NodalBCs"*/);
2122 
2123  for (const auto & bnode : bnd_nodes)
2124  {
2125  BoundaryID boundary_id = bnode->_bnd_id;
2126  Node * node = bnode->_node;
2127 
2128  if (node->processor_id() == processor_id() &&
2129  nbc_warehouse->hasActiveBoundaryObjects(boundary_id))
2130  {
2131  // reinit variables in nodes
2132  _fe_problem.reinitNodeFace(node, boundary_id, 0);
2133 
2134  const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id);
2135  for (const auto & nbc : bcs)
2136  if (nbc->shouldApply())
2137  nbc->computeResidual();
2138  }
2139  }
2140  }
2141  }
2142  PARALLEL_CATCH;
2143 
2144  if (_Re_time)
2145  _Re_time->close();
2146  _Re_non_time->close();
2147 }
2148 
2149 void
2151 {
2152  // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs
2153  // on boundary nodes
2154  if (_has_diag_save_in)
2156 
2157  MooseObjectWarehouse<NodalBCBase> * nbc_warehouse;
2158 
2159  // Select nodal kernels
2160  if (tags.size() == _fe_problem.numMatrixTags() || !tags.size())
2161  nbc_warehouse = &_nodal_bcs;
2162  else if (tags.size() == 1)
2163  nbc_warehouse = &(_nodal_bcs.getMatrixTagObjectWarehouse(*(tags.begin()), 0));
2164  else
2165  nbc_warehouse = &(_nodal_bcs.getMatrixTagsObjectWarehouse(tags, 0));
2166 
2167  // Return early if there is no nodal kernel
2168  if (!nbc_warehouse->hasActiveObjects())
2169  return;
2170 
2171  PARALLEL_TRY
2172  {
2173  // We may be switching from add to set. Moreover, we rely on a call to MatZeroRows to enforce
2174  // the nodal boundary condition constraints which requires that the matrix be truly assembled
2175  // as opposed to just flushed. Consequently we can't do the following despite any desire to
2176  // keep our initial sparsity pattern honored (see https://gitlab.com/petsc/petsc/-/issues/852)
2177  //
2178  // flushTaggedMatrices(tags);
2179  closeTaggedMatrices(tags);
2180 
2181  // Cache the information about which BCs are coupled to which
2182  // variables, so we don't have to figure it out for each node.
2183  std::map<std::string, std::set<unsigned int>> bc_involved_vars;
2184  const std::set<BoundaryID> & all_boundary_ids = _mesh.getBoundaryIDs();
2185  for (const auto & bid : all_boundary_ids)
2186  {
2187  // Get reference to all the NodalBCs for this ID. This is only
2188  // safe if there are NodalBCBases there to be gotten...
2189  if (nbc_warehouse->hasActiveBoundaryObjects(bid))
2190  {
2191  const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(bid);
2192  for (const auto & bc : bcs)
2193  {
2194  const std::vector<MooseVariableFEBase *> & coupled_moose_vars = bc->getCoupledMooseVars();
2195 
2196  // Create the set of "involved" MOOSE nonlinear vars, which includes all coupled vars
2197  // and the BC's own variable
2198  std::set<unsigned int> & var_set = bc_involved_vars[bc->name()];
2199  for (const auto & coupled_var : coupled_moose_vars)
2200  if (coupled_var->kind() == Moose::VAR_SOLVER)
2201  var_set.insert(coupled_var->number());
2202 
2203  var_set.insert(bc->variable().number());
2204  }
2205  }
2206  }
2207 
2208  // reinit scalar variables again. This reinit does not re-fill any of the scalar variable
2209  // solution arrays because that was done above. It only will reorder the derivative
2210  // information for AD calculations to be suitable for NodalBC calculations
2211  for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
2212  _fe_problem.reinitScalars(tid, true);
2213 
2214  // Get variable coupling list. We do all the NodalBCBase stuff on
2215  // thread 0... The couplingEntries() data structure determines
2216  // which variables are "coupled" as far as the preconditioner is
2217  // concerned, not what variables a boundary condition specifically
2218  // depends on.
2219  auto & coupling_entries = _fe_problem.couplingEntries(/*_tid=*/0, this->number());
2220 
2221  // Compute Jacobians for NodalBCBases
2223  for (const auto & bnode : bnd_nodes)
2224  {
2225  BoundaryID boundary_id = bnode->_bnd_id;
2226  Node * node = bnode->_node;
2227 
2228  if (nbc_warehouse->hasActiveBoundaryObjects(boundary_id) &&
2229  node->processor_id() == processor_id())
2230  {
2231  _fe_problem.reinitNodeFace(node, boundary_id, 0);
2232 
2233  const auto & bcs = nbc_warehouse->getActiveBoundaryObjects(boundary_id);
2234  for (const auto & bc : bcs)
2235  {
2236  // Get the set of involved MOOSE vars for this BC
2237  std::set<unsigned int> & var_set = bc_involved_vars[bc->name()];
2238 
2239  // Loop over all the variables whose Jacobian blocks are
2240  // actually being computed, call computeOffDiagJacobian()
2241  // for each one which is actually coupled (otherwise the
2242  // value is zero.)
2243  for (const auto & it : coupling_entries)
2244  {
2245  unsigned int ivar = it.first->number(), jvar = it.second->number();
2246 
2247  // We are only going to call computeOffDiagJacobian() if:
2248  // 1.) the BC's variable is ivar
2249  // 2.) jvar is "involved" with the BC (including jvar==ivar), and
2250  // 3.) the BC should apply.
2251  if ((bc->variable().number() == ivar) && var_set.count(jvar) && bc->shouldApply())
2252  bc->computeOffDiagJacobian(jvar);
2253  }
2254 
2255  const auto & coupled_scalar_vars = bc->getCoupledMooseScalarVars();
2256  for (const auto & jvariable : coupled_scalar_vars)
2257  if (hasScalarVariable(jvariable->name()))
2258  bc->computeOffDiagJacobianScalar(jvariable->number());
2259  }
2260  }
2261  } // end loop over boundary nodes
2262 
2263  // Set the cached NodalBCBase values in the Jacobian matrix
2265  }
2266  PARALLEL_CATCH;
2267 }
2268 
2269 void
2271  [[maybe_unused]] const std::set<TagID> & vector_tags,
2272  [[maybe_unused]] const std::set<TagID> & matrix_tags)
2273 {
2274 #ifdef MOOSE_KOKKOS_ENABLED
2276  computeKokkosNodalBCsResidual(vector_tags);
2277 #endif
2278 
2279  // Return early if there is no nodal kernel
2281  return;
2282 
2283  PARALLEL_TRY
2284  {
2286 
2287  if (!bnd_nodes.empty())
2288  {
2289  TIME_SECTION("NodalBCs", 3 /*, "Computing NodalBCs"*/);
2290 
2291  for (const auto & bnode : bnd_nodes)
2292  {
2293  BoundaryID boundary_id = bnode->_bnd_id;
2294  Node * node = bnode->_node;
2295 
2296  if (node->processor_id() == processor_id())
2297  {
2298  // reinit variables in nodes
2299  _fe_problem.reinitNodeFace(node, boundary_id, 0);
2300  if (_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
2301  {
2302  const auto & bcs = _nodal_bcs.getActiveBoundaryObjects(boundary_id);
2303  for (const auto & nbc : bcs)
2304  if (nbc->shouldApply())
2305  nbc->computeResidualAndJacobian();
2306  }
2307  }
2308  }
2309  }
2310  }
2311  PARALLEL_CATCH;
2312 
2313  // Set the cached NodalBCBase values in the Jacobian matrix
2315 }
2316 
2317 void
2318 NonlinearSystemBase::getNodeDofs(dof_id_type node_id, std::vector<dof_id_type> & dofs)
2319 {
2320  const Node & node = _mesh.nodeRef(node_id);
2321  unsigned int s = number();
2322  if (node.has_dofs(s))
2323  {
2324  for (unsigned int v = 0; v < nVariables(); v++)
2325  for (unsigned int c = 0; c < node.n_comp(s, v); c++)
2326  dofs.push_back(node.dof_number(s, v, c));
2327  }
2328 }
2329 
2330 void
2332  GeometricSearchData & geom_search_data,
2333  std::unordered_map<dof_id_type, std::vector<dof_id_type>> & graph)
2334 {
2335  const auto & node_to_elem_map = _mesh.nodeToElemMap();
2336  const auto & nearest_node_locators = geom_search_data._nearest_node_locators;
2337  for (const auto & it : nearest_node_locators)
2338  {
2339  std::vector<dof_id_type> & secondary_nodes = it.second->_secondary_nodes;
2340 
2341  for (const auto & secondary_node : secondary_nodes)
2342  {
2343  std::set<dof_id_type> unique_secondary_indices;
2344  std::set<dof_id_type> unique_primary_indices;
2345 
2346  auto node_to_elem_pair = node_to_elem_map.find(secondary_node);
2347  if (node_to_elem_pair != node_to_elem_map.end())
2348  {
2349  const std::vector<dof_id_type> & elems = node_to_elem_pair->second;
2350 
2351  // Get the dof indices from each elem connected to the node
2352  for (const auto & cur_elem : elems)
2353  {
2354  std::vector<dof_id_type> dof_indices;
2355  dofMap().dof_indices(_mesh.elemPtr(cur_elem), dof_indices);
2356 
2357  for (const auto & dof : dof_indices)
2358  unique_secondary_indices.insert(dof);
2359  }
2360  }
2361 
2362  std::vector<dof_id_type> primary_nodes = it.second->_neighbor_nodes[secondary_node];
2363 
2364  for (const auto & primary_node : primary_nodes)
2365  {
2366  auto primary_node_to_elem_pair = node_to_elem_map.find(primary_node);
2367  mooseAssert(primary_node_to_elem_pair != node_to_elem_map.end(),
2368  "Missing entry in node to elem map");
2369  const std::vector<dof_id_type> & primary_node_elems = primary_node_to_elem_pair->second;
2370 
2371  // Get the dof indices from each elem connected to the node
2372  for (const auto & cur_elem : primary_node_elems)
2373  {
2374  std::vector<dof_id_type> dof_indices;
2375  dofMap().dof_indices(_mesh.elemPtr(cur_elem), dof_indices);
2376 
2377  for (const auto & dof : dof_indices)
2378  unique_primary_indices.insert(dof);
2379  }
2380  }
2381 
2382  for (const auto & secondary_id : unique_secondary_indices)
2383  for (const auto & primary_id : unique_primary_indices)
2384  {
2385  graph[secondary_id].push_back(primary_id);
2386  graph[primary_id].push_back(secondary_id);
2387  }
2388  }
2389  }
2390 
2391  // handle node-to-node constraints
2392  const auto & ncs = _constraints.getActiveNodalConstraints();
2393  for (const auto & nc : ncs)
2394  {
2395  std::vector<dof_id_type> primary_dofs;
2396  std::vector<dof_id_type> & primary_node_ids = nc->getPrimaryNodeId();
2397  for (const auto & node_id : primary_node_ids)
2398  {
2399  Node * node = _mesh.queryNodePtr(node_id);
2400  if (node && node->processor_id() == this->processor_id())
2401  {
2402  getNodeDofs(node_id, primary_dofs);
2403  }
2404  }
2405 
2406  _communicator.allgather(primary_dofs);
2407 
2408  std::vector<dof_id_type> secondary_dofs;
2409  std::vector<dof_id_type> & secondary_node_ids = nc->getSecondaryNodeId();
2410  for (const auto & node_id : secondary_node_ids)
2411  {
2412  Node * node = _mesh.queryNodePtr(node_id);
2413  if (node && node->processor_id() == this->processor_id())
2414  {
2415  getNodeDofs(node_id, secondary_dofs);
2416  }
2417  }
2418 
2419  _communicator.allgather(secondary_dofs);
2420 
2421  for (const auto & primary_id : primary_dofs)
2422  for (const auto & secondary_id : secondary_dofs)
2423  {
2424  graph[primary_id].push_back(secondary_id);
2425  graph[secondary_id].push_back(primary_id);
2426  }
2427  }
2428 
2429  // Make every entry sorted and unique
2430  for (auto & it : graph)
2431  {
2432  std::vector<dof_id_type> & row = it.second;
2433  std::sort(row.begin(), row.end());
2434  std::vector<dof_id_type>::iterator uit = std::unique(row.begin(), row.end());
2435  row.resize(uit - row.begin());
2436  }
2437 }
2438 
2439 void
2441 {
2442  if (!hasMatrix(systemMatrixTag()))
2443  mooseError("Need a system matrix ");
2444 
2445  // At this point, have no idea how to make
2446  // this work with tag system
2447  auto & jacobian = getMatrix(systemMatrixTag());
2448 
2449  std::unordered_map<dof_id_type, std::vector<dof_id_type>> graph;
2450 
2451  findImplicitGeometricCouplingEntries(geom_search_data, graph);
2452 
2453  for (const auto & it : graph)
2454  {
2455  dof_id_type dof = it.first;
2456  const auto & row = it.second;
2457 
2458  for (const auto & coupled_dof : row)
2459  jacobian.add(dof, coupled_dof, 0);
2460  }
2461 }
2462 
2463 void
2465  bool displaced)
2466 {
2467  if (!hasMatrix(systemMatrixTag()))
2468  mooseError("A system matrix is required");
2469 
2470  auto & jacobian = getMatrix(systemMatrixTag());
2471 
2473  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
2474  MAT_NEW_NONZERO_ALLOCATION_ERR,
2475  PETSC_FALSE));
2477  LibmeshPetscCall(MatSetOption(
2478  static_cast<PetscMatrix<Number> &>(jacobian).mat(), MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
2479 
2480  std::vector<numeric_index_type> zero_rows;
2481 
2482  if (displaced)
2483  mooseAssert(_fe_problem.getDisplacedProblem(),
2484  "If we're calling this method with displaced = true, then we better well have a "
2485  "displaced problem");
2486  auto & subproblem = displaced ? static_cast<SubProblem &>(*_fe_problem.getDisplacedProblem())
2487  : static_cast<SubProblem &>(_fe_problem);
2488  const auto & penetration_locators = subproblem.geomSearchData()._penetration_locators;
2489 
2490  bool constraints_applied;
2492  constraints_applied = false;
2493  for (const auto & it : penetration_locators)
2494  {
2496  {
2497  // Reset the constraint_applied flag before each new constraint, as they need to be
2498  // assembled separately
2499  constraints_applied = false;
2500  }
2501  PenetrationLocator & pen_loc = *(it.second);
2502 
2503  std::vector<dof_id_type> & secondary_nodes = pen_loc._nearest_node._secondary_nodes;
2504 
2505  BoundaryID secondary_boundary = pen_loc._secondary_boundary;
2506  BoundaryID primary_boundary = pen_loc._primary_boundary;
2507 
2508  zero_rows.clear();
2509  if (_constraints.hasActiveNodeFaceConstraints(secondary_boundary, displaced))
2510  {
2511  const auto & constraints =
2512  _constraints.getActiveNodeFaceConstraints(secondary_boundary, displaced);
2513 
2514  for (const auto & secondary_node_num : secondary_nodes)
2515  {
2516  Node & secondary_node = _mesh.nodeRef(secondary_node_num);
2517 
2518  if (secondary_node.processor_id() == processor_id())
2519  {
2520  if (pen_loc._penetration_info[secondary_node_num])
2521  {
2522  PenetrationInfo & info = *pen_loc._penetration_info[secondary_node_num];
2523 
2524  reinitNodeFace(secondary_node, secondary_boundary, info, displaced);
2526 
2527  for (const auto & nfc : constraints)
2528  {
2529  if (nfc->isExplicitConstraint())
2530  continue;
2531  // Return if this constraint does not correspond to the primary-secondary pair
2532  // prepared by the outer loops.
2533  // This continue statement is required when, e.g. one secondary surface constrains
2534  // more than one primary surface.
2535  if (nfc->secondaryBoundary() != secondary_boundary ||
2536  nfc->primaryBoundary() != primary_boundary)
2537  continue;
2538 
2539  nfc->_jacobian = &jacobian_to_view;
2540 
2541  if (nfc->shouldApply())
2542  {
2543  constraints_applied = true;
2544 
2545  // Begin the diagonal node-face constraint accumulation phase for neighbor Jacobian
2546  // blocks.
2548 
2549  nfc->prepareShapes(nfc->variable().number());
2550  nfc->prepareNeighborShapes(nfc->variable().number());
2551 
2552  nfc->computeJacobian();
2553 
2554  if (nfc->overwriteSecondaryJacobian())
2555  {
2556  // Add this variable's dof's row to be zeroed
2557  zero_rows.push_back(nfc->variable().nodalDofIndex());
2558  }
2559 
2560  std::vector<dof_id_type> secondary_dofs(1, nfc->variable().nodalDofIndex());
2561 
2562  // Assume that if the user is overwriting the secondary Jacobian, then they are
2563  // supplying Jacobians that do not correspond to their other physics
2564  // (e.g. Kernels), hence we should not apply a scalingFactor that is normally
2565  // based on the order of their other physics (e.g. Kernels)
2566  Real scaling_factor =
2567  nfc->overwriteSecondaryJacobian() ? 1. : nfc->variable().scalingFactor();
2568 
2569  // Cache the jacobian block for the secondary side
2570  nfc->addJacobian(_fe_problem.assembly(0, number()),
2571  nfc->_Kee,
2572  secondary_dofs,
2573  nfc->_connected_dof_indices,
2574  scaling_factor);
2575 
2576  // Cache Ken, Kne, Knn
2577  if (nfc->addCouplingEntriesToJacobian())
2578  {
2579  // Make sure we use a proper scaling factor (e.g. don't use an interior scaling
2580  // factor when we're overwriting secondary stuff)
2581  nfc->addJacobian(_fe_problem.assembly(0, number()),
2582  nfc->_Ken,
2583  secondary_dofs,
2584  nfc->primaryVariable().dofIndicesNeighbor(),
2585  scaling_factor);
2586 
2587  // Use _connected_dof_indices to get all the correct columns
2588  nfc->addJacobian(_fe_problem.assembly(0, number()),
2589  nfc->_Kne,
2590  nfc->primaryVariable().dofIndicesNeighbor(),
2591  nfc->_connected_dof_indices,
2592  nfc->primaryVariable().scalingFactor());
2593 
2594  // We've handled Ken and Kne, finally handle Knn
2596  }
2597 
2598  // Do the off-diagonals next
2599  const std::vector<MooseVariableFEBase *> coupled_vars = nfc->getCoupledMooseVars();
2600  for (const auto & jvar : coupled_vars)
2601  {
2602  // Only compute jacobians for nonlinear variables
2603  if (jvar->kind() != Moose::VAR_SOLVER)
2604  continue;
2605 
2606  // Only compute Jacobian entries if this coupling is being used by the
2607  // preconditioner
2608  if (nfc->variable().number() == jvar->number() ||
2610  nfc->variable().number(), jvar->number(), this->number()))
2611  continue;
2612 
2613  // Begin the off-diagonal node-face constraint accumulation phase for
2614  // element and neighbor Jacobian blocks.
2617 
2618  nfc->prepareShapes(nfc->variable().number());
2619  nfc->prepareNeighborShapes(jvar->number());
2620 
2621  nfc->computeOffDiagJacobian(jvar->number());
2622 
2623  // Cache the jacobian block for the secondary side
2624  nfc->addJacobian(_fe_problem.assembly(0, number()),
2625  nfc->_Kee,
2626  secondary_dofs,
2627  nfc->_connected_dof_indices,
2628  scaling_factor);
2629 
2630  // Cache Ken, Kne, Knn
2631  if (nfc->addCouplingEntriesToJacobian())
2632  {
2633  // Make sure we use a proper scaling factor (e.g. don't use an interior scaling
2634  // factor when we're overwriting secondary stuff)
2635  nfc->addJacobian(_fe_problem.assembly(0, number()),
2636  nfc->_Ken,
2637  secondary_dofs,
2638  jvar->dofIndicesNeighbor(),
2639  scaling_factor);
2640 
2641  // Use _connected_dof_indices to get all the correct columns
2642  nfc->addJacobian(_fe_problem.assembly(0, number()),
2643  nfc->_Kne,
2644  nfc->variable().dofIndicesNeighbor(),
2645  nfc->_connected_dof_indices,
2646  nfc->variable().scalingFactor());
2647 
2648  // We've handled Ken and Kne, finally handle Knn
2650  }
2651  }
2652  }
2653  }
2654  }
2655  }
2656  }
2657  }
2659  {
2660  // See if constraints were applied anywhere
2661  _communicator.max(constraints_applied);
2662 
2663  if (constraints_applied)
2664  {
2665  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
2666  MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
2667  PETSC_TRUE));
2668 
2669  jacobian.close();
2670  jacobian.zero_rows(zero_rows, 0.0);
2671  jacobian.close();
2673  jacobian.close();
2674  }
2675  }
2676  }
2678  {
2679  // See if constraints were applied anywhere
2680  _communicator.max(constraints_applied);
2681 
2682  if (constraints_applied)
2683  {
2684  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
2685  MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
2686  PETSC_TRUE));
2687 
2688  jacobian.close();
2689  jacobian.zero_rows(zero_rows, 0.0);
2690  jacobian.close();
2692  jacobian.close();
2693  }
2694  }
2695 
2696  THREAD_ID tid = 0;
2697  // go over element-element constraint interface
2698  const auto & element_pair_locators = subproblem.geomSearchData()._element_pair_locators;
2699  for (const auto & it : element_pair_locators)
2700  {
2701  ElementPairLocator & elem_pair_loc = *(it.second);
2702 
2703  if (_constraints.hasActiveElemElemConstraints(it.first, displaced))
2704  {
2705  // ElemElemConstraint objects
2706  const auto & element_constraints =
2707  _constraints.getActiveElemElemConstraints(it.first, displaced);
2708 
2709  // go over pair elements
2710  const std::list<std::pair<const Elem *, const Elem *>> & elem_pairs =
2711  elem_pair_loc.getElemPairs();
2712  for (const auto & pr : elem_pairs)
2713  {
2714  const Elem * elem1 = pr.first;
2715  const Elem * elem2 = pr.second;
2716 
2717  if (elem1->processor_id() != processor_id())
2718  continue;
2719 
2720  const ElementPairInfo & info = elem_pair_loc.getElemPairInfo(pr);
2721 
2722  // for each element process constraints on the
2723  for (const auto & ec : element_constraints)
2724  {
2725  _fe_problem.setCurrentSubdomainID(elem1, tid);
2726  subproblem.reinitElemPhys(elem1, info._elem1_constraint_q_point, tid);
2727  _fe_problem.setNeighborSubdomainID(elem2, tid);
2728  subproblem.reinitNeighborPhys(elem2, info._elem2_constraint_q_point, tid);
2729 
2730  // Begin the element-element constraint accumulation phase for element and neighbor
2731  // Jacobian blocks.
2734 
2735  ec->prepareShapes(ec->variable().number());
2736  ec->prepareNeighborShapes(ec->variable().number());
2737 
2738  ec->reinit(info);
2739  ec->computeJacobian();
2742  }
2744  }
2745  }
2746  }
2747 
2748  // go over NodeElemConstraints
2749  std::set<dof_id_type> unique_secondary_node_ids;
2750  constraints_applied = false;
2751  for (const auto & secondary_id : _mesh.meshSubdomains())
2752  {
2753  for (const auto & primary_id : _mesh.meshSubdomains())
2754  {
2755  if (_constraints.hasActiveNodeElemConstraints(secondary_id, primary_id, displaced))
2756  {
2757  const auto & constraints =
2758  _constraints.getActiveNodeElemConstraints(secondary_id, primary_id, displaced);
2759 
2760  // get unique set of ids of all nodes on current block
2761  unique_secondary_node_ids.clear();
2762  const MeshBase & meshhelper = _mesh.getMesh();
2763  for (const auto & elem : as_range(meshhelper.active_subdomain_elements_begin(secondary_id),
2764  meshhelper.active_subdomain_elements_end(secondary_id)))
2765  {
2766  for (auto & n : elem->node_ref_range())
2767  unique_secondary_node_ids.insert(n.id());
2768  }
2769 
2770  for (auto secondary_node_id : unique_secondary_node_ids)
2771  {
2772  const Node & secondary_node = _mesh.nodeRef(secondary_node_id);
2773  // check if secondary node is on current processor
2774  if (secondary_node.processor_id() == processor_id())
2775  {
2776  // This reinits the variables that exist on the secondary node
2777  _fe_problem.reinitNodeFace(&secondary_node, secondary_id, 0);
2778 
2780 
2781  for (const auto & nec : constraints)
2782  {
2783  if (nec->shouldApply())
2784  {
2785  constraints_applied = true;
2786 
2787  // Begin the diagonal node-element constraint accumulation phase for
2788  // element and neighbor Jacobian blocks.
2791 
2792  nec->_jacobian = &jacobian_to_view;
2793  nec->prepareShapes(nec->variable().number());
2794  nec->prepareNeighborShapes(nec->variable().number());
2795 
2796  nec->computeJacobian();
2797 
2798  if (nec->overwriteSecondaryJacobian())
2799  {
2800  // Add this variable's dof's row to be zeroed
2801  zero_rows.push_back(nec->variable().nodalDofIndex());
2802  }
2803 
2804  std::vector<dof_id_type> secondary_dofs(1, nec->variable().nodalDofIndex());
2805 
2806  // Cache the jacobian block for the secondary side
2807  nec->addJacobian(_fe_problem.assembly(0, number()),
2808  nec->_Kee,
2809  secondary_dofs,
2810  nec->_connected_dof_indices,
2811  nec->variable().scalingFactor());
2812 
2813  // Cache the jacobian block for the primary side
2814  nec->addJacobian(_fe_problem.assembly(0, number()),
2815  nec->_Kne,
2816  nec->primaryVariable().dofIndicesNeighbor(),
2817  nec->_connected_dof_indices,
2818  nec->primaryVariable().scalingFactor());
2819 
2822 
2823  // Do the off-diagonals next
2824  const std::vector<MooseVariableFEBase *> coupled_vars = nec->getCoupledMooseVars();
2825  for (const auto & jvar : coupled_vars)
2826  {
2827  // Only compute jacobians for nonlinear variables
2828  if (jvar->kind() != Moose::VAR_SOLVER)
2829  continue;
2830 
2831  // Only compute Jacobian entries if this coupling is being used by the
2832  // preconditioner
2833  if (nec->variable().number() == jvar->number() ||
2835  nec->variable().number(), jvar->number(), this->number()))
2836  continue;
2837 
2838  // Begin the off-diagonal node-element constraint accumulation phase for
2839  // element and neighbor Jacobian blocks.
2842 
2843  nec->prepareShapes(nec->variable().number());
2844  nec->prepareNeighborShapes(jvar->number());
2845 
2846  nec->computeOffDiagJacobian(jvar->number());
2847 
2848  // Cache the jacobian block for the secondary side
2849  nec->addJacobian(_fe_problem.assembly(0, number()),
2850  nec->_Kee,
2851  secondary_dofs,
2852  nec->_connected_dof_indices,
2853  nec->variable().scalingFactor());
2854 
2855  // Cache the jacobian block for the primary side
2856  nec->addJacobian(_fe_problem.assembly(0, number()),
2857  nec->_Kne,
2858  nec->variable().dofIndicesNeighbor(),
2859  nec->_connected_dof_indices,
2860  nec->variable().scalingFactor());
2861 
2864  }
2865  }
2866  }
2867  }
2868  }
2869  }
2870  }
2871  }
2872  // See if constraints were applied anywhere
2873  _communicator.max(constraints_applied);
2874 
2875  if (constraints_applied)
2876  {
2877  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
2878  MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
2879  PETSC_TRUE));
2880 
2881  jacobian.close();
2882  jacobian.zero_rows(zero_rows, 0.0);
2883  jacobian.close();
2885  jacobian.close();
2886  }
2887 }
2888 
2889 void
2891 {
2892  MooseObjectWarehouse<ScalarKernelBase> * scalar_kernel_warehouse;
2893 
2894  if (!tags.size() || tags.size() == _fe_problem.numMatrixTags())
2895  scalar_kernel_warehouse = &_scalar_kernels;
2896  else if (tags.size() == 1)
2897  scalar_kernel_warehouse = &(_scalar_kernels.getMatrixTagObjectWarehouse(*(tags.begin()), 0));
2898  else
2899  scalar_kernel_warehouse = &(_scalar_kernels.getMatrixTagsObjectWarehouse(tags, 0));
2900 
2901  // Compute the diagonal block for scalar variables
2902  if (scalar_kernel_warehouse->hasActiveObjects())
2903  {
2904  const auto & scalars = scalar_kernel_warehouse->getActiveObjects();
2905 
2906  _fe_problem.reinitScalars(/*tid=*/0);
2907 
2908  _fe_problem.reinitOffDiagScalars(/*_tid*/ 0);
2909 
2910  bool have_scalar_contributions = false;
2911  for (const auto & kernel : scalars)
2912  {
2913  if (!kernel->computesJacobian())
2914  continue;
2915 
2916  kernel->reinit();
2917  const std::vector<dof_id_type> & dof_indices = kernel->variable().dofIndices();
2918  const DofMap & dof_map = kernel->variable().dofMap();
2919  const dof_id_type first_dof = dof_map.first_dof();
2920  const dof_id_type end_dof = dof_map.end_dof();
2921  for (dof_id_type dof : dof_indices)
2922  {
2923  if (dof >= first_dof && dof < end_dof)
2924  {
2925  kernel->computeJacobian();
2926  _fe_problem.addJacobianOffDiagScalar(kernel->variable().number());
2927  have_scalar_contributions = true;
2928  break;
2929  }
2930  }
2931  }
2932 
2933  if (have_scalar_contributions)
2935  }
2936 }
2937 
2938 void
2940 {
2942 
2943  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
2944  {
2945  _kernels.jacobianSetup(tid);
2948  if (_doing_dg)
2954  }
2961 
2962 #ifdef MOOSE_KOKKOS_ENABLED
2967 #endif
2968 
2969  // Avoid recursion
2970  if (this == &_fe_problem.currentNonlinearSystem())
2972 }
2973 
2974 void
2976 {
2977  TIME_SECTION("computeJacobianInternal", 3);
2978 
2980 
2981  // Make matrix ready to use
2983 
2984  for (auto tag : tags)
2985  {
2986  if (!hasMatrix(tag))
2987  continue;
2988 
2989  auto & jacobian = getMatrix(tag);
2990  // Necessary for speed
2991  if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&jacobian))
2992  {
2993  LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
2994  MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
2995  PETSC_TRUE));
2997  LibmeshPetscCall(
2998  MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
3000  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
3001  MAT_IGNORE_ZERO_ENTRIES,
3002  PETSC_TRUE));
3003  }
3004  }
3005 
3006  jacobianSetup();
3007 
3008  // Jacobian contributions from UOs - for now this is used for ray tracing
3009  // and ray kernels that contribute to the Jacobian (think line sources)
3010  std::vector<UserObject *> uos;
3012  .query()
3013  .condition<AttribSystem>("UserObject")
3014  .condition<AttribExecOns>(EXEC_PRE_KERNELS)
3015  .queryInto(uos);
3016  for (auto & uo : uos)
3017  uo->jacobianSetup();
3018  for (auto & uo : uos)
3019  {
3020  uo->initialize();
3021  uo->execute();
3022  uo->finalize();
3023  }
3024 
3025  // reinit scalar variables
3026  for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
3028 
3029 #ifdef MOOSE_KOKKOS_ENABLED
3031  computeKokkosJacobian(tags);
3032 #endif
3033 
3034  PARALLEL_TRY
3035  {
3036  // We would like to compute ScalarKernels, block NodalKernels, FVFluxKernels, and mortar objects
3037  // up front because we want these included whether we are computing an ordinary Jacobian or a
3038  // Jacobian for determining variable scaling factors
3040 
3041  // Block restricted Nodal Kernels
3043  {
3046  Threads::parallel_reduce(range, cnkjt);
3047 
3048  unsigned int n_threads = libMesh::n_threads();
3049  for (unsigned int i = 0; i < n_threads;
3050  i++) // Add any cached jacobians that might be hanging around
3052  }
3053 
3055  if (_fe_problem.haveFV())
3056  {
3057  // the same loop works for both residual and jacobians because it keys
3058  // off of FEProblem's _currently_computing_jacobian parameter
3060  _fe_problem, this->number(), tags, /*on_displaced=*/false);
3062  Threads::parallel_reduce(faces, fvj);
3063  }
3065  displaced_problem && displaced_problem->haveFV())
3066  {
3068  _fe_problem, this->number(), tags, /*on_displaced=*/true);
3069  FVRange faces(displaced_problem->mesh().ownedFaceInfoBegin(),
3070  displaced_problem->mesh().ownedFaceInfoEnd());
3071  Threads::parallel_reduce(faces, fvr);
3072  }
3073 
3075 
3076  // Get our element range for looping over
3078 
3080  {
3081  // Only compute Jacobians corresponding to the diagonals of volumetric compute objects
3082  // because this typically gives us a good representation of the physics. NodalBCs and
3083  // Constraints can introduce dramatically different scales (often order unity).
3084  // IntegratedBCs and/or InterfaceKernels may use penalty factors. DGKernels may be ok, but
3085  // they are almost always used in conjunction with Kernels
3087  Threads::parallel_reduce(elem_range, cj);
3088  unsigned int n_threads = libMesh::n_threads();
3089  for (unsigned int i = 0; i < n_threads;
3090  i++) // Add any Jacobian contributions still hanging around
3092 
3093  // Check whether any exceptions were thrown and propagate this information for parallel
3094  // consistency before
3095  // 1) we do parallel communication when closing tagged matrices
3096  // 2) early returning before reaching our PARALLEL_CATCH below
3098 
3099  closeTaggedMatrices(tags);
3100 
3101  return;
3102  }
3103 
3104  switch (_fe_problem.coupling())
3105  {
3106  case Moose::COUPLING_DIAG:
3107  {
3109  Threads::parallel_reduce(elem_range, cj);
3110 
3111  unsigned int n_threads = libMesh::n_threads();
3112  for (unsigned int i = 0; i < n_threads;
3113  i++) // Add any Jacobian contributions still hanging around
3115 
3116  // Boundary restricted Nodal Kernels
3118  {
3121 
3122  Threads::parallel_reduce(bnd_range, cnkjt);
3123  unsigned int n_threads = libMesh::n_threads();
3124  for (unsigned int i = 0; i < n_threads;
3125  i++) // Add any cached jacobians that might be hanging around
3127  }
3128  }
3129  break;
3130 
3131  default:
3133  {
3135  Threads::parallel_reduce(elem_range, cj);
3136  unsigned int n_threads = libMesh::n_threads();
3137 
3138  for (unsigned int i = 0; i < n_threads; i++)
3140 
3141  // Boundary restricted Nodal Kernels
3143  {
3146 
3147  Threads::parallel_reduce(bnd_range, cnkjt);
3148  unsigned int n_threads = libMesh::n_threads();
3149  for (unsigned int i = 0; i < n_threads;
3150  i++) // Add any cached jacobians that might be hanging around
3152  }
3153  }
3154  break;
3155  }
3156 
3157  computeDiracContributions(tags, true);
3158 
3159  static bool first = true;
3160 
3161  // This adds zeroes into geometric coupling entries to ensure they stay in the matrix
3162  if ((_fe_problem.restoreOriginalNonzeroPattern() || first) &&
3164  {
3165  first = false;
3167 
3170  }
3171  }
3172  PARALLEL_CATCH;
3173 
3174  // Have no idea how to have constraints work
3175  // with the tag system
3176  PARALLEL_TRY
3177  {
3178  // Add in Jacobian contributions from other Constraints
3179  if (_fe_problem._has_constraints && tags.count(systemMatrixTag()))
3180  {
3181  // Some constraints need to be able to read values from the Jacobian, which requires that it
3182  // be closed/assembled
3183  auto & system_matrix = getMatrix(systemMatrixTag());
3184  std::unique_ptr<SparseMatrix<Number>> hash_copy;
3185  const SparseMatrix<Number> * view_jac_ptr;
3186  auto make_readable_jacobian = [&]()
3187  {
3188 #if PETSC_RELEASE_GREATER_EQUALS(3, 23, 0)
3189  if (system_matrix.use_hash_table())
3190  {
3191  hash_copy = libMesh::cast_ref<PetscMatrix<Number> &>(system_matrix).copy_from_hash();
3192  view_jac_ptr = hash_copy.get();
3193  }
3194  else
3195  view_jac_ptr = &system_matrix;
3196 #else
3197  view_jac_ptr = &system_matrix;
3198 #endif
3199  if (view_jac_ptr == &system_matrix)
3200  system_matrix.close();
3201  };
3202 
3203  make_readable_jacobian();
3204 
3205  // Nodal Constraints
3206  const bool had_nodal_constraints = enforceNodalConstraintsJacobian(*view_jac_ptr);
3207  if (had_nodal_constraints)
3208  // We have to make a new readable Jacobian
3209  make_readable_jacobian();
3210 
3211  // Undisplaced Constraints
3212  constraintJacobians(*view_jac_ptr, false);
3213 
3214  // Displaced Constraints
3216  constraintJacobians(*view_jac_ptr, true);
3217  }
3218  }
3219  PARALLEL_CATCH;
3220 
3222  closeTaggedMatrices(tags);
3223 
3224  // We need to close the save_in variables on the aux system before NodalBCBases clear the dofs
3225  // on boundary nodes
3228 
3229  if (hasDiagSaveIn())
3231 
3232  // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
3233  // counters
3236 }
3237 
3238 void
3240 {
3241  _nl_matrix_tags.clear();
3242 
3243  auto & tags = _fe_problem.getMatrixTags();
3244 
3245  for (auto & tag : tags)
3246  _nl_matrix_tags.insert(tag.second);
3247 
3248  computeJacobian(jacobian, _nl_matrix_tags);
3249 }
3250 
3251 void
3252 NonlinearSystemBase::computeJacobian(SparseMatrix<Number> & jacobian, const std::set<TagID> & tags)
3253 {
3255 
3256  computeJacobianTags(tags);
3257 
3259 }
3260 
3261 void
3262 NonlinearSystemBase::computeJacobianTags(const std::set<TagID> & tags)
3263 {
3264  TIME_SECTION("computeJacobianTags", 5);
3265 
3266  FloatingPointExceptionGuard fpe_guard(_app);
3267 
3268  try
3269  {
3271  }
3272  catch (MooseException & e)
3273  {
3274  // The buck stops here, we have already handled the exception by
3275  // calling stopSolve(), it is now up to PETSc to return a
3276  // "diverged" reason during the next solve.
3277  }
3278 }
3279 
3280 void
3282 {
3283  _nl_matrix_tags.clear();
3284 
3285  auto & tags = _fe_problem.getMatrixTags();
3286  for (auto & tag : tags)
3287  _nl_matrix_tags.insert(tag.second);
3288 
3290 }
3291 
3292 void
3294  const std::set<TagID> & tags)
3295 {
3296  TIME_SECTION("computeJacobianBlocks", 3);
3297  FloatingPointExceptionGuard fpe_guard(_app);
3298 
3299  for (unsigned int i = 0; i < blocks.size(); i++)
3300  {
3301  SparseMatrix<Number> & jacobian = blocks[i]->_jacobian;
3302 
3303  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
3304  MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
3305  PETSC_TRUE));
3307  LibmeshPetscCall(MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
3308  MAT_NEW_NONZERO_ALLOCATION_ERR,
3309  PETSC_TRUE));
3310 
3311  jacobian.zero();
3312  }
3313 
3314  for (unsigned int tid = 0; tid < libMesh::n_threads(); tid++)
3316 
3317  PARALLEL_TRY
3318  {
3321  Threads::parallel_reduce(elem_range, cjb);
3322  }
3323  PARALLEL_CATCH;
3324 
3325  for (unsigned int i = 0; i < blocks.size(); i++)
3326  blocks[i]->_jacobian.close();
3327 
3328  for (unsigned int i = 0; i < blocks.size(); i++)
3329  {
3330  libMesh::System & precond_system = blocks[i]->_precond_system;
3331  SparseMatrix<Number> & jacobian = blocks[i]->_jacobian;
3332 
3333  unsigned int ivar = blocks[i]->_ivar;
3334  unsigned int jvar = blocks[i]->_jvar;
3335 
3336  // Dirichlet BCs
3337  std::vector<numeric_index_type> zero_rows;
3338  PARALLEL_TRY
3339  {
3341  for (const auto & bnode : bnd_nodes)
3342  {
3343  BoundaryID boundary_id = bnode->_bnd_id;
3344  Node * node = bnode->_node;
3345 
3346  if (_nodal_bcs.hasActiveBoundaryObjects(boundary_id))
3347  {
3348  const auto & bcs = _nodal_bcs.getActiveBoundaryObjects(boundary_id);
3349 
3350  if (node->processor_id() == processor_id())
3351  {
3352  _fe_problem.reinitNodeFace(node, boundary_id, 0);
3353 
3354  for (const auto & bc : bcs)
3355  if (bc->variable().number() == ivar && bc->shouldApply())
3356  {
3357  // The first zero is for the variable number... there is only one variable in
3358  // each mini-system The second zero only works with Lagrange elements!
3359  zero_rows.push_back(node->dof_number(precond_system.number(), 0, 0));
3360  }
3361  }
3362  }
3363  }
3364  }
3365  PARALLEL_CATCH;
3366 
3367  jacobian.close();
3368 
3369  // This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
3370  if (ivar == jvar)
3371  jacobian.zero_rows(zero_rows, 1.0);
3372  else
3373  jacobian.zero_rows(zero_rows, 0.0);
3374 
3375  jacobian.close();
3376  }
3377 }
3378 
3379 void
3381 {
3388  _kernels.updateActive(tid);
3390 
3391  if (tid == 0)
3392  {
3400 
3401 #ifdef MOOSE_KOKKOS_ENABLED
3407 #endif
3408  }
3409 }
3410 
3411 Real
3413  const NumericVector<Number> & update)
3414 {
3415  // Default to no damping
3416  Real damping = 1.0;
3417  bool has_active_dampers = false;
3418 
3419  try
3420  {
3422  {
3423  PARALLEL_TRY
3424  {
3425  TIME_SECTION("computeDampers", 3, "Computing Dampers");
3426  has_active_dampers = true;
3429  Threads::parallel_reduce(_fe_problem.getCurrentAlgebraicElementRange(), cid);
3430  damping = std::min(cid.damping(), damping);
3431  }
3432  PARALLEL_CATCH;
3433  }
3434 
3436  {
3437  PARALLEL_TRY
3438  {
3439  TIME_SECTION("computeDamping::element", 3, "Computing Element Damping");
3440 
3441  has_active_dampers = true;
3444  Threads::parallel_reduce(_fe_problem.getCurrentAlgebraicNodeRange(), cndt);
3445  damping = std::min(cndt.damping(), damping);
3446  }
3447  PARALLEL_CATCH;
3448  }
3449 
3451  {
3452  PARALLEL_TRY
3453  {
3454  TIME_SECTION("computeDamping::general", 3, "Computing General Damping");
3455 
3456  has_active_dampers = true;
3457  const auto & gdampers = _general_dampers.getActiveObjects();
3458  for (const auto & damper : gdampers)
3459  {
3460  Real gd_damping = damper->computeDamping(solution, update);
3461  try
3462  {
3463  damper->checkMinDamping(gd_damping);
3464  }
3465  catch (MooseException & e)
3466  {
3468  }
3469  damping = std::min(gd_damping, damping);
3470  }
3471  }
3472  PARALLEL_CATCH;
3473  }
3474  }
3475  catch (MooseException & e)
3476  {
3477  // The buck stops here, we have already handled the exception by
3478  // calling stopSolve(), it is now up to PETSc to return a
3479  // "diverged" reason during the next solve.
3480  }
3481  catch (std::exception & e)
3482  {
3483  // Allow the libmesh error/exception on negative jacobian
3484  const std::string & message = e.what();
3485  if (message.find("Jacobian") == std::string::npos)
3486  throw;
3487  }
3488 
3489  _communicator.min(damping);
3490 
3491  if (has_active_dampers && damping < 1.0)
3492  _console << " Damping factor: " << damping << std::endl;
3493 
3494  return damping;
3495 }
3496 
3497 void
3498 NonlinearSystemBase::computeDiracContributions(const std::set<TagID> & tags, bool is_jacobian)
3499 {
3501 
3502  std::set<const Elem *> dirac_elements;
3503 
3505  {
3506  TIME_SECTION("computeDirac", 3, "Computing DiracKernels");
3507 
3508  // TODO: Need a threading fix... but it's complicated!
3509  for (THREAD_ID tid = 0; tid < libMesh::n_threads(); ++tid)
3510  {
3511  const auto & dkernels = _dirac_kernels.getActiveObjects(tid);
3512  for (const auto & dkernel : dkernels)
3513  {
3514  dkernel->clearPoints();
3515  dkernel->addPoints();
3516  }
3517  }
3518 
3519  ComputeDiracThread cd(_fe_problem, tags, is_jacobian);
3520 
3521  _fe_problem.getDiracElements(dirac_elements);
3522 
3523  DistElemRange range(dirac_elements.begin(), dirac_elements.end(), 1);
3524  // TODO: Make Dirac work thread!
3525  // Threads::parallel_reduce(range, cd);
3526 
3527  cd(range);
3528 
3529  if (is_jacobian)
3530  for (const auto tid : make_range(libMesh::n_threads()))
3532  }
3533 }
3534 
3537 {
3538  if (!_residual_copy.get())
3540 
3541  return *_residual_copy;
3542 }
3543 
3546 {
3547  _need_residual_ghosted = true;
3548  if (!_residual_ghosted)
3549  {
3550  // The first time we realize we need a ghosted residual vector,
3551  // we add it.
3552  _residual_ghosted = &addVector("residual_ghosted", false, GHOSTED);
3553 
3554  // If we've already realized we need time and/or non-time
3555  // residual vectors, but we haven't yet realized they need to be
3556  // ghosted, fix that now.
3557  //
3558  // If an application changes its mind, the libMesh API lets us
3559  // change the vector.
3560  if (_Re_time)
3561  {
3562  const auto vector_name = _subproblem.vectorTagName(_Re_time_tag);
3563  _Re_time = &system().add_vector(vector_name, false, GHOSTED);
3564  }
3565  if (_Re_non_time)
3566  {
3567  const auto vector_name = _subproblem.vectorTagName(_Re_non_time_tag);
3568  _Re_non_time = &system().add_vector(vector_name, false, GHOSTED);
3569  }
3570  }
3571  return *_residual_ghosted;
3572 }
3573 
3574 void
3576  std::vector<dof_id_type> & n_nz,
3577  std::vector<dof_id_type> & n_oz)
3578 {
3580  {
3582 
3583  std::unordered_map<dof_id_type, std::vector<dof_id_type>> graph;
3584 
3586 
3589  graph);
3590 
3591  const dof_id_type first_dof_on_proc = dofMap().first_dof(processor_id());
3592  const dof_id_type end_dof_on_proc = dofMap().end_dof(processor_id());
3593 
3594  // The total number of dofs on and off processor
3595  const dof_id_type n_dofs_on_proc = dofMap().n_local_dofs();
3596  const dof_id_type n_dofs_not_on_proc = dofMap().n_dofs() - dofMap().n_local_dofs();
3597 
3598  for (const auto & git : graph)
3599  {
3600  dof_id_type dof = git.first;
3601  dof_id_type local_dof = dof - first_dof_on_proc;
3602 
3603  if (dof < first_dof_on_proc || dof >= end_dof_on_proc)
3604  continue;
3605 
3606  const auto & row = git.second;
3607 
3608  SparsityPattern::Row & sparsity_row = sparsity[local_dof];
3609 
3610  unsigned int original_row_length = sparsity_row.size();
3611 
3612  sparsity_row.insert(sparsity_row.end(), row.begin(), row.end());
3613 
3614  SparsityPattern::sort_row(
3615  sparsity_row.begin(), sparsity_row.begin() + original_row_length, sparsity_row.end());
3616 
3617  // Fix up nonzero arrays
3618  for (const auto & coupled_dof : row)
3619  {
3620  if (coupled_dof < first_dof_on_proc || coupled_dof >= end_dof_on_proc)
3621  {
3622  if (n_oz[local_dof] < n_dofs_not_on_proc)
3623  n_oz[local_dof]++;
3624  }
3625  else
3626  {
3627  if (n_nz[local_dof] < n_dofs_on_proc)
3628  n_nz[local_dof]++;
3629  }
3630  }
3631  }
3632  }
3633 }
3634 
3635 void
3637 {
3638  *_u_dot = u_dot;
3639 }
3640 
3641 void
3643 {
3644  *_u_dotdot = u_dotdot;
3645 }
3646 
3647 void
3649 {
3650  *_u_dot_old = u_dot_old;
3651 }
3652 
3653 void
3655 {
3656  *_u_dotdot_old = u_dotdot_old;
3657 }
3658 
3659 void
3660 NonlinearSystemBase::setPreconditioner(std::shared_ptr<MoosePreconditioner> pc)
3661 {
3662  if (_preconditioner.get() != nullptr)
3663  mooseError("More than one active Preconditioner detected");
3664 
3665  _preconditioner = pc;
3666 }
3667 
3668 MoosePreconditioner const *
3670 {
3671  return _preconditioner.get();
3672 }
3673 
3674 void
3676 {
3677  _increment_vec = &_sys.add_vector("u_increment", true, GHOSTED);
3678 }
3679 
3680 void
3682  const std::set<MooseVariable *> & damped_vars)
3683 {
3684  for (const auto & var : damped_vars)
3685  var->computeIncrementAtQps(*_increment_vec);
3686 }
3687 
3688 void
3690  const std::set<MooseVariable *> & damped_vars)
3691 {
3692  for (const auto & var : damped_vars)
3693  var->computeIncrementAtNode(*_increment_vec);
3694 }
3695 
3696 void
3697 NonlinearSystemBase::checkKernelCoverage(const std::set<SubdomainID> & mesh_subdomains) const
3698 {
3699  // Obtain all blocks and variables covered by all kernels
3700  std::set<SubdomainID> input_subdomains;
3701  std::set<std::string> kernel_variables;
3702 
3703  bool global_kernels_exist = false;
3704  global_kernels_exist |= _scalar_kernels.hasActiveObjects();
3705  global_kernels_exist |= _nodal_kernels.hasActiveObjects();
3706 
3707  _kernels.subdomainsCovered(input_subdomains, kernel_variables);
3708  _dg_kernels.subdomainsCovered(input_subdomains, kernel_variables);
3709  _nodal_kernels.subdomainsCovered(input_subdomains, kernel_variables);
3710  _scalar_kernels.subdomainsCovered(input_subdomains, kernel_variables);
3711  _constraints.subdomainsCovered(input_subdomains, kernel_variables);
3712 
3713 #ifdef MOOSE_KOKKOS_ENABLED
3714  _kokkos_kernels.subdomainsCovered(input_subdomains, kernel_variables);
3715  _kokkos_nodal_kernels.subdomainsCovered(input_subdomains, kernel_variables);
3716 #endif
3717 
3718  if (_fe_problem.haveFV())
3719  {
3720  std::vector<FVElementalKernel *> fv_elemental_kernels;
3722  .query()
3723  .template condition<AttribSystem>("FVElementalKernel")
3724  .queryInto(fv_elemental_kernels);
3725 
3726  for (auto fv_kernel : fv_elemental_kernels)
3727  {
3728  if (fv_kernel->blockRestricted())
3729  for (auto block_id : fv_kernel->blockIDs())
3730  input_subdomains.insert(block_id);
3731  else
3732  global_kernels_exist = true;
3733  kernel_variables.insert(fv_kernel->variable().name());
3734 
3735  // Check for lagrange multiplier
3736  if (dynamic_cast<FVScalarLagrangeMultiplierConstraint *>(fv_kernel))
3737  kernel_variables.insert(dynamic_cast<FVScalarLagrangeMultiplierConstraint *>(fv_kernel)
3738  ->lambdaVariable()
3739  .name());
3740  }
3741 
3742  std::vector<FVFluxKernel *> fv_flux_kernels;
3744  .query()
3745  .template condition<AttribSystem>("FVFluxKernel")
3746  .queryInto(fv_flux_kernels);
3747 
3748  for (auto fv_kernel : fv_flux_kernels)
3749  {
3750  if (fv_kernel->blockRestricted())
3751  for (auto block_id : fv_kernel->blockIDs())
3752  input_subdomains.insert(block_id);
3753  else
3754  global_kernels_exist = true;
3755  kernel_variables.insert(fv_kernel->variable().name());
3756  }
3757 
3758  std::vector<FVInterfaceKernel *> fv_interface_kernels;
3760  .query()
3761  .template condition<AttribSystem>("FVInterfaceKernel")
3762  .queryInto(fv_interface_kernels);
3763 
3764  for (auto fvik : fv_interface_kernels)
3765  if (auto scalar_fvik = dynamic_cast<FVScalarLagrangeMultiplierInterface *>(fvik))
3766  kernel_variables.insert(scalar_fvik->lambdaVariable().name());
3767 
3768  std::vector<FVFluxBC *> fv_flux_bcs;
3770  .query()
3771  .template condition<AttribSystem>("FVFluxBC")
3772  .queryInto(fv_flux_bcs);
3773 
3774  for (auto fvbc : fv_flux_bcs)
3775  if (auto scalar_fvbc = dynamic_cast<FVBoundaryScalarLagrangeMultiplierConstraint *>(fvbc))
3776  kernel_variables.insert(scalar_fvbc->lambdaVariable().name());
3777  }
3778 
3779  for (const auto & ibc : _integrated_bcs.getActiveObjects())
3780  {
3781  const auto additional_variables_covered = ibc->additionalROVariables();
3782  kernel_variables.insert(additional_variables_covered.begin(),
3783  additional_variables_covered.end());
3784  }
3785 
3786  // Check kernel coverage of subdomains (blocks) in your mesh
3787  if (!global_kernels_exist)
3788  {
3789  std::set<SubdomainID> difference;
3790  std::set_difference(mesh_subdomains.begin(),
3791  mesh_subdomains.end(),
3792  input_subdomains.begin(),
3793  input_subdomains.end(),
3794  std::inserter(difference, difference.end()));
3795 
3796  // there supposed to be no kernels on this lower-dimensional subdomain
3797  for (const auto & id : _mesh.interiorLowerDBlocks())
3798  difference.erase(id);
3799  for (const auto & id : _mesh.boundaryLowerDBlocks())
3800  difference.erase(id);
3801 
3802  if (!difference.empty())
3803  {
3804  std::vector<SubdomainID> difference_vec =
3805  std::vector<SubdomainID>(difference.begin(), difference.end());
3806  std::vector<SubdomainName> difference_names = _mesh.getSubdomainNames(difference_vec);
3807  std::stringstream missing_block_names;
3808  std::copy(difference_names.begin(),
3809  difference_names.end(),
3810  std::ostream_iterator<std::string>(missing_block_names, " "));
3811  std::stringstream missing_block_ids;
3812  std::copy(difference.begin(),
3813  difference.end(),
3814  std::ostream_iterator<unsigned int>(missing_block_ids, " "));
3815 
3816  mooseError("Each subdomain must contain at least one Kernel.\nThe following block(s) lack an "
3817  "active kernel: " +
3818  missing_block_names.str(),
3819  " (ids: ",
3820  missing_block_ids.str(),
3821  ")");
3822  }
3823  }
3824 
3825  // Check kernel use of variables
3826  std::set<VariableName> variables(getVariableNames().begin(), getVariableNames().end());
3827 
3828  std::set<VariableName> difference;
3829  std::set_difference(variables.begin(),
3830  variables.end(),
3831  kernel_variables.begin(),
3832  kernel_variables.end(),
3833  std::inserter(difference, difference.end()));
3834 
3835  // skip checks for varaibles defined on lower-dimensional subdomain
3836  std::set<VariableName> vars(difference);
3837  for (auto & var_name : vars)
3838  {
3839  auto blks = getSubdomainsForVar(var_name);
3840  for (const auto & id : blks)
3841  if (_mesh.interiorLowerDBlocks().count(id) > 0 || _mesh.boundaryLowerDBlocks().count(id) > 0)
3842  difference.erase(var_name);
3843  }
3844 
3845  if (!difference.empty())
3846  {
3847  std::stringstream missing_kernel_vars;
3848  std::copy(difference.begin(),
3849  difference.end(),
3850  std::ostream_iterator<std::string>(missing_kernel_vars, " "));
3851  mooseError("Each variable must be referenced by at least one active Kernel.\nThe following "
3852  "variable(s) lack an active kernel: " +
3853  missing_kernel_vars.str());
3854  }
3855 }
3856 
3857 bool
3859 {
3860  auto & time_kernels = _kernels.getVectorTagObjectWarehouse(timeVectorTag(), 0);
3861 
3862  return time_kernels.hasActiveObjects();
3863 }
3864 
3865 std::vector<std::string>
3867 {
3868  std::vector<std::string> variable_names;
3869  const auto & time_kernels = _kernels.getVectorTagObjectWarehouse(timeVectorTag(), 0);
3870  if (time_kernels.hasActiveObjects())
3871  for (const auto & kernel : time_kernels.getObjects())
3872  variable_names.push_back(kernel->variable().name());
3873 
3874  return variable_names;
3875 }
3876 
3877 bool
3879 {
3880  // IntegratedBCs are for now the only objects we consider to be consuming
3881  // matprops on boundaries.
3882  if (_integrated_bcs.hasActiveBoundaryObjects(bnd_id, tid))
3883  for (const auto & bc : _integrated_bcs.getActiveBoundaryObjects(bnd_id, tid))
3884  if (std::static_pointer_cast<MaterialPropertyInterface>(bc)->getMaterialPropertyCalled())
3885  return true;
3886 
3887  // Thin layer heat transfer in the heat_transfer module is being used on a boundary even though
3888  // it's an interface kernel. That boundary is external, on both sides of a gap in a mesh
3890  for (const auto & ik : _interface_kernels.getActiveBoundaryObjects(bnd_id, tid))
3891  if (std::static_pointer_cast<MaterialPropertyInterface>(ik)->getMaterialPropertyCalled())
3892  return true;
3893 
3894  // Because MortarConstraints do not inherit from BoundaryRestrictable, they are not sorted
3895  // by boundary in the MooseObjectWarehouse. So for now, we return true for all boundaries
3896  // Note: constraints are not threaded at this time
3897  if (_constraints.hasActiveObjects(/*tid*/ 0))
3898  for (const auto & ct : _constraints.getActiveObjects(/*tid*/ 0))
3899  if (auto mpi = std::dynamic_pointer_cast<MaterialPropertyInterface>(ct);
3900  mpi && mpi->getMaterialPropertyCalled())
3901  return true;
3902  return false;
3903 }
3904 
3905 bool
3907 {
3908  // InterfaceKernels are for now the only objects we consider to be consuming matprops on internal
3909  // boundaries.
3911  for (const auto & ik : _interface_kernels.getActiveBoundaryObjects(bnd_id, tid))
3912  if (std::static_pointer_cast<MaterialPropertyInterface>(ik)->getMaterialPropertyCalled())
3913  return true;
3914  return false;
3915 }
3916 
3917 bool
3919 {
3920  // DGKernels are for now the only objects we consider to be consuming matprops on
3921  // internal sides.
3922  if (_dg_kernels.hasActiveBlockObjects(subdomain_id, tid))
3923  for (const auto & dg : _dg_kernels.getActiveBlockObjects(subdomain_id, tid))
3924  if (std::static_pointer_cast<MaterialPropertyInterface>(dg)->getMaterialPropertyCalled())
3925  return true;
3926  // NOTE:
3927  // HDG kernels do not require face material properties on internal sides at this time.
3928  // The idea is to have element locality of HDG for hybridization
3929  return false;
3930 }
3931 
3932 bool
3934 {
3935  return _doing_dg;
3936 }
3937 
3938 void
3940 {
3943 }
3944 
3945 void
3947  const std::set<TagID> & vector_tags,
3948  const std::set<TagID> & matrix_tags)
3949 {
3950  parallel_object_only();
3951 
3952  try
3953  {
3954  for (auto & map_pr : _undisplaced_mortar_functors)
3955  map_pr.second(compute_type, vector_tags, matrix_tags);
3956 
3957  for (auto & map_pr : _displaced_mortar_functors)
3958  map_pr.second(compute_type, vector_tags, matrix_tags);
3959  }
3960  catch (MetaPhysicL::LogicError &)
3961  {
3962  mooseError(
3963  "We caught a MetaPhysicL error in NonlinearSystemBase::mortarConstraints. This is very "
3964  "likely due to AD not having a sufficiently large derivative container size. Please run "
3965  "MOOSE configure with the '--with-derivative-size=<n>' option");
3966  }
3967 }
3968 
3969 void
3971 {
3972  if (_auto_scaling_initd)
3973  return;
3974 
3975  // Want the libMesh count of variables, not MOOSE, e.g. I don't care about array variable counts
3976  const auto n_vars = system().n_vars();
3977 
3978  if (_scaling_group_variables.empty())
3979  {
3980  _var_to_group_var.reserve(n_vars);
3982 
3983  for (const auto var_number : make_range(n_vars))
3984  _var_to_group_var.emplace(var_number, var_number);
3985  }
3986  else
3987  {
3988  std::set<unsigned int> var_numbers, var_numbers_covered, var_numbers_not_covered;
3989  for (const auto var_number : make_range(n_vars))
3990  var_numbers.insert(var_number);
3991 
3993 
3994  for (const auto group_index : index_range(_scaling_group_variables))
3995  for (const auto & var_name : _scaling_group_variables[group_index])
3996  {
3997  if (!hasVariable(var_name) && !hasScalarVariable(var_name))
3998  mooseError("'",
3999  var_name,
4000  "', provided to the 'scaling_group_variables' parameter, does not exist in "
4001  "the nonlinear system.");
4002 
4003  const MooseVariableBase & var =
4004  hasVariable(var_name)
4005  ? static_cast<MooseVariableBase &>(getVariable(0, var_name))
4006  : static_cast<MooseVariableBase &>(getScalarVariable(0, var_name));
4007  auto map_pair = _var_to_group_var.emplace(var.number(), group_index);
4008  if (!map_pair.second)
4009  mooseError("Variable ", var_name, " is contained in multiple scaling grouplings");
4010  var_numbers_covered.insert(var.number());
4011  }
4012 
4013  std::set_difference(var_numbers.begin(),
4014  var_numbers.end(),
4015  var_numbers_covered.begin(),
4016  var_numbers_covered.end(),
4017  std::inserter(var_numbers_not_covered, var_numbers_not_covered.begin()));
4018 
4019  _num_scaling_groups = _scaling_group_variables.size() + var_numbers_not_covered.size();
4020 
4021  auto index = static_cast<unsigned int>(_scaling_group_variables.size());
4022  for (auto var_number : var_numbers_not_covered)
4023  _var_to_group_var.emplace(var_number, index++);
4024  }
4025 
4026  _variable_autoscaled.resize(n_vars, true);
4027  const auto & number_to_var_map = _vars[0].numberToVariableMap();
4028 
4030  for (const auto i : index_range(_variable_autoscaled))
4033  libmesh_map_find(number_to_var_map, i)->name()) !=
4035  _variable_autoscaled[i] = false;
4036 
4037  _auto_scaling_initd = true;
4038 }
4039 
4040 bool
4042 {
4044  return true;
4045 
4046  _console << "\nPerforming automatic scaling calculation\n" << std::endl;
4047 
4048  TIME_SECTION("computeScaling", 3, "Computing Automatic Scaling");
4049 
4050  // It's funny but we need to assemble our vector of scaling factors here otherwise we will be
4051  // applying scaling factors of 0 during Assembly of our scaling Jacobian
4053 
4054  // container for repeated access of element global dof indices
4055  std::vector<dof_id_type> dof_indices;
4056 
4057  if (!_auto_scaling_initd)
4058  setupScalingData();
4059 
4060  std::vector<Real> inverse_scaling_factors(_num_scaling_groups, 0);
4061  std::vector<Real> resid_inverse_scaling_factors(_num_scaling_groups, 0);
4062  std::vector<Real> jac_inverse_scaling_factors(_num_scaling_groups, 0);
4063  auto & dof_map = dofMap();
4064 
4065  // what types of scaling do we want?
4066  bool jac_scaling = _resid_vs_jac_scaling_param < 1. - TOLERANCE;
4067  bool resid_scaling = _resid_vs_jac_scaling_param > TOLERANCE;
4068 
4069  const NumericVector<Number> & scaling_residual = RHS();
4070 
4071  if (jac_scaling)
4072  {
4073  // if (!_auto_scaling_initd)
4074  // We need to reinit this when the number of dofs changes
4075  // but there is no good way to track that
4076  // In theory, it is the job of libmesh system to track this,
4077  // but this special matrix is not owned by libMesh system
4078  // Let us reinit eveytime since it is not expensive
4079  {
4080  auto init_vector = NumericVector<Number>::build(this->comm());
4081  init_vector->init(system().n_dofs(), system().n_local_dofs(), /*fast=*/false, PARALLEL);
4082 
4083  _scaling_matrix->clear();
4084  _scaling_matrix->init(*init_vector);
4085  }
4086 
4088  // Dispatch to derived classes to ensure that we use the correct matrix tag
4091  }
4092 
4093  if (resid_scaling)
4094  {
4097  // Dispatch to derived classes to ensure that we use the correct vector tag
4101  }
4102 
4103  // Did something bad happen during residual/Jacobian scaling computation?
4105  return false;
4106 
4107  auto examine_dof_indices = [this,
4108  jac_scaling,
4109  resid_scaling,
4110  &dof_map,
4111  &jac_inverse_scaling_factors,
4112  &resid_inverse_scaling_factors,
4113  &scaling_residual](const auto & dof_indices, const auto var_number)
4114  {
4115  for (auto dof_index : dof_indices)
4116  if (dof_map.local_index(dof_index))
4117  {
4118  if (jac_scaling)
4119  {
4120  // For now we will use the diagonal for determining scaling
4121  auto mat_value = (*_scaling_matrix)(dof_index, dof_index);
4122  auto & factor = jac_inverse_scaling_factors[_var_to_group_var[var_number]];
4123  factor = std::max(factor, std::abs(mat_value));
4124  }
4125  if (resid_scaling)
4126  {
4127  auto vec_value = scaling_residual(dof_index);
4128  auto & factor = resid_inverse_scaling_factors[_var_to_group_var[var_number]];
4129  factor = std::max(factor, std::abs(vec_value));
4130  }
4131  }
4132  };
4133 
4134  // Compute our scaling factors for the spatial field variables
4135  for (const auto & elem : _fe_problem.getCurrentAlgebraicElementRange())
4136  for (const auto i : make_range(system().n_vars()))
4138  {
4139  dof_map.dof_indices(elem, dof_indices, i);
4140  examine_dof_indices(dof_indices, i);
4141  }
4142 
4143  for (const auto i : make_range(system().n_vars()))
4144  if (_variable_autoscaled[i] && system().variable_type(i).family == SCALAR)
4145  {
4146  dof_map.SCALAR_dof_indices(dof_indices, i);
4147  examine_dof_indices(dof_indices, i);
4148  }
4149 
4150  if (resid_scaling)
4151  _communicator.max(resid_inverse_scaling_factors);
4152  if (jac_scaling)
4153  _communicator.max(jac_inverse_scaling_factors);
4154 
4155  if (jac_scaling && resid_scaling)
4156  for (MooseIndex(inverse_scaling_factors) i = 0; i < inverse_scaling_factors.size(); ++i)
4157  {
4158  // Be careful not to take log(0)
4159  if (!resid_inverse_scaling_factors[i])
4160  {
4161  if (!jac_inverse_scaling_factors[i])
4162  inverse_scaling_factors[i] = 1;
4163  else
4164  inverse_scaling_factors[i] = jac_inverse_scaling_factors[i];
4165  }
4166  else if (!jac_inverse_scaling_factors[i])
4167  // We know the resid is not zero
4168  inverse_scaling_factors[i] = resid_inverse_scaling_factors[i];
4169  else
4170  inverse_scaling_factors[i] =
4171  std::exp(_resid_vs_jac_scaling_param * std::log(resid_inverse_scaling_factors[i]) +
4172  (1 - _resid_vs_jac_scaling_param) * std::log(jac_inverse_scaling_factors[i]));
4173  }
4174  else if (jac_scaling)
4175  inverse_scaling_factors = jac_inverse_scaling_factors;
4176  else if (resid_scaling)
4177  inverse_scaling_factors = resid_inverse_scaling_factors;
4178  else
4179  mooseError("We shouldn't be calling this routine if we're not performing any scaling");
4180 
4181  // We have to make sure that our scaling values are not zero
4182  for (auto & scaling_factor : inverse_scaling_factors)
4183  if (scaling_factor == 0)
4184  scaling_factor = 1;
4185 
4186  // Now flatten the group scaling factors to the individual variable scaling factors
4187  std::vector<Real> flattened_inverse_scaling_factors(system().n_vars());
4188  for (const auto i : index_range(flattened_inverse_scaling_factors))
4189  flattened_inverse_scaling_factors[i] = inverse_scaling_factors[_var_to_group_var[i]];
4190 
4191  // Now set the scaling factors for the variables
4192  applyScalingFactors(flattened_inverse_scaling_factors);
4194  displaced_problem->systemBaseNonlinear(number()).applyScalingFactors(
4195  flattened_inverse_scaling_factors);
4196 
4197  _computed_scaling = true;
4198  return true;
4199 }
4200 
4201 void
4203 {
4204  if (!hasVector("scaling_factors"))
4205  // No variables have indicated they need scaling
4206  return;
4207 
4208  auto & scaling_vector = getVector("scaling_factors");
4209 
4210  const auto & lm_mesh = _mesh.getMesh();
4211  const auto & dof_map = dofMap();
4212 
4213  const auto & field_variables = _vars[0].fieldVariables();
4214  const auto & scalar_variables = _vars[0].scalars();
4215 
4216  std::vector<dof_id_type> dof_indices;
4217 
4218  for (const Elem * const elem :
4219  as_range(lm_mesh.active_local_elements_begin(), lm_mesh.active_local_elements_end()))
4220  for (const auto * const field_var : field_variables)
4221  {
4222  const auto & factors = field_var->arrayScalingFactor();
4223  for (const auto i : make_range(field_var->count()))
4224  {
4225  dof_map.dof_indices(elem, dof_indices, field_var->number() + i);
4226  for (const auto dof : dof_indices)
4227  scaling_vector.set(dof, factors[i]);
4228  }
4229  }
4230 
4231  for (const auto * const scalar_var : scalar_variables)
4232  {
4233  mooseAssert(scalar_var->count() == 1,
4234  "Scalar variables should always have only one component.");
4235  dof_map.SCALAR_dof_indices(dof_indices, scalar_var->number());
4236  for (const auto dof : dof_indices)
4237  scaling_vector.set(dof, scalar_var->scalingFactor());
4238  }
4239 
4240  // Parallel assemble
4241  scaling_vector.close();
4242 
4243  if (auto * displaced_problem = _fe_problem.getDisplacedProblem().get())
4244  // copy into the corresponding displaced system vector because they should be the exact same
4245  displaced_problem->systemBaseNonlinear(number()).getVector("scaling_factors") = scaling_vector;
4246 }
4247 
4248 bool
4250 {
4251  // Clear the iteration counters
4252  _current_l_its.clear();
4253  _current_nl_its = 0;
4254 
4255  // Initialize the solution vector using a predictor and known values from nodal bcs
4257 
4258  // Now that the initial solution has ben set, potentially perform a residual/Jacobian evaluation
4259  // to determine variable scaling factors
4260  if (_automatic_scaling)
4261  {
4262  const bool scaling_succeeded = computeScaling();
4263  if (!scaling_succeeded)
4264  return false;
4265  }
4266 
4267  // We do not know a priori what variable a global degree of freedom corresponds to, so we need a
4268  // map from global dof to scaling factor. We just use a ghosted NumericVector for that mapping
4270 
4271  return true;
4272 }
4273 
4274 void
4276 {
4277  if (matrixFromColoring())
4278  LibmeshPetscCall(MatFDColoringDestroy(&_fdcoloring));
4279 }
4280 
4283 {
4284  if (!_fsp)
4285  mooseError("No field split preconditioner is present for this system");
4286 
4287  return *_fsp;
4288 }
std::string name(const ElemQuality q)
std::vector< std::shared_ptr< TimeIntegrator > > _time_integrators
Time integrator.
Definition: SystemBase.h:1049
virtual void setSolutionUDotDotOld(const NumericVector< Number > &u_dotdot_old)
virtual void reinitNeighborPhys(const Elem *neighbor, unsigned int neighbor_side, const std::vector< Point > &physical_points, const THREAD_ID tid)=0
virtual void residualSetup(THREAD_ID tid=0) const
NumericVector< Number > & getResidualTimeVector()
Return a numeric vector that is associated with the time tag.
void setActiveMaterialProperties(const std::unordered_set< unsigned int > &mat_prop_ids, const THREAD_ID tid)
Record and set the material properties required by the current computing thread.
MooseObjectTagWarehouse< NodalKernelBase > _nodal_kernels
NodalKernels for each thread.
NumericVector< Number > * _Re_time
residual vector for time contributions
void computeJacobianBlocks(std::vector< JacobianBlock *> &blocks)
Computes several Jacobian blocks simultaneously, summing their contributions into smaller preconditio...
virtual void insert(const T *v, const std::vector< numeric_index_type > &dof_indices)
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Definition: EigenADReal.h:50
TagID _Re_time_tag
Tag for time contribution residual.
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
std::map< std::pair< BoundaryID, BoundaryID >, PenetrationLocator * > _penetration_locators
dof_id_type end_dof(const processor_id_type proc) const
bool empty() const
virtual void addKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a kernel.
virtual void setSolutionUDotDot(const NumericVector< Number > &udotdot)
Set transient term used by residual and Jacobian evaluation.
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Base kernel for hybridized finite element formulations.
Definition: HDGKernel.h:17
MooseObjectTagWarehouse< ResidualObject > _kokkos_nodal_kernels
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
void reinitIncrementAtNodeForDampers(THREAD_ID tid, const std::set< MooseVariable *> &damped_vars)
Compute the incremental change in variables at nodes for dampers.
void overwriteNodeFace(NumericVector< Number > &soln)
Called from explicit time stepping to overwrite boundary positions (explicit dynamics).
Base class for deriving general dampers.
Definition: GeneralDamper.h:21
bool _use_pre_smo_residual
Whether to use the pre-SMO initial residual in the relative convergence check.
MoosePreconditioner const * getPreconditioner() const
virtual const char * what() const
Get out the error message.
void findImplicitGeometricCouplingEntries(GeometricSearchData &geom_search_data, std::unordered_map< dof_id_type, std::vector< dof_id_type >> &graph)
Finds the implicit sparsity graph between geometrically related dofs.
void setupDampers()
Setup damping stuff (called before we actually start)
Real _initial_residual
The initial (i.e., 0th nonlinear iteration) residual, see setPreSMOResidual for a detailed explanatio...
unsigned int n_threads()
std::vector< bool > _variable_autoscaled
Container to hold flag if variable is to participate in autoscaling.
void zeroVectorForResidual(const std::string &vector_name)
virtual void cacheResidualNeighbor(const THREAD_ID tid) override
bool identifyVariableGroupsInNL() const
Whether to identify variable groups in nonlinear systems.
void zeroTaggedVectors(const std::set< TagID > &tags)
Zero all vectors for given tags.
Definition: SystemBase.C:694
const std::set< SubdomainID > & interiorLowerDBlocks() const
Definition: MooseMesh.h:1552
Base class for split-based preconditioners.
Definition: Split.h:25
bool hasActiveBlockObjects(THREAD_ID tid=0) const
std::shared_ptr< DisplacedProblem > displaced_problem
bool hasVector(const std::string &tag_name) const
Check if the named vector exists in the system.
Definition: SystemBase.C:925
virtual void checkExceptionAndStopSolve(bool print_message=true)
Check to see if an exception has occurred on any processor and, if possible, force the solve to fail...
unsigned int n_comp(const unsigned int s, const unsigned int var) const
void applyScalingFactors(const std::vector< Real > &inverse_scaling_factors)
Applies scaling factors to the system&#39;s variables.
Definition: SystemBase.C:1497
bool _debugging_residuals
true if debugging residuals
SCALAR
BoundaryID _secondary_boundary
NumericVector< Number > * _Re_non_time
residual vector for non-time contributions
const std::map< SubdomainID, std::vector< std::shared_ptr< T > > > & getActiveBlockObjects(THREAD_ID tid=0) const
MooseObjectTagWarehouse< ResidualObject > _kokkos_kernels
unsigned int TagID
Definition: MooseTypes.h:238
Real computeDamping(const NumericVector< Number > &solution, const NumericVector< Number > &update)
Compute damping.
virtual void reinitNode(const Node *node, const THREAD_ID tid) override
virtual void setPreviousNewtonSolution(const NumericVector< Number > &soln)
virtual void predictorCleanup(NumericVector< libMesh::Number > &ghosted_solution)
Perform cleanup tasks after application of predictor to solution vector.
bool _assemble_constraints_separately
Whether or not to assemble the residual and Jacobian after the application of each constraint...
virtual Elem * elemPtr(const dof_id_type i)
Definition: MooseMesh.C:3213
auto exp(const T &)
TagID systemMatrixTag() const override
Return the Matrix Tag ID for System.
MPI_Info info
NumericVector< Number > & solution()
Definition: SystemBase.h:197
bool hasObjects(THREAD_ID tid=0) const
Convenience functions for determining if objects exist.
MooseObjectTagWarehouse< DGKernelBase > _dg_kernels
virtual bool haveFV() const override
returns true if this problem includes/needs finite volume functionality.
char ** blocks
face_info_iterator ownedFaceInfoBegin()
Iterators to owned faceInfo objects.
Definition: MooseMesh.C:1498
PARALLEL
void reinitIncrementAtQpsForDampers(THREAD_ID tid, const std::set< MooseVariable *> &damped_vars)
Compute the incremental change in variables at QPs for dampers.
void computeResidualAndJacobianInternal(const std::set< TagID > &vector_tags, const std::set< TagID > &matrix_tags)
Compute residual and Jacobian from contributions not related to constraints, such as nodal boundary c...
bool useHashTableMatrixAssembly() const
void addImplicitGeometricCouplingEntriesToJacobian(bool add=true)
If called with true this will add entries into the jacobian to link together degrees of freedom that ...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
bool areCoupled(const unsigned int ivar, const unsigned int jvar, const unsigned int nl_sys_num) const
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
void accumulateIterationIntoTimeStepOccurences()
Pass the number of solution invalid occurrences from current iteration to cumulative counters...
unsigned int number() const
Get variable number coming from libMesh.
virtual void initialSetup() override
Setup Functions.
Data structure used to hold penetration information.
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
const std::vector< std::shared_ptr< NodalConstraint > > & getActiveNodalConstraints() const
Access methods for active objects.
NumericVector< Number > * _u_dot_old
old solution vector for u^dot
Definition: SystemBase.h:1011
bool _has_nodalbc_diag_save_in
If there is a nodal BC having diag_save_in.
virtual void reinitScalars(const THREAD_ID tid, bool reinit_for_derivative_reordering=false) override
fills the VariableValue arrays for scalar variables from the solution vector
Base class for automatic differentiation Dirichlet BCs.
void add(std::shared_ptr< MooseObject > obj)
add adds a new object to the warehouse and stores attributes/metadata about it for running queries/fi...
Definition: TheWarehouse.C:116
virtual void getDiracElements(std::set< const Elem *> &elems) override
Fills "elems" with the elements that should be looped over for Dirac Kernels.
void setupDM()
Setup the PETSc DM object (when appropriate)
void setCurrentlyComputingResidual(bool currently_computing_residual) final
Set whether or not the problem is in the process of computing the residual.
void checkKernelCoverage(const std::set< SubdomainID > &mesh_subdomains) const
void addDGKernel(std::string dg_kernel_name, const std::string &name, InputParameters &parameters)
Adds a DG kernel.
void computeJacobian(libMesh::SparseMatrix< Number > &jacobian, const std::set< TagID > &tags)
Associate jacobian to systemMatrixTag, and then form a matrix for all the tags.
const InputParameters & parameters() const
Get the parameters of the object.
Definition: MooseBase.h:131
char ** vars
virtual void reinitNeighborPhys(const Elem *neighbor, unsigned int neighbor_side, const std::vector< Point > &physical_points, const THREAD_ID tid) override
void computeKokkosResidualAndJacobian(const std::set< TagID > &vector_tags, const std::set< TagID > &matrix_tags)
virtual TagID addVectorTag(const TagName &tag_name, const Moose::VectorTagType type=Moose::VECTOR_TAG_RESIDUAL)
Create a Tag.
Definition: SubProblem.C:93
void getNodeDofs(dof_id_type node_id, std::vector< dof_id_type > &dofs)
Base class for all Constraint types.
Definition: Constraint.h:19
std::set< TagID > _nl_vector_tags
Vector tags to temporarily store all tags associated with the current system.
std::vector< std::string > _ignore_variables_for_autoscaling
A container for variables that do not partipate in autoscaling.
void residualSetup() override
Base boundary condition of a Dirichlet type.
virtual void associateVectorToTag(NumericVector< Number > &vec, TagID tag)
Associate a vector for a given tag.
Definition: SystemBase.C:982
virtual void reinitNodes(const std::vector< dof_id_type > &nodes, const THREAD_ID tid) override
MooseObjectTagWarehouse< NodalBCBase > _nodal_bcs
virtual void addJacobianOffDiagScalar(unsigned int ivar, const THREAD_ID tid=0)
virtual void setException(const std::string &message)
Set an exception, which is stored at this point by toggling a member variable in this class...
const std::vector< std::shared_ptr< NodeFaceConstraint > > & getActiveNodeFaceConstraints(BoundaryID boundary_id, bool displaced) const
virtual void customSetup(const ExecFlagType &exec_type, THREAD_ID tid=0) const
Factory & _factory
Definition: SystemBase.h:989
MooseObjectWarehouse< T > & getVectorTagsObjectWarehouse(const std::set< TagID > &tags, THREAD_ID tid)
Retrieve a moose object warehouse in which every moose object at least has one of the given vector ta...
virtual const Node * queryNodePtr(const dof_id_type i) const
Definition: MooseMesh.C:865
const ElementPairInfo & getElemPairInfo(std::pair< const Elem *, const Elem *> elem_pair) const
MooseObjectWarehouseBase< Split > _splits
Decomposition splits.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
NumericVector< Number > * _u_dotdot
solution vector for u^dotdot
Definition: SystemBase.h:1008
bool hasActiveMortarConstraints(const std::pair< BoundaryID, BoundaryID > &mortar_interface_key, bool displaced) const
const Parallel::Communicator & comm() const
NumericVector< Number > & add_vector(std::string_view vec_name, const bool projections=true, const ParallelType type=PARALLEL)
Solving a linear problem.
Definition: MooseTypes.h:897
bool _has_nodalbc_save_in
If there is a nodal BC having save_in.
bool hasActiveNodalConstraints() const
Deterimine if active objects exist.
virtual void prepareAssemblyNeighbor(const THREAD_ID tid)
Begin a fresh neighbor accumulation phase by sizing and zeroing the neighbor blocks.
virtual bool hasMatrix(TagID tag) const
Check if the tagged matrix exists in the system.
Definition: SystemBase.h:361
MooseObjectWarehouse< NodalDamper > _nodal_dampers
Nodal Dampers for each thread.
void computeNodalBCsResidualAndJacobian(const std::set< TagID > &vector_tags, const std::set< TagID > &matrix_tags)
Compute the residual and Jacobian together for nodal boundary conditions.
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver()=0
dof_id_type n_dofs(const unsigned int vn) const
Real preSMOResidual() const
The pre-SMO residual.
std::unique_ptr< libMesh::DiagonalMatrix< Number > > _scaling_matrix
A diagonal matrix used for computing scaling.
virtual void setSolutionUDotOld(const NumericVector< Number > &u_dot_old)
virtual void associateMatrixToTag(libMesh::SparseMatrix< Number > &matrix, TagID tag)
Associate a matrix to a tag.
Definition: SystemBase.C:1077
bool hasDiagSaveIn() const
Weather or not the nonlinear system has diagonal Jacobian save-ins.
This class provides an interface for common operations on field variables of both FE and FV types wit...
const Parallel::Communicator & _communicator
void updateActive(THREAD_ID tid=0) override
Update the various active lists.
Real initialResidual() const
The initial residual.
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
bool needInterfaceMaterialOnSide(BoundaryID bnd_id, THREAD_ID tid) const
Indicated whether this system needs material properties on interfaces.
const libMesh::ConstElemRange & getCurrentAlgebraicElementRange()
These are the element and nodes that contribute to the jacobian and residual for this local processor...
MooseObjectWarehouse< ResidualObject > _kokkos_preset_nodal_bcs
std::size_t _num_scaling_groups
The number of scaling groups.
const libMesh::ConstNodeRange & getCurrentAlgebraicNodeRange()
void computingScalingJacobian(bool computing_scaling_jacobian)
Setter for whether we&#39;re computing the scaling jacobian.
dof_id_type n_local_dofs(const unsigned int vn) const
virtual void updateActive(THREAD_ID tid=0) override
Update the active status of Kernels.
bool has_dofs(const unsigned int s=libMesh::invalid_uint) const
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
Data structure of nodes and their associated penetration information.
bool hasActiveNodeElemConstraints(SubdomainID secondary_id, SubdomainID primary_id, bool displaced) const
Real _pre_smo_residual
The pre-SMO residual, see setPreSMOResidual for a detailed explanation.
bool hasDampers()
Whether or not this system has dampers.
const std::vector< std::shared_ptr< NodeElemConstraintBase > > & getActiveNodeElemConstraints(SubdomainID secondary_id, SubdomainID primary_id, bool displaced) const
bool _compute_scaling_once
Whether the scaling factors should only be computed once at the beginning of the simulation through a...
void computeResidualTags(const std::set< TagID > &tags)
Form multiple tag-associated residual vectors for all the given tags.
virtual void cacheJacobianNeighbor(const THREAD_ID tid) override
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
bool _has_save_in
If there is any Kernel or IntegratedBC having save_in.
virtual const Node & nodeRef(const dof_id_type i) const
Definition: MooseMesh.C:839
TagID _Ke_system_tag
Tag for system contribution Jacobian.
virtual void setResidual(NumericVector< libMesh::Number > &residual, const THREAD_ID tid) override
std::vector< SetupInterface * > getFVSetupObjects(THREAD_ID tid)
Retrieve every finite volume object belonging to this system on thread tid, as SetupInterfaces, so that the setup methods can be dispatched to all finite volume families with a single loop.
dof_id_type n_dofs() const
virtual void disassociateMatrixFromTag(libMesh::SparseMatrix< Number > &matrix, TagID tag)
Disassociate a matrix from a tag.
Definition: SystemBase.C:1089
Scope guard for starting and stopping Floating Point Exception Trapping.
virtual void zero()=0
auto max(const L &left, const R &right)
Serves as a base class for DGKernel and ADDGKernel.
Definition: DGKernelBase.h:32
const Variable & variable(const unsigned int c) const override
void constraintResiduals(NumericVector< Number > &residual, bool displaced)
Add residual contributions from Constraints.
Base class for MOOSE preconditioners.
NumericVector< Number > & addVector(const std::string &vector_name, const bool project, const libMesh::ParallelType type)
Adds a solution length vector to the system.
virtual GeometricSearchData & geomSearchData() override
std::unordered_map< std::pair< BoundaryID, BoundaryID >, ComputeMortarFunctor > _undisplaced_mortar_functors
Functors for computing undisplaced mortar constraints.
Specialization for filling multiple "small" preconditioning matrices simulatenously.
virtual bool matrixFromColoring() const
Whether a system matrix is formed from coloring.
Definition: SolverSystem.h:117
void update()
Update the system (doing libMesh magic)
Definition: SystemBase.C:1244
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num) override
void addScalarKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a scalar kernel.
void addBoundaryCondition(const std::string &bc_name, const std::string &name, InputParameters &parameters)
Adds a boundary condition.
bool hasActiveNodeFaceConstraints(BoundaryID boundary_id, bool displaced) const
void computeResidual(NumericVector< Number > &residual, TagID tag_id)
Form a residual vector for a given tag.
virtual void addCachedResidualDirectly(NumericVector< libMesh::Number > &residual, const THREAD_ID tid)
Allows for all the residual contributions that are currently cached to be added directly into the vec...
virtual unsigned int nVariables() const
Get the number of variables in this system.
Definition: SystemBase.C:892
EXTERN_C_BEGIN PetscErrorCode DMCreate_Moose(DM)
bool hasActiveBoundaryObjects(THREAD_ID tid=0) const
bool _need_residual_ghosted
Whether or not a ghosted copy of the residual needs to be made.
virtual void activateAllMatrixTags()
Make all existing matrices active.
Definition: SystemBase.C:1132
virtual const std::string & name() const
Definition: SystemBase.C:1342
virtual void jacobianSetup()
Definition: SystemBase.C:1595
virtual bool containsTimeKernel() override
If the system has a kernel that corresponds to a time derivative.
void onTimestepBegin()
Called at the beginning of the time step.
const ConstBndNodeRange & getCurrentAlgebraicBndNodeRange()
std::vector< dof_id_type, Threads::scalable_allocator< dof_id_type > > Row
MooseObjectTagWarehouse< DiracKernelBase > _dirac_kernels
Dirac Kernel storage for each thread.
void closeTaggedMatrices(const std::set< TagID > &tags)
Close all matrices associated the tags.
Definition: SystemBase.C:1061
TagID _Re_non_time_tag
Tag for non-time contribution residual.
std::set< TagID > _nl_matrix_tags
Matrix tags to temporarily store all tags associated with the current system.
void set_basic_system_only()
std::map< std::pair< BoundaryID, BoundaryID >, NearestNodeLocator * > _nearest_node_locators
void setPredictor(std::shared_ptr< Predictor > predictor)
Real _resid_vs_jac_scaling_param
The param that indicates the weighting of the residual vs the Jacobian in determining variable scalin...
bool _auto_scaling_initd
Whether we&#39;ve initialized the automatic scaling data structures.
virtual void computeScalingResidual()=0
Compute a "residual" for automatic scaling purposes.
bool _doing_dg
true if DG is active (optimization reasons)
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
Definition: SystemBase.C:1164
void syncIteration()
Sync iteration counts to main processor Sum across all processors.
virtual void deactivateAllMatrixTags()
Make matrices inactive.
Definition: SystemBase.C:1120
void computeNodalBCsResidual(NumericVector< Number > &residual)
Enforces nodal boundary conditions.
unsigned int number() const
void computeResidualAndJacobianTags(const std::set< TagID > &vector_tags, const std::set< TagID > &matrix_tags)
Form possibly multiple tag-associated vectors and matrices.
SERIAL
bool needBoundaryMaterialOnSide(BoundaryID bnd_id, THREAD_ID tid) const
Indicated whether this system needs material properties on boundaries.
MooseObjectWarehouse< DirichletBCBase > _preset_nodal_bcs
std::unordered_map< unsigned int, unsigned int > _var_to_group_var
A map from variable index to group variable index and it&#39;s associated (inverse) scaling factor...
const std::vector< std::shared_ptr< T > > & getActiveObjects(THREAD_ID tid=0) const
Retrieve complete vector to the active all/block/boundary restricted objects for a given thread...
std::vector< unsigned int > _current_l_its
virtual void zero()=0
virtual std::unique_ptr< Base > create()=0
void setCurrentNonlinearSystem(const unsigned int nl_sys_num)
std::shared_ptr< T > getActiveObject(const std::string &name, THREAD_ID tid=0) const
This is the common base class for the three main kernel types implemented in MOOSE, Kernel, VectorKernel and ArrayKernel.
Definition: KernelBase.h:23
dof_id_type id() const
std::vector< dof_id_type > _secondary_nodes
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3548
void min(const T &r, T &o, Request &req) const
void computeDiracContributions(const std::set< TagID > &tags, bool is_jacobian)
void updateActive(THREAD_ID tid)
Update active objects of Warehouses owned by NonlinearSystemBase.
TheWarehouse & theWarehouse() const
unsigned int n_vars
void reinitMaterialsNeighbor(SubdomainID blk_id, const THREAD_ID tid, bool swap_stateful=true, const std::deque< MaterialBase *> *reinit_mats=nullptr)
reinit materials on the neighboring element face
const ElementPairList & getElemPairs() const
FieldSplitPreconditionerBase & getFieldSplitPreconditioner()
std::unordered_map< std::pair< BoundaryID, BoundaryID >, ComputeMortarFunctor > _displaced_mortar_functors
Functors for computing displaced mortar constraints.
bool enforceNodalConstraintsJacobian(const SparseMatrix< Number > &jacobian)
Enforce nodal constraints in the Jacobian.
GHOSTED
boundary_id_type BoundaryID
Real referenceResidual() const
The reference residual used in relative convergence check.
void addSplit(const std::string &split_name, const std::string &name, InputParameters &parameters)
Adds a split.
bool _automatic_scaling
Whether to automatically scale the variables.
Definition: SystemBase.h:1055
void computeJacobianTags(const std::set< TagID > &tags)
Computes multiple (tag associated) Jacobian matricese.
SolutionInvalidity & solutionInvalidity()
Get the SolutionInvalidity for this app.
Definition: MooseApp.h:185
std::shared_ptr< MoosePreconditioner > _preconditioner
Preconditioner.
virtual void timestepSetup(THREAD_ID tid=0) const
NonlinearSystemBase & currentNonlinearSystem()
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
void computingScalingResidual(bool computing_scaling_residual)
Setter for whether we&#39;re computing the scaling residual.
virtual void setupDM()=0
setup the data management data structure that manages the field split
SubProblem & subproblem()
Definition: SystemBase.h:102
std::vector< std::string > _vecs_to_zero_for_residual
vectors that will be zeroed before a residual computation
virtual TagID addMatrixTag(TagName tag_name)
Create a Tag.
Definition: SubProblem.C:312
std::shared_ptr< Split > getSplit(const std::string &name)
Retrieves a split by name.
TheWarehouse is a container for MooseObjects that allows querying/filtering over various customizeabl...
Definition: TheWarehouse.h:186
std::unique_ptr< NumericVector< Number > > solution
SubProblem & _subproblem
The subproblem for whom this class holds variable data, etc; this can either be the governing finite ...
Definition: SystemBase.h:983
void subdomainsCovered(std::set< SubdomainID > &subdomains_covered, std::set< std::string > &unique_variables, THREAD_ID tid=0) const
Populates a set of covered subdomains and the associated variable names.
void addImplicitGeometricCouplingEntries(GeometricSearchData &geom_search_data)
Adds entries to the Jacobian in the correct positions for couplings coming from dofs being coupled th...
virtual void addHDGKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a hybridized discontinuous Galerkin (HDG) kernel.
virtual void zero_rows(std::vector< numeric_index_type > &rows, T diag_value=0.0)
MooseObjectTagWarehouse< KernelBase > _kernels
MooseObjectWarehouse< T > & getMatrixTagObjectWarehouse(TagID tag_id, THREAD_ID tid)
Retrieve a moose object warehouse in which every moose object has the given matrix tag...
bool shouldEvaluatePreSMOResidual() const
We offer the option to check convergence against the pre-SMO residual.
std::vector< VectorTag > getVectorTags(const std::set< TagID > &tag_ids) const
Definition: SubProblem.C:173
Moose::SolveType _type
Definition: SolverParams.h:19
Base class for deriving nodal dampers.
Definition: NodalDamper.h:27
virtual void disassociateVectorFromTag(NumericVector< Number > &vec, TagID tag)
Disassociate a given vector from a given tag.
virtual void cacheResidual(const THREAD_ID tid) override
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:363
virtual void computeScalingJacobian()=0
Compute a "Jacobian" for automatic scaling purposes.
bool errorOnJacobianNonzeroReallocation() const
Will return True if the user wants to get an error when a nonzero is reallocated in the Jacobian by P...
This is the ElementPairLocator class.
This is the ElementPairInfo class.
std::map< BoundaryID, std::shared_ptr< ElementPairLocator > > _element_pair_locators
Moose::CouplingType coupling() const
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1158
void setupScalingData()
Setup group scaling containers.
virtual GeometricSearchData & geomSearchData()=0
const bool & usePreSMOResidual() const
Whether we are using pre-SMO residual in relative convergence checks.
MooseObjectTagWarehouse< HDGKernel > _hybridized_kernels
const std::set< SubdomainID > & boundaryLowerDBlocks() const
Definition: MooseMesh.h:1556
std::vector< SubdomainName > getSubdomainNames(const std::vector< SubdomainID > &subdomain_ids) const
Get the associated subdomainNames for the subdomain ids that are passed in.
Definition: MooseMesh.C:1756
auto log(const T &)
AuxiliarySystem & getAuxiliarySystem()
virtual void initialSetup(THREAD_ID tid=0) const
Convenience methods for calling object setup methods.
virtual void updateGeomSearch(GeometricSearchData::GeometricSearchType type=GeometricSearchData::ALL) override
Update this object&#39;s geometric search data as well as the displaced problem&#39;s if it exists...
void closeTaggedVectors(const std::set< TagID > &tags)
Close all vectors for given tags.
Definition: SystemBase.C:668
Base class for deriving any boundary condition that works at nodes.
Definition: NodalBCBase.h:26
void computeResidualInternal(const std::set< TagID > &tags)
Compute the residual for a given tag.
virtual void prepareAssembly(const THREAD_ID tid) override
bool computeScaling()
Method used to obtain scaling factors for variables.
std::vector< std::pair< MooseVariableFieldBase *, MooseVariableFieldBase * > > & couplingEntries(const THREAD_ID tid, const unsigned int nl_sys_num)
Interface for objects interacting with the PerfGraph.
virtual std::map< TagName, TagID > & getMatrixTags()
Return all matrix tags in the system, where a tag is represented by a map from name to ID...
Definition: SubProblem.h:253
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition: SystemBase.C:852
virtual void setCurrentSubdomainID(const Elem *elem, const THREAD_ID tid) override
virtual void clearDiracInfo() override
Gets called before Dirac Kernels are asked to add the points they are supposed to be evaluated in...
void destroyColoring()
Destroy the coloring object if it exists.
virtual void reinitNodesNeighbor(const std::vector< dof_id_type > &nodes, const THREAD_ID tid) override
bool identify_variable_groups() const
virtual void close()=0
virtual void jacobianSetup(THREAD_ID tid=0) const
ConstraintWarehouse _constraints
Constraints storage object.
virtual void turnOffJacobian()
Turn off the Jacobian (must be called before equation system initialization)
void computeKokkosJacobian(const std::set< TagID > &tags)
Compute Jacobian with Kokkos objects.
TagID residualVectorTag() const override
const std::map< BoundaryID, std::vector< std::shared_ptr< T > > > & getActiveBoundaryObjects(THREAD_ID tid=0) const
void computingNonlinearResid(bool computing_nonlinear_residual) final
Set whether or not the problem is in the process of computing the nonlinear residual.
virtual void customSetup(const ExecFlagType &exec_type) override
ComputeType
The type of nonlinear computation being performed.
Definition: MooseTypes.h:829
Base class for deriving element dampers.
Definition: ElementDamper.h:33
Base interface for field split preconditioner.
bool _add_implicit_geometric_coupling_entries_to_jacobian
Whether or not to add implicit geometric couplings to the Jacobian for FDP.
const_iterator end() const
MooseObjectTagWarehouse< ResidualObject > _kokkos_integrated_bcs
void computeKokkosNodalBCsResidual(const std::set< TagID > &tags)
Compute Kokkos nodal BCs.
bool have_parameter(std::string_view name) const
A wrapper around the Parameters base class method.
virtual void addNodalKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a NodalKernel.
virtual unsigned int numMatrixTags() const
The total number of tags.
Definition: SubProblem.h:248
Base class for creating new types of boundary conditions.
tbb::split split
MooseApp & _app
Definition: SystemBase.h:988
FEProblemBase & _fe_problem
the governing finite element/volume problem
Definition: SystemBase.h:986
virtual void reinitElemPhys(const Elem *elem, const std::vector< Point > &phys_points_in_elem, const THREAD_ID tid)=0
virtual MooseVariableScalar & getScalarVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a scalar variable with specified number.
Definition: SystemBase.C:146
ParallelType type() const
virtual NumericVector< Number > & RHS()=0
std::vector< VariableWarehouse > _vars
Variable warehouses (one for each thread)
Definition: SystemBase.h:996
const std::unordered_map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected...
Definition: MooseMesh.C:1234
Provides a way for users to bail out of the current solve.
unsigned int _n_residual_evaluations
Total number of residual evaluations that have been performed.
virtual void update()
void addDiracKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a Dirac kernel.
virtual void close()=0
void computeJacobianInternal(const std::set< TagID > &tags)
Form multiple matrices for all the tags.
bool _has_diag_save_in
If there is any Kernel or IntegratedBC having diag_save_in.
Base class for creating new types of nodal kernels.
const FEType & variable_type(const unsigned int i) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
std::unique_ptr< NumericVector< Number > > _residual_copy
Copy of the residual vector, or nullptr if a copy is not needed.
virtual void subdomainSetup()
Definition: SystemBase.C:1581
bool hasSaveIn() const
Weather or not the nonlinear system has save-ins.
Generic class for solving transient nonlinear problems.
Definition: SubProblem.h:78
TagID timeVectorTag() const override
Ideally, we should not need this API.
Class for containing MooseEnum item information.
Definition: MooseEnumItem.h:18
MooseMesh & _mesh
Definition: SystemBase.h:991
virtual std::vector< std::string > timeKernelVariableNames() override
Returns the names of the variables that have time derivative kernels in the system.
bool hasActiveObjects(THREAD_ID tid=0) const
NonlinearSystemBase(FEProblemBase &problem, libMesh::System &sys, const std::string &name)
void max(const T &r, T &o, Request &req) const
NumericVector< Number > * _u_dot
solution vector for u^dot
Definition: SystemBase.h:1006
MooseObjectWarehouse< ElementDamper > _element_dampers
Element Dampers for each thread.
void addObject(std::shared_ptr< Constraint > object, THREAD_ID tid=0, bool recurse=true) override
Add Constraint object to the warehouse.
virtual void setSolutionUDot(const NumericVector< Number > &udot)
Set transient term used by residual and Jacobian evaluation.
virtual libMesh::SparseMatrix< Number > & getMatrix(TagID tag)
Get a raw SparseMatrix.
Definition: SystemBase.C:1025
bool hasKokkosResidualObjects() const
virtual void augmentSparsity(libMesh::SparsityPattern::Graph &sparsity, std::vector< dof_id_type > &n_nz, std::vector< dof_id_type > &n_oz) override
Will modify the sparsity pattern to add logical geometric connections.
const std::vector< std::shared_ptr< MortarConstraintBase > > & getActiveMortarConstraints(const std::pair< BoundaryID, BoundaryID > &mortar_interface_key, bool displaced) const
MooseObjectWarehouse< T > & getMatrixTagsObjectWarehouse(const std::set< TagID > &tags, THREAD_ID tid)
Retrieve a moose object warehouse in which every moose object has one of the given matrix tags...
void computeScalarKernelsJacobians(const std::set< TagID > &tags)
void setInitialResidual(Real r)
Record the initial residual (for later relative convergence check)
Query query()
query creates and returns an initialized a query object for querying objects from the warehouse...
Definition: TheWarehouse.h:467
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num)=0
const_iterator begin() const
bool needInternalNeighborSideMaterial(SubdomainID subdomain_id, THREAD_ID tid) const
Indicates whether this system needs material properties on internal sides.
void computeKokkosResidual(const std::set< TagID > &tags)
Compute residual with Kokkos objects.
Base class for deriving dampers.
Definition: Damper.h:24
bool getFailNextNonlinearConvergenceCheck() const
Whether it will skip further residual evaluations and fail the next nonlinear convergence check(s) ...
Base class shared by AD and non-AD scalar kernels.
void addDamper(const std::string &damper_name, const std::string &name, InputParameters &parameters)
Adds a damper.
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
virtual void postAddResidualObject(ResidualObject &)
Called after any ResidualObject-derived objects are added to the system.
const std::vector< VariableName > & getVariableNames() const
Definition: SystemBase.h:863
virtual void preInit() override
This is called prior to the libMesh system has been init&#39;d.
Definition: SolverSystem.C:32
virtual void updateActive(THREAD_ID tid=0) override
Update the active status of Kernels.
virtual void timestepSetup() override
bool hasActiveElemElemConstraints(const InterfaceID interface_id, bool displaced) const
bool _off_diagonals_in_auto_scaling
Whether to include off diagonals when determining automatic scaling factors.
virtual unsigned int numVectorTags(const Moose::VectorTagType type=Moose::VECTOR_TAG_ANY) const
The total number of tags, which can be limited to the tag type.
Definition: SubProblem.C:196
void reinitNodeFace(const Node &secondary_node, const BoundaryID secondary_boundary, const PenetrationInfo &info, const bool displaced)
Reinitialize quantities such as variables, residuals, Jacobians, materials for node-face constraints...
Base class for deriving any boundary condition of a integrated type.
SolverParams & solverParams(unsigned int solver_sys_num=0)
Get the solver parameters.
NumericVector< Number > * _residual_ghosted
ghosted form of the residual
void setCachedJacobian(GlobalDataKey)
Sets previously-cached Jacobian values via SparseMatrix::set() calls.
Definition: Assembly.C:4477
TagID _Re_tag
Used for the residual vector from PETSc.
virtual void customSetup(const ExecFlagType &exec_type)
Definition: SystemBase.C:1574
MooseObjectWarehouse< T > & getVectorTagObjectWarehouse(TagID tag_id, THREAD_ID tid)
Retrieve a moose object warehouse in which every moose object has the given vector tag...
const std::set< SubdomainID > & getSubdomainsForVar(unsigned int var_number) const
Definition: SystemBase.h:764
virtual void addObject(std::shared_ptr< T > object, THREAD_ID tid=0, bool recurse=true)
Adds an object to the storage structure.
bool ignoreZerosInJacobian() const
Will return true if zeros in the Jacobian are to be dropped from the sparsity pattern.
void computeNodalBCsJacobian(const std::set< TagID > &tags)
Compute the Jacobian for nodal boundary conditions.
const ExecFlagType EXEC_PRE_KERNELS
Definition: Moose.C:58
libMesh::System & _sys
void mortarConstraints(Moose::ComputeType compute_type, const std::set< TagID > &vector_tags, const std::set< TagID > &matrix_tags)
Do mortar constraint residual/jacobian computations.
NumericVector< Number > * _increment_vec
increment vector
InterfaceKernelBase is the base class for all InterfaceKernel type classes.
QueryCache & condition(Args &&... args)
Adds a new condition to the query.
Definition: TheWarehouse.h:285
bool doingDG() const
Getter for _doing_dg.
void computeResidualTag(NumericVector< Number > &residual, TagID tag_id)
Computes residual for a given tag.
void addConstraint(const std::string &c_name, const std::string &name, InputParameters &parameters)
Adds a Constraint.
virtual TagName vectorTagName(const TagID tag) const
Retrieve the name associated with a TagID.
Definition: SubProblem.C:222
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
bool restoreOriginalNonzeroPattern() const
face_info_iterator ownedFaceInfoEnd()
Definition: MooseMesh.C:1507
void constraintJacobians(const SparseMatrix< Number > &jacobian_to_view, bool displaced)
Add jacobian contributions from Constraints.
virtual libMesh::System & system() override
Get the reference to the libMesh system.
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a variable of with specified name.
Definition: SystemBase.C:91
std::vector< BoundaryID > getBoundaryIDs(const Elem *const elem, const unsigned short int side) const
Returns a vector of boundary IDs for the requested element on the requested side. ...
bool preSolve()
Perform some steps to get ready for the solver.
void full_sparsity_pattern_needed()
bool _has_constraints
Whether or not this system has any Constraints.
dof_id_type first_dof(const processor_id_type proc) const
bool _computed_scaling
Flag used to indicate whether we have already computed the scaling Jacobian.
void remove_algebraic_ghosting_functor(GhostingFunctor &evaluable_functor)
MooseObjectTagWarehouse< InterfaceKernelBase > _interface_kernels
unsigned int n_vars() const
NumericVector< Number > & residualVector(TagID tag)
Return a residual vector that is associated with the residual tag.
NumericVector< Number > & solutionOld()
Definition: SystemBase.h:198
NumericVector< Number > & getResidualNonTimeVector()
Return a numeric vector that is associated with the nontime tag.
virtual bool hasScalarVariable(const std::string &var_name) const
Definition: SystemBase.C:877
const TagName PREVIOUS_NL_SOLUTION_TAG
Definition: MooseTypes.C:28
processor_id_type processor_id() const
std::shared_ptr< Predictor > _predictor
If predictor is active, this is non-NULL.
void enforceNodalConstraintsResidual(NumericVector< Number > &residual)
Enforce nodal constraints.
void subdomainsCovered(std::set< SubdomainID > &subdomains_covered, std::set< std::string > &unique_variables, THREAD_ID tid=0) const
Update supplied subdomain and variable coverate containters.
MooseObjectWarehouse< GeneralDamper > _general_dampers
General Dampers.
const std::vector< std::shared_ptr< ElemElemConstraint > > & getActiveElemElemConstraints(InterfaceID interface_id, bool displaced) const
virtual void initialSetup()
Setup Functions.
Definition: SystemBase.C:1560
bool defaultGhosting()
Whether or not the user has requested default ghosting ot be on.
Definition: SubProblem.h:144
void addCachedJacobian(GlobalDataKey)
Adds the values that have been cached by calling cacheJacobian() and or cacheJacobianNeighbor() to th...
Definition: Assembly.C:3800
virtual void cacheJacobian(const THREAD_ID tid) override
auto min(const L &left, const R &right)
void jacobianSetup() override
void setKokkosInitialSolution()
virtual NumericVector< Number > & getVector(const std::string &name)
Get a raw NumericVector by name.
Definition: SystemBase.C:934
MooseObjectTagWarehouse< IntegratedBCBase > _integrated_bcs
const DofMap & get_dof_map() const
virtual void reinitNodeFace(const Node *node, BoundaryID bnd_id, const THREAD_ID tid) override
virtual void residualSetup()
Definition: SystemBase.C:1588
virtual void reinitOffDiagScalars(const THREAD_ID tid) override
processor_id_type processor_id() const
virtual void addObject(std::shared_ptr< T > object, THREAD_ID tid=0, bool recurse=true) override
Adds an object to the storage structure.
virtual void setNeighborSubdomainID(const Elem *elem, unsigned int side, const THREAD_ID tid) override
virtual void addResidualScalar(const THREAD_ID tid=0)
virtual void subdomainSetup(THREAD_ID tid=0) const
virtual void jacobianSetup() override
virtual void addCachedResidual(const THREAD_ID tid) override
std::vector< std::vector< std::string > > _scaling_group_variables
A container of variable groupings that can be used in scaling calculations.
void addInterfaceKernel(std::string interface_kernel_name, const std::string &name, InputParameters &parameters)
Adds an interface kernel.
FieldSplitPreconditionerBase * _fsp
The field split preconditioner if this sytem is using one.
auto index_range(const T &sizable)
virtual NumericVector< Number > & residualCopy() override
void reinitMortarFunctors()
Update the mortar functors if the mesh has changed.
virtual NumericVector< Number > & residualGhosted() override
DiracKernelBase is the base class for all DiracKernel type classes.
virtual void updateActive(THREAD_ID tid=0)
Updates the active objects storage.
MooseObjectTagWarehouse< ResidualObject > _kokkos_nodal_bcs
void assembleScalingVector()
Assemble the numeric vector of scaling factors such that it can be used during assembly of the system...
BoundaryID _primary_boundary
NumericVector< Number > * _u_dotdot_old
old solution vector for u^dotdot
Definition: SystemBase.h:1013
Base variable class.
MooseObjectTagWarehouse< ScalarKernelBase > _scalar_kernels
virtual void residualEnd(THREAD_ID tid=0) const
const std::unordered_map< std::pair< BoundaryID, BoundaryID >, MortarInterfaceConfig > & getMortarInterfaces(bool on_displaced) const
void setConstraintSecondaryValues(NumericVector< Number > &solution, bool displaced)
Sets the value of constrained variables in the solution vector.
unsigned int THREAD_ID
Definition: MooseTypes.h:237
uint8_t dof_id_type
virtual void addJacobianScalar(const THREAD_ID tid=0)
NearestNodeLocator & _nearest_node
const std::set< SubdomainID > & meshSubdomains() const
Returns a read-only reference to the set of subdomains currently present in the Mesh.
Definition: MooseMesh.C:3271
ParallelType
virtual void addCachedJacobian(const THREAD_ID tid) override
virtual void timestepSetup()
Definition: SystemBase.C:1567
virtual ~NonlinearSystemBase()
virtual void preInit() override
This is called prior to the libMesh system has been init&#39;d.
virtual void residualSetup() override
void setPreconditioner(std::shared_ptr< MoosePreconditioner > pc)
Sets a preconditioner.
virtual void localize(std::vector< T > &v_local) const=0
MooseObjectWarehouse< ADDirichletBCBase > _ad_preset_nodal_bcs
virtual libMesh::System & system() override
Get the reference to the libMesh system.
Key structure for APIs manipulating global vectors/matrices.
Definition: Assembly.h:844