https://mooseframework.inl.gov
Loading...
Searching...
No Matches
NonlinearSystem.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// moose includes
11#include "NonlinearSystem.h"
12#include "FEProblem.h"
13#include "DisplacedProblem.h"
14#include "TimeIntegrator.h"
16#include "PetscSupport.h"
19#include "MooseVariableScalar.h"
20#include "MooseTypes.h"
21#include "AuxiliarySystem.h"
22#include "Console.h"
23
24#include "libmesh/nonlinear_solver.h"
25#include "libmesh/petsc_nonlinear_solver.h"
26#include "libmesh/sparse_matrix.h"
27#include "libmesh/petsc_matrix.h"
28#include "libmesh/petsc_vector.h"
29#include "libmesh/diagonal_matrix.h"
30#include "libmesh/default_coupling.h"
31#include "libmesh/petsc_solver_exception.h"
32
33namespace Moose
34{
35void
36compute_jacobian(const NumericVector<Number> & soln,
37 SparseMatrix<Number> & jacobian,
38 NonlinearImplicitSystem & sys)
39{
40 FEProblemBase * p =
41 sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
42 p->computeJacobianSys(sys, soln, jacobian);
43}
44
45void
46compute_bounds(NumericVector<Number> & lower,
47 NumericVector<Number> & upper,
48 NonlinearImplicitSystem & sys)
49{
50 FEProblemBase * p =
51 sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
52 p->computeBounds(sys, lower, upper);
53}
54
55void
56compute_nullspace(std::vector<NumericVector<Number> *> & sp, NonlinearImplicitSystem & sys)
57{
58 FEProblemBase * p =
59 sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
60 p->computeNullSpace(sys, sp);
61}
62
63void
64compute_transpose_nullspace(std::vector<NumericVector<Number> *> & sp,
65 NonlinearImplicitSystem & sys)
66{
67 FEProblemBase * p =
68 sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
69 p->computeTransposeNullSpace(sys, sp);
70}
71
72void
73compute_nearnullspace(std::vector<NumericVector<Number> *> & sp, NonlinearImplicitSystem & sys)
74{
75 FEProblemBase * p =
76 sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
77 p->computeNearNullSpace(sys, sp);
78}
79
80void
81compute_postcheck(const NumericVector<Number> & old_soln,
82 NumericVector<Number> & search_direction,
83 NumericVector<Number> & new_soln,
84 bool & changed_search_direction,
85 bool & changed_new_soln,
86 NonlinearImplicitSystem & sys)
87{
88 FEProblemBase * p =
89 sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
91 sys, old_soln, search_direction, new_soln, changed_search_direction, changed_new_soln);
92}
93} // namespace Moose
94
95NonlinearSystem::NonlinearSystem(FEProblemBase & fe_problem, const std::string & name)
97 fe_problem, fe_problem.es().add_system<NonlinearImplicitSystem>(name), name),
98 _nl_implicit_sys(fe_problem.es().get_system<NonlinearImplicitSystem>(name)),
99 _nl_residual_functor(_fe_problem),
100 _fd_residual_functor(_fe_problem),
101 _resid_and_jac_functor(_fe_problem),
102 _use_coloring_finite_difference(false)
103{
104 nonlinearSolver()->residual_object = &_nl_residual_functor;
110
112 cast_ptr<libMesh::PetscNonlinearSolver<Real> *>(_nl_implicit_sys.nonlinear_solver.get());
113 if (petsc_solver)
114 {
115 petsc_solver->set_residual_zero_out(false);
116 petsc_solver->set_jacobian_zero_out(false);
117 petsc_solver->use_default_monitor(false);
118 }
119}
120
122
123void
138
139void
141{
142 // Only attach the postcheck function to the solver if we actually
143 // have dampers or if the FEProblemBase needs to update the solution,
144 // which is also done during the linesearch postcheck. It doesn't
145 // hurt to do this multiple times, it is just setting a pointer.
149
151 {
152 TIME_SECTION("nlPreSMOResidual", 3, "Computing Pre-SMO Residual");
153 // Calculate the pre-SMO residual for use in the convergence criterion.
159 _console << " * Nonlinear |R| = "
160 << Console::outputNorm(std::numeric_limits<Real>::max(), _pre_smo_residual)
161 << " (Before preset BCs, predictors, correctors, and constraints)\n";
162 _console << std::flush;
163 }
164
165 const bool presolve_succeeded = preSolve();
166 if (!presolve_succeeded)
167 return;
168
170
171 const bool time_integrator_solve = std::any_of(_time_integrators.begin(),
172 _time_integrators.end(),
173 [](auto & ti) { return ti->overridesSolve(); });
174 if (time_integrator_solve)
175 mooseAssert(_time_integrators.size() == 1,
176 "If solve is overridden, then there must be only one time integrator");
177
178 if (time_integrator_solve)
179 _time_integrators.front()->solve();
180 else
181 system().solve();
182
183 for (auto & ti : _time_integrators)
184 {
185 if (!ti->overridesSolve())
186 ti->setNumIterationsLastSolve();
187 ti->postSolve();
188 }
189
190 if (!_time_integrators.empty())
191 {
192 _n_iters = _time_integrators.front()->getNumNonlinearIterations();
193 _n_linear_iters = _time_integrators.front()->getNumLinearIterations();
194 }
195 else
196 {
198 _n_linear_iters = _nl_implicit_sys.nonlinear_solver->get_total_linear_iterations();
199 }
200
201 // store info about the solve
203
204 // determine whether solution invalid occurs in the converged solution
206
208 LibmeshPetscCall(MatFDColoringDestroy(&_fdcoloring));
209}
210
211void
213 const std::set<TagID> & vector_tags_to_close)
214{
216 cast_ref<libMesh::PetscNonlinearSolver<Real> &>(*sys().nonlinear_solver);
217
218 if (exec_flag == EXEC_LINEAR || exec_flag == EXEC_POSTCHECK)
219 {
220 LibmeshPetscCall(SNESSetFunctionDomainError(solver.snes()));
221
222 // Clean up by getting vectors into a valid state for a
223 // (possible) subsequent solve.
224 closeTaggedVectors(vector_tags_to_close);
225 }
226 else if (exec_flag == EXEC_NONLINEAR)
227 LibmeshPetscCall(SNESSetJacobianDomainError(solver.snes()));
228 else
229 mooseError("Unsupported execute flag: ", Moose::stringify(exec_flag));
230}
231
232void
234{
235 std::shared_ptr<FiniteDifferencePreconditioner> fdp =
236 std::dynamic_pointer_cast<FiniteDifferencePreconditioner>(_preconditioner);
237 if (!fdp)
238 mooseError("Did not setup finite difference preconditioner, and please add a preconditioning "
239 "block with type = fdp");
240
241 if (fdp->finiteDifferenceType() == "coloring")
242 {
245 }
246
247 else if (fdp->finiteDifferenceType() == "standard")
248 {
251 }
252 else
253 mooseError("Unknown finite difference type");
254}
255
256void
258{
259 // Make sure that libMesh isn't going to override our preconditioner
260 _nl_implicit_sys.nonlinear_solver->jacobian = nullptr;
261
262 libMesh::PetscNonlinearSolver<Number> * petsc_nonlinear_solver =
263 cast_ptr<libMesh::PetscNonlinearSolver<Number> *>(_nl_implicit_sys.nonlinear_solver.get());
264
265 PetscMatrix<Number> * petsc_mat =
266 cast_ptr<PetscMatrix<Number> *>(&_nl_implicit_sys.get_system_matrix());
267
268 LibmeshPetscCall(SNESSetJacobian(petsc_nonlinear_solver->snes(),
269 petsc_mat->mat(),
270 petsc_mat->mat(),
271 SNESComputeJacobianDefault,
272 nullptr));
273}
274
275void
277{
278 // Make sure that libMesh isn't going to override our preconditioner
279 _nl_implicit_sys.nonlinear_solver->jacobian = nullptr;
280
281 libMesh::PetscNonlinearSolver<Number> & petsc_nonlinear_solver =
283
284 // Pointer to underlying PetscMatrix type
285 PetscMatrix<Number> * petsc_mat =
286 dynamic_cast<PetscMatrix<Number> *>(&_nl_implicit_sys.get_system_matrix());
287
289
290 if (!petsc_mat)
291 mooseError("Could not convert to Petsc matrix.");
292
293 petsc_mat->close();
294
295 ISColoring iscoloring;
296
297 // PETSc 3.5.x
298 MatColoring matcoloring;
299 LibmeshPetscCallA(_communicator.get(), MatColoringCreate(petsc_mat->mat(), &matcoloring));
300 LibmeshPetscCallA(_communicator.get(), MatColoringSetType(matcoloring, MATCOLORINGLF));
301 LibmeshPetscCallA(_communicator.get(), MatColoringSetFromOptions(matcoloring));
302 LibmeshPetscCallA(_communicator.get(), MatColoringApply(matcoloring, &iscoloring));
303 LibmeshPetscCallA(_communicator.get(), MatColoringDestroy(&matcoloring));
304
305 LibmeshPetscCallA(_communicator.get(),
306 MatFDColoringCreate(petsc_mat->mat(), iscoloring, &_fdcoloring));
307 LibmeshPetscCallA(_communicator.get(), MatFDColoringSetFromOptions(_fdcoloring));
308 // clang-format off
309#if PETSC_VERSION_LESS_THAN(3, 24, 0)
310 LibmeshPetscCallA(_communicator.get(),
311 MatFDColoringSetFunction(_fdcoloring,
312 (PetscErrorCode(*)(void))(void (*)(void))
314 &petsc_nonlinear_solver));
315#else
316 LibmeshPetscCallA(_communicator.get(),
317 MatFDColoringSetFunction(_fdcoloring,
318 (MatFDColoringFn*)
320 &petsc_nonlinear_solver));
321#endif
322 // clang-format on
323 LibmeshPetscCallA(_communicator.get(),
324 MatFDColoringSetUp(petsc_mat->mat(), iscoloring, _fdcoloring));
325 LibmeshPetscCallA(_communicator.get(),
326 SNESSetJacobian(petsc_nonlinear_solver.snes(),
327 petsc_mat->mat(),
328 petsc_mat->mat(),
329 SNESComputeJacobianDefaultColor,
330 _fdcoloring));
331 // PETSc >=3.3.0
332 LibmeshPetscCallA(_communicator.get(), ISColoringDestroy(&iscoloring));
333}
334
335bool
337{
339 return false;
340 // When not computing the residual (for example at the beginning of a time step),
341 // we may be in the process of counting invalid solution warnings, so the call to
342 // acceptInvalidSolution() would fail due to lack of parallel synchronization
343 // TODO: think of a better solution
345 {
346 mooseWarning("The solution is not converged due to the solution being invalid.");
347 return false;
348 }
349 return _nl_implicit_sys.nonlinear_solver->converged;
350}
351
352void
353NonlinearSystem::attachPreconditioner(Preconditioner<Number> * preconditioner)
354{
355 nonlinearSolver()->attach_preconditioner(preconditioner);
356}
357
358void
360{
361#ifdef MOOSE_KOKKOS_ENABLED
362 // The Kokkos assembler writes Jacobian contributions directly into the underlying PETSc
363 // Mat (see Moose::Kokkos::Matrix::create), which requires the matrix to be a
364 // PetscMatrix rather than the DiagonalMatrix/LumpedMassMatrix used to store scaling
365 // factors.
367 {
368 // Assemble the Jacobian into the system libMesh matrix, which is a PetscMatrix, so that the
369 // Kokkos kernels can write directly into its Mat.
370 auto & jacobian = _nl_implicit_sys.get_system_matrix();
372
373 auto & petsc_matrix = cast_ref<PetscMatrix<Number> &>(jacobian);
374
375 // Create the Petsc reduction vector with the layout of the matrix so that extracting the
376 // reduction values matches the matrix's vector type on device or host.
377 Vec scaling_vec = nullptr;
378 LibmeshPetscCall(MatCreateVecs(petsc_matrix.mat(), nullptr, &scaling_vec));
379
380 {
381 libMesh::PetscVector<Number> scaling_vector(scaling_vec, this->comm());
382
383 // For off-diagonal scaling, sum the absolute values of the assembled matrix entries.
384 // The host LumpedMassMatrix instead takes the absolute value of each element contribution
385 // before assembling it. The results differ if contributions from local element matrices to
386 // the same global matrix entry cancel because they have opposite signs. MatGetDiagonal runs
387 // on the device for Kokkos matrices, but MatGetRowSumAbs currently synchronizes the matrix
388 // data to the host.
390 LibmeshPetscCall(MatGetRowSumAbs(petsc_matrix.mat(), scaling_vec));
391 else
392 LibmeshPetscCall(MatGetDiagonal(petsc_matrix.mat(), scaling_vec));
393
394 *_scaling_matrix = scaling_vector;
396 }
397
398 LibmeshPetscCall(VecDestroy(&scaling_vec));
399 return;
400 }
401#endif
402
404}
405
406void
411
412SNES
414{
417
418 if (petsc_solver)
419 {
420 const char * snes_prefix = nullptr;
421 std::string snes_prefix_str;
422 if (system().prefix_with_name())
423 {
424 snes_prefix_str = system().prefix();
425 snes_prefix = snes_prefix_str.c_str();
426 }
427 return petsc_solver->snes(snes_prefix);
428 }
429 else
430 mooseError("It is not a petsc nonlinear solver");
431}
432
433void
435{
438 "Evaluting the residual and Jacobian together does not make sense for a JFNK solve type in "
439 "which only function evaluations are required, e.g. there is no need to form a matrix");
440
441 nonlinearSolver()->residual_object = nullptr;
442 nonlinearSolver()->jacobian = nullptr;
443 nonlinearSolver()->residual_and_jacobian_object = &_resid_and_jac_functor;
444}
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
const ExecFlagType EXEC_POSTCHECK
Definition Moose.C:36
const ExecFlagType EXEC_LINEAR
Definition Moose.C:32
const ExecFlagType EXEC_NONLINEAR
Definition Moose.C:34
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
static std::string outputNorm(const Real &old_norm, const Real &norm, const unsigned int precision=6)
A helper function for outputting norms in color.
Definition Console.C:617
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
virtual void computeNearNullSpace(libMesh::NonlinearImplicitSystem &sys, std::vector< NumericVector< libMesh::Number > * > &sp)
void needsPreviousNewtonIteration(bool state)
Set a flag that indicated that user required values for the previous Newton iterate.
virtual bool hasException()
Whether or not an exception has occurred.
virtual bool shouldUpdateSolution()
Check to see whether the problem should update the solution.
virtual void computeJacobianSys(libMesh::NonlinearImplicitSystem &sys, const NumericVector< libMesh::Number > &soln, libMesh::SparseMatrix< libMesh::Number > &jacobian)
Form a Jacobian matrix.
bool acceptInvalidSolution() const
Whether or not to accept the solution based on its invalidity.
bool getFailNextNonlinearConvergenceCheck() const
Whether it will skip further residual evaluations and fail the next nonlinear convergence check(s)
bool hasDampers()
Whether or not this system has dampers.
bool hasKokkosResidualObjects() const
SolverParams & solverParams(unsigned int solver_sys_num=0)
Get the solver parameters.
virtual void computeNullSpace(libMesh::NonlinearImplicitSystem &sys, std::vector< NumericVector< libMesh::Number > * > &sp)
virtual void computeBounds(libMesh::NonlinearImplicitSystem &sys, NumericVector< libMesh::Number > &lower, NumericVector< libMesh::Number > &upper)
virtual void computePostCheck(libMesh::NonlinearImplicitSystem &sys, const NumericVector< libMesh::Number > &old_soln, NumericVector< libMesh::Number > &search_direction, NumericVector< libMesh::Number > &new_soln, bool &changed_search_direction, bool &changed_new_soln)
bool useSNESMFReuseBase()
Return a flag that indicates if we are reusing the vector base.
virtual void computeTransposeNullSpace(libMesh::NonlinearImplicitSystem &sys, std::vector< NumericVector< libMesh::Number > * > &sp)
virtual void computeResidualSys(libMesh::NonlinearImplicitSystem &sys, const NumericVector< libMesh::Number > &soln, NumericVector< libMesh::Number > &residual)
This function is called by Libmesh to form a residual.
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.
SolutionInvalidity & solutionInvalidity()
Get the SolutionInvalidity for this app.
Definition MooseApp.h:182
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
Class for containing MooseEnum item information.
Nonlinear system to be solved.
bool preSolve()
Perform some steps to get ready for the solver.
bool _use_finite_differenced_preconditioner
Whether or not to use a finite differenced preconditioner.
Real _pre_smo_residual
The pre-SMO residual, see setPreSMOResidual for a detailed explanation.
bool shouldEvaluatePreSMOResidual() const
We offer the option to check convergence against the pre-SMO residual.
std::unique_ptr< libMesh::DiagonalMatrix< Number > > _scaling_matrix
A diagonal matrix used for computing scaling.
bool _off_diagonals_in_auto_scaling
Whether to include off diagonals when determining automatic scaling factors.
virtual libMesh::System & system() override
Get the reference to the libMesh system.
std::shared_ptr< MoosePreconditioner > _preconditioner
Preconditioner.
virtual void potentiallySetupFiniteDifferencing() override
Create finite differencing contexts for assembly of the Jacobian and/or approximating the action of t...
void setupColoringFiniteDifferencedPreconditioner()
According to the nonzero pattern provided in the matrix, a graph is constructed.
ComputeResidualFunctor _nl_residual_functor
virtual libMesh::NonlinearImplicitSystem & sys()
virtual SNES getSNES() override
virtual ~NonlinearSystem()
void setupStandardFiniteDifferencedPreconditioner()
Form preconditioning matrix via a standard finite difference method column-by-column.
virtual void stopSolve(const ExecFlagType &exec_flag, const std::set< TagID > &vector_tags_to_close) override
Quit the current solve as soon as possible.
ComputeResidualAndJacobian _resid_and_jac_functor
virtual void setupFiniteDifferencedPreconditioner() override
ComputeFDResidualFunctor _fd_residual_functor
void computeScalingResidual() override
Compute a "residual" for automatic scaling purposes.
NonlinearSystem(FEProblemBase &problem, const std::string &name)
libMesh::NonlinearImplicitSystem & _nl_implicit_sys
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver() override
virtual void attachPreconditioner(libMesh::Preconditioner< Number > *preconditioner) override
Attach a customized preconditioner that requires physics knowledge.
virtual void solve() override
Solve the system (using libMesh magic)
virtual void residualAndJacobianTogether() override
Call this method if you want the residual and Jacobian to be computed simultaneously.
virtual bool converged() override
Returns the convergence state.
void computeScalingJacobian() override
Compute a "Jacobian" for automatic scaling purposes.
bool _use_coloring_finite_difference
virtual NumericVector< Number > & RHS() override
bool hasSynced() const
Whether the solution invalidity has synchronized iteration counts across MPI processes.
void checkInvalidSolution()
const NumericVector< Number > * _current_solution
solution vector from solver
MooseApp & _app
FEProblemBase & _fe_problem
the governing finite element/volume problem
std::vector< std::shared_ptr< TimeIntegrator > > _time_integrators
Time integrator.
unsigned int number() const
Gets the number of this system.
void closeTaggedVectors(const std::set< TagID > &tags)
Close all vectors for given tags.
Definition SystemBase.C:669
NumericVector< Number > * rhs
const SparseMatrix< Number > & get_system_matrix() const
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
unsigned int n_nonlinear_iterations() const
NonlinearImplicitSystem::ComputeResidual * mffd_residual_object
virtual void close()=0
virtual Real l2_norm() const=0
const Parallel::Communicator & _communicator
const Parallel::Communicator & comm() const
void set_residual_zero_out(bool state)
void set_snesmf_reuse_base(bool state)
SNES snes(const char *name=nullptr)
void set_jacobian_zero_out(bool state)
void use_default_monitor(bool state)
virtual void close() override
std::unique_ptr< NumericVector< Number > > current_local_solution
void prefix_with_name(bool value)
virtual void solve()
std::string prefix() const
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
void compute_nearnullspace(std::vector< NumericVector< Number > * > &sp, NonlinearImplicitSystem &sys)
@ ST_JFNK
Jacobian-Free Newton Krylov.
Definition MooseTypes.h:899
void compute_nullspace(std::vector< NumericVector< Number > * > &sp, NonlinearImplicitSystem &sys)
void compute_jacobian(const NumericVector< Number > &soln, SparseMatrix< Number > &jacobian, NonlinearImplicitSystem &sys)
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:65
void compute_postcheck(const NumericVector< Number > &old_soln, NumericVector< Number > &search_direction, NumericVector< Number > &new_soln, bool &changed_search_direction, bool &changed_new_soln, NonlinearImplicitSystem &sys)
void compute_transpose_nullspace(std::vector< NumericVector< Number > * > &sp, NonlinearImplicitSystem &sys)
void compute_bounds(NumericVector< Number > &lower, NumericVector< Number > &upper, NonlinearImplicitSystem &sys)
PetscErrorCode libmesh_petsc_snes_fd_residual(SNES, Vec x, Vec r, void *ctx)