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