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