https://mooseframework.inl.gov
Loading...
Searching...
No Matches
DefaultNonlinearConvergence.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
12#include "FEProblemBase.h"
13#include "PetscSupport.h"
14#include "NonlinearSystemBase.h"
16
17#include "libmesh/system.h"
18
19// PETSc includes
20#include <petsc.h>
21#include <petscmat.h>
22#include <petscsnes.h>
23
25
28{
31
32 params.addPrivateParam<bool>("added_as_default", false);
33
34 params.addClassDescription("Default convergence criteria for FEProblem.");
35
36 return params;
37}
38
40 : DefaultConvergenceBase(parameters),
41 _fe_problem(*getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
42 _nl_abs_div_tol(getSharedExecutionerParam<Real>("nl_abs_div_tol")),
43 _nl_rel_div_tol(getSharedExecutionerParam<Real>("nl_div_tol")),
44 _div_threshold(std::numeric_limits<Real>::max()),
45 _nl_forced_its(getSharedExecutionerParam<unsigned int>("nl_forced_its")),
46 _nl_max_pingpong(getSharedExecutionerParam<unsigned int>("n_max_nonlinear_pingpong")),
47 _nl_current_pingpong(0),
48 _nl_rel_step_tol(getSharedExecutionerParam<Real>("nl_rel_step_tol")),
49 _nl_max_funcs(getSharedExecutionerParam<unsigned int>("nl_max_funcs")),
50 _nl_max_its(getSharedExecutionerParam<unsigned int>("nl_max_its")),
51 _nl_abs_tol(getSharedExecutionerParam<Real>("nl_abs_tol")),
52 _nl_rel_tol(getSharedExecutionerParam<Real>("nl_rel_tol"))
53{
54}
55
56void
58{
60
61 // This method is also called in preLoop(), which will overwrite the parameters set here.
62 // It needs to be called here to collect the names of any duplicate parameters for the
63 // checkDuplicateSetSharedExecutionerParams() check. It needs to be called in preLoop()
64 // because it needs to know the current nonlinear system; Convergence objects do not know
65 // their "associated" nonlinear system (and they could in fact have multiple).
67}
68
69void
71{
73
75 mooseError("DefaultNonlinearConvergence can only be used with nonlinear solves.");
76}
77
78void
85
86void
88{
90
91 auto & params = nl_sys.system().parameters;
92 params.set<unsigned int>("nonlinear solver maximum iterations") = _nl_max_its;
93 params.set<unsigned int>("nonlinear solver maximum function evaluations") = _nl_max_funcs;
94 params.set<Real>("nonlinear solver absolute residual tolerance") = _nl_abs_tol;
95 params.set<Real>("nonlinear solver relative residual tolerance") = _nl_rel_tol;
96 params.set<Real>("nonlinear solver divergence tolerance") =
97 getSharedExecutionerParam<Real>("nl_div_tol");
98 params.set<Real>("nonlinear solver absolute step tolerance") =
99 getSharedExecutionerParam<Real>("nl_abs_step_tol");
100 params.set<Real>("nonlinear solver relative step tolerance") = _nl_rel_step_tol;
101
102 // Records which object's tolerances are the ones actually active on the shared SNES, so that
103 // checkPetscToleranceOverrides() does not mistake another DefaultNonlinearConvergence object's
104 // (legitimately) overwriting these same parameters for an ignored PETSc command-line option.
105 params.set<const DefaultNonlinearConvergence *>(
106 "_default_nonlinear_convergence_tolerance_writer") = this;
107}
108
114
115bool
117 const Real fnorm,
118 const Real ref_norm,
119 const Real rel_tol,
120 const Real abs_tol,
121 std::ostringstream & oss)
122{
123 if (fnorm < abs_tol)
124 {
125 oss << "Converged due to absolute residual " << fnorm << " < absolute tolerance (" << abs_tol
126 << ")\n";
127 return true;
128 }
129 else if (n_iter && fnorm <= ref_norm * rel_tol)
130 {
131 oss << "Converged due to relative/normalized residual norm " << fnorm / ref_norm
132 << " < relative tolerance (" << rel_tol << ")\n";
133 return true;
134 }
135 else
136 return false;
137}
138
139void
141{
143 return;
145
147 auto & params = nl_sys.system().parameters;
148 // If another DefaultNonlinearConvergence object last wrote these shared parameters (as
149 // happens when multiple such objects are combined, e.g. via ParsedConvergence, onto the same
150 // nonlinear system), its tolerances are the ones actually active on the SNES, not ours; that
151 // is not a PETSc command-line override, so there is nothing for us to warn about here.
152 if (params.get<const DefaultNonlinearConvergence *>(
153 "_default_nonlinear_convergence_tolerance_writer") != this)
154 return;
155
156 SNES snes = nl_sys.getSNES();
157 PetscReal abs_tol, rel_tol, rel_step_tol;
158 PetscInt max_its, max_funcs;
159 LibmeshPetscCallA(
160 _fe_problem.comm().get(),
161 SNESGetTolerances(snes, &abs_tol, &rel_tol, &rel_step_tol, &max_its, &max_funcs));
162
163 std::ostringstream oss;
164 if (abs_tol != _nl_abs_tol)
165 oss << " -snes_atol = " << abs_tol << " (nl_abs_tol = " << _nl_abs_tol << ")\n";
166 if (rel_tol != _nl_rel_tol)
167 oss << " -snes_rtol = " << rel_tol << " (nl_rel_tol = " << _nl_rel_tol << ")\n";
168 if (rel_step_tol != _nl_rel_step_tol)
169 oss << " -snes_stol = " << rel_step_tol << " (nl_rel_step_tol = " << _nl_rel_step_tol << ")\n";
170 if (max_its != static_cast<PetscInt>(_nl_max_its))
171 oss << " -snes_max_it = " << max_its << " (nl_max_its = " << _nl_max_its << ")\n";
172 if (max_funcs != static_cast<PetscInt>(_nl_max_funcs))
173 oss << " -snes_max_funcs = " << max_funcs << " (nl_max_funcs = " << _nl_max_funcs << ")\n";
174
175 if (!oss.str().empty())
176 mooseWarning("The following PETSc SNES option(s) were set to a value different from what "
177 "this Convergence object enforces. Because this object performs its own "
178 "convergence check using its own cached tolerances, these PETSc-level settings "
179 "have no effect:\n",
180 oss.str());
181}
182
185{
186 TIME_SECTION(_perfid_check_convergence);
187
190
191 SNES snes = system.getSNES();
192
194
195 // ||u||
196 PetscReal xnorm;
197 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetSolutionNorm(snes, &xnorm));
198
199 // ||r||
200 PetscReal fnorm;
201 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetFunctionNorm(snes, &fnorm));
202
203 // ||du||
204 PetscReal snorm;
205 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetUpdateNorm(snes, &snorm));
206
207 // Get current number of function evaluations done by SNES
208 PetscInt nfuncs;
209 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetNumberFunctionEvals(snes, &nfuncs));
210
211#if !PETSC_VERSION_LESS_THAN(3, 8, 4)
212 PetscBool force_iteration = PETSC_FALSE;
213 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetForceIteration(snes, &force_iteration));
214
215 // if PETSc says to force iteration, then force at least one iteration
216 if (force_iteration && !(_nl_forced_its))
217 _nl_forced_its = 1;
218
219 // if specified here to force iteration, but PETSc doesn't know, tell it
220 if (!force_iteration && (_nl_forced_its))
221 {
222 LibmeshPetscCallA(_fe_problem.comm().get(), SNESSetForceIteration(snes, PETSC_TRUE));
223 }
224#endif
225
226 // See if SNESSetFunctionDomainError() has been called.
227 // Note: SNESSetFunctionDomainError() and SNESGetFunctionDomainError() were added
228 // in different releases of PETSc. The latter was removed in PETSc 3.25.0.
229#if PETSC_VERSION_LESS_THAN(3, 25, 0)
230 PetscBool domainerror;
231 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetFunctionDomainError(snes, &domainerror));
232 if (domainerror)
234#else
235 SNESConvergedReason reason;
236 LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetConvergedReason(snes, &reason));
237 if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
239#endif
240
241 // Needed by ResidualReferenceConvergence
243
244 Real fnorm_old;
245 // This is the first residual before any iterations have been done, but after
246 // solution-modifying objects (if any) have been imposed on the solution vector.
247 // We save it, and use it to detect convergence if system.usePreSMOResidual() == false.
248 if (n_iter == 0)
249 {
250 system.setInitialResidual(fnorm);
251 fnorm_old = fnorm;
253 }
254 else
255 fnorm_old = system._last_nl_rnorm;
256
257 // Check for nonlinear residual ping-pong.
258 // Ping-pong will always start from a residual increase
259 if ((_nl_current_pingpong % 2 == 1 && !(fnorm > fnorm_old)) ||
260 (_nl_current_pingpong % 2 == 0 && fnorm > fnorm_old))
262 else
264
265 const auto ref_residual = system.referenceResidual();
266 std::ostringstream oss;
267 if (n_iter < _nl_forced_its)
268 oss << "Number of forced iterations not yet reached: " << n_iter << " < " << _nl_forced_its
269 << '\n';
270 else if (fnorm != fnorm)
271 {
272 oss << "Failed to converge, residual norm is NaN\n";
274 }
275 else if (checkResidualConvergence(n_iter, fnorm, ref_residual, _nl_rel_tol, _nl_abs_tol, oss))
277 else if (nfuncs >= cast_int<PetscInt>(_nl_max_funcs))
278 {
279 oss << "Exceeded maximum number of residual evaluations: " << nfuncs << " > " << _nl_max_funcs
280 << '\n';
282 }
283 else if ((n_iter >= _nl_forced_its) && n_iter && fnorm > system._last_nl_rnorm &&
284 fnorm >= _div_threshold)
285 {
286 oss << "Nonlinear solve was blowing up!\n";
288 }
289 else if (snorm < _nl_rel_step_tol * xnorm)
290 {
291 oss << "Converged due to small update length: " << snorm << " < " << _nl_rel_step_tol << " * "
292 << xnorm << '\n';
294 }
295 else if (_nl_rel_div_tol > 0 && fnorm > ref_residual * _nl_rel_div_tol)
296 {
297 oss << "Diverged due to relative residual " << ref_residual << " > divergence tolerance "
298 << _nl_rel_div_tol << " * relative residual " << ref_residual << '\n';
300 }
301 else if (_nl_abs_div_tol > 0 && fnorm > _nl_abs_div_tol)
302 {
303 oss << "Diverged due to residual " << fnorm << " > absolute divergence tolerance "
304 << _nl_abs_div_tol << '\n';
306 }
308 {
309 oss << "Diverged due to maximum nonlinear residual pingpong achieved" << '\n';
311 }
312
313 system._last_nl_rnorm = fnorm;
314 system._current_nl_its = static_cast<unsigned int>(n_iter);
315
316 std::string msg;
317 msg = oss.str();
318 if (_app.multiAppLevel() > 0)
320 if (msg.length() > 0)
321#if !PETSC_VERSION_LESS_THAN(3, 17, 0)
322 LibmeshPetscCallA(_fe_problem.comm().get(), PetscInfo(snes, "%s", msg.c_str()));
323#else
324 LibmeshPetscCallA(_fe_problem.comm().get(), PetscInfo(snes, msg.c_str()));
325#endif
326
327 verboseOutput(oss);
328
329 return status;
330}
331
332void
334{
335 _nl_max_its = max_iter;
336}
337
338void
340{
341 _nl_abs_tol = abs_tol;
342}
343
344void
346{
347 _nl_rel_tol = rel_tol;
348}
registerMooseObject("MooseApp", DefaultNonlinearConvergence)
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
void ErrorVector unsigned int
virtual void preLoop()
Method that gets called before each iteration loop.
Definition Convergence.h:53
PerfID _perfid_check_convergence
Performance ID for checkConvergence.
Definition Convergence.h:82
void verboseOutput(std::ostringstream &oss)
Outputs the stream to the console if verbose output is enabled.
Definition Convergence.C:51
MooseConvergenceStatus
Status returned by calls to checkConvergence.
Definition Convergence.h:34
virtual void checkIterationType(IterationType) const
Perform checks related to the iteration type.
Definition Convergence.h:48
Base class for default convergence criteria.
virtual void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job.
static InputParameters validParams()
Default nonlinear convergence criteria for FEProblem.
const Real _nl_rel_div_tol
Nonlinear relative divergence tolerance.
virtual void preLoop() override
Method that gets called before each iteration loop.
unsigned int _nl_current_pingpong
Current number of nonlinear ping-pong iterations for the current solve.
const Real _nl_abs_div_tol
Nonlinear absolute divergence tolerance.
void setNonlinearSystemParameters()
Sets the nonlinear system parameters, such as tolerances.
virtual void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job.
unsigned int _nl_max_its
Nonlinear maximum nonlinear iterations (modifiable by setMaximumIterations)
bool _nl_checked_petsc_tolerance_overrides
Whether checkPetscToleranceOverrides() has already run for this simulation.
unsigned int _nl_forced_its
Number of iterations to force.
const Real _nl_rel_step_tol
Nonlinear relative step tolerance.
void setMaximumIterations(const unsigned int max_iter)
Sets the maximum nonlinear iterations.
Real _nl_rel_tol
Nonlinear relative tolerance (modifiable by setRelativeTolerance)
virtual NonlinearSystemBase & nonlinearSystem()
Nonlinear system whose convergence state should be checked.
virtual bool checkResidualConvergence(const unsigned int n_iter, const Real fnorm, const Real ref_norm, const Real rel_tol, const Real abs_tol, std::ostringstream &oss)
Check the absolute and relative convergence of the nonlinear solution.
DefaultNonlinearConvergence(const InputParameters &parameters)
virtual void nonlinearConvergenceSetup()
Performs setup necessary for each call to checkConvergence.
const unsigned int _nl_max_funcs
Maximum number of residual (function) evaluations.
virtual void checkIterationType(IterationType it_type) const override
Perform checks related to the iteration type.
const Real _div_threshold
Divergence threshold value.
void setRelativeTolerance(const Real rel_tol)
Sets the relative nonlinear tolerance.
void setAbsoluteTolerance(const Real abs_tol)
Sets the absolute nonlinear tolerance.
void checkPetscToleranceOverrides()
Warns, once per simulation, if any PETSc SNES tolerance/iteration options (e.g.
const unsigned int _nl_max_pingpong
Maximum number of nonlinear ping-pong iterations for a solve.
virtual MooseConvergenceStatus checkConvergence(unsigned int n_iter) override
Returns convergence status.
Real _nl_abs_tol
Nonlinear absolute tolerance (modifiable by setAbsoluteTolerance)
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
NonlinearSystemBase & currentNonlinearSystem()
static InputParameters feProblemDefaultConvergenceParams()
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addPrivateParam(const std::string &name, const T &value)
These method add a parameter to the InputParameters object which can be retrieved like any other para...
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
unsigned int multiAppLevel() const
The MultiApp Level.
Definition MooseApp.h:859
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
Class for containing MooseEnum item information.
MooseApp & _app
The MOOSE application this is associated with.
Definition MooseBase.h:375
Nonlinear system to be solved.
Real referenceResidual() const
The reference residual used in relative convergence check.
virtual SNES getSNES()=0
void setInitialResidual(Real r)
Record the initial residual (for later relative convergence check)
virtual libMesh::System & system() override
Get the reference to the libMesh system.
const Parallel::Communicator & comm() const
T & set(const std::string &)
Parameters parameters
void indentMessage(const std::string &prefix, std::string &message, const char *color, bool indent_first_line, const std::string &post_prefix)
Definition MooseUtils.C:801