https://mooseframework.inl.gov
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/equation_systems.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 {
49  EquationSystems & es = _fe_problem.es();
50 
51  es.parameters.set<unsigned int>("nonlinear solver maximum iterations") =
52  getSharedExecutionerParam<unsigned int>("nl_max_its");
53  es.parameters.set<unsigned int>("nonlinear solver maximum function evaluations") =
54  getSharedExecutionerParam<unsigned int>("nl_max_funcs");
55  es.parameters.set<Real>("nonlinear solver absolute residual tolerance") =
56  getSharedExecutionerParam<Real>("nl_abs_tol");
57  es.parameters.set<Real>("nonlinear solver relative residual tolerance") =
58  getSharedExecutionerParam<Real>("nl_rel_tol");
59  es.parameters.set<Real>("nonlinear solver divergence tolerance") =
60  getSharedExecutionerParam<Real>("nl_div_tol");
61  es.parameters.set<Real>("nonlinear solver absolute step tolerance") =
62  getSharedExecutionerParam<Real>("nl_abs_step_tol");
63  es.parameters.set<Real>("nonlinear solver relative step tolerance") =
64  getSharedExecutionerParam<Real>("nl_rel_step_tol");
65 }
66 
67 void
69 {
71 
73  mooseError("DefaultNonlinearConvergence can only be used with nonlinear solves.");
74 }
75 
78 {
80 }
81 
82 bool
84  const Real fnorm,
85  const Real ref_norm,
86  const Real rel_tol,
87  const Real abs_tol,
88  std::ostringstream & oss)
89 {
90  if (fnorm < abs_tol)
91  {
92  oss << "Converged due to absolute residual " << fnorm << " < absolute tolerance (" << abs_tol
93  << ")\n";
94  return true;
95  }
96  else if (n_iter && fnorm <= ref_norm * rel_tol)
97  {
98  oss << "Converged due to relative/normalized residual norm " << fnorm / ref_norm
99  << " < relative tolerance (" << rel_tol << ")\n";
100  return true;
101  }
102  else
103  return false;
104 }
105 
108 {
109  TIME_SECTION(_perfid_check_convergence);
110 
113 
114  SNES snes = system.getSNES();
115 
116  // ||u||
117  PetscReal xnorm;
118  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetSolutionNorm(snes, &xnorm));
119 
120  // ||r||
121  PetscReal fnorm;
122  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetFunctionNorm(snes, &fnorm));
123 
124  // ||du||
125  PetscReal snorm;
126  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetUpdateNorm(snes, &snorm));
127 
128  // Get current number of function evaluations done by SNES
129  PetscInt nfuncs;
130  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetNumberFunctionEvals(snes, &nfuncs));
131 
132  // Get tolerances from SNES
133  PetscReal rel_step_tol;
134  PetscInt max_its, max_funcs;
135  LibmeshPetscCallA(
136  _fe_problem.comm().get(),
137  SNESGetTolerances(snes, &_abs_tol, &_rel_tol, &rel_step_tol, &max_its, &max_funcs));
138 
139 #if !PETSC_VERSION_LESS_THAN(3, 8, 4)
140  PetscBool force_iteration = PETSC_FALSE;
141  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetForceIteration(snes, &force_iteration));
142 
143  // if PETSc says to force iteration, then force at least one iteration
144  if (force_iteration && !(_nl_forced_its))
145  _nl_forced_its = 1;
146 
147  // if specified here to force iteration, but PETSc doesn't know, tell it
148  if (!force_iteration && (_nl_forced_its))
149  {
150  LibmeshPetscCallA(_fe_problem.comm().get(), SNESSetForceIteration(snes, PETSC_TRUE));
151  }
152 #endif
153 
154  // See if SNESSetFunctionDomainError() has been called.
155  // Note: SNESSetFunctionDomainError() and SNESGetFunctionDomainError() were added
156  // in different releases of PETSc. The latter was removed in PETSc 3.25.0.
157 #if PETSC_VERSION_LESS_THAN(3, 25, 0)
158  PetscBool domainerror;
159  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetFunctionDomainError(snes, &domainerror));
160  if (domainerror)
162 #else
163  SNESConvergedReason reason;
164  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetConvergedReason(snes, &reason));
165  if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
167 #endif
168 
169  // Needed by ResidualReferenceConvergence
171 
172  Real fnorm_old;
173  // This is the first residual before any iterations have been done, but after
174  // solution-modifying objects (if any) have been imposed on the solution vector.
175  // We save it, and use it to detect convergence if system.usePreSMOResidual() == false.
176  if (n_iter == 0)
177  {
178  system.setInitialResidual(fnorm);
179  fnorm_old = fnorm;
181  }
182  else
183  fnorm_old = system._last_nl_rnorm;
184 
185  // Check for nonlinear residual ping-pong.
186  // Ping-pong will always start from a residual increase
187  if ((_nl_current_pingpong % 2 == 1 && !(fnorm > fnorm_old)) ||
188  (_nl_current_pingpong % 2 == 0 && fnorm > fnorm_old))
190  else
192 
193  const auto ref_residual = system.referenceResidual();
194  std::ostringstream oss;
195  if (n_iter < _nl_forced_its)
196  oss << "Number of forced iterations not yet reached: " << n_iter << " < " << _nl_forced_its
197  << '\n';
198  else if (fnorm != fnorm)
199  {
200  oss << "Failed to converge, residual norm is NaN\n";
202  }
203  else if (checkResidualConvergence(n_iter, fnorm, ref_residual, _rel_tol, _abs_tol, oss))
205  else if (nfuncs >= max_funcs)
206  {
207  oss << "Exceeded maximum number of residual evaluations: " << nfuncs << " > " << max_funcs
208  << '\n';
210  }
211  else if ((n_iter >= _nl_forced_its) && n_iter && fnorm > system._last_nl_rnorm &&
212  fnorm >= _div_threshold)
213  {
214  oss << "Nonlinear solve was blowing up!\n";
216  }
217  else if (snorm < rel_step_tol * xnorm)
218  {
219  oss << "Converged due to small update length: " << snorm << " < " << rel_step_tol << " * "
220  << xnorm << '\n';
222  }
223  else if (_nl_rel_div_tol > 0 && fnorm > ref_residual * _nl_rel_div_tol)
224  {
225  oss << "Diverged due to relative residual " << ref_residual << " > divergence tolerance "
226  << _nl_rel_div_tol << " * relative residual " << ref_residual << '\n';
228  }
229  else if (_nl_abs_div_tol > 0 && fnorm > _nl_abs_div_tol)
230  {
231  oss << "Diverged due to residual " << fnorm << " > absolute divergence tolerance "
232  << _nl_abs_div_tol << '\n';
234  }
236  {
237  oss << "Diverged due to maximum nonlinear residual pingpong achieved" << '\n';
239  }
240 
241  system._last_nl_rnorm = fnorm;
242  system._current_nl_its = static_cast<unsigned int>(n_iter);
243 
244  std::string msg;
245  msg = oss.str();
246  if (_app.multiAppLevel() > 0)
248  if (msg.length() > 0)
249 #if !PETSC_VERSION_LESS_THAN(3, 17, 0)
250  LibmeshPetscCallA(_fe_problem.comm().get(), PetscInfo(snes, "%s", msg.c_str()));
251 #else
252  LibmeshPetscCallA(_fe_problem.comm().get(), PetscInfo(snes, msg.c_str()));
253 #endif
254 
255  verboseOutput(oss);
256 
257  return status;
258 }
registerMooseObject("MooseApp", DefaultNonlinearConvergence)
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.
virtual void nonlinearConvergenceSetup()
Performs setup necessary for each call to checkConvergence.
PetscReal _abs_tol
Nonlinear absolute tolerance.
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...
virtual SNES getSNES()=0
virtual MooseConvergenceStatus checkConvergence(unsigned int n_iter) override
Returns convergence status.
const Real _nl_rel_div_tol
Nonlinear relative divergence tolerance.
Base class for default convergence criteria.
DefaultNonlinearConvergence(const InputParameters &parameters)
virtual NonlinearSystemBase & nonlinearSystem()
Nonlinear system whose convergence state should be checked.
unsigned int multiAppLevel() const
The MultiApp Level.
Definition: MooseApp.h:855
void verboseOutput(std::ostringstream &oss)
Outputs the stream to the console if verbose output is enabled.
Definition: Convergence.C:51
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
const Real _nl_abs_div_tol
Nonlinear absolute divergence tolerance.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
auto max(const L &left, const R &right)
const unsigned int _nl_max_pingpong
Maximum number of nonlinear ping-pong iterations for a solve.
Nonlinear system to be solved.
MPI_Status status
void indentMessage(const std::string &prefix, std::string &message, const char *color, bool indent_first_line, const std::string &post_prefix)
Definition: MooseUtils.C:749
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:103
Real referenceResidual() const
The reference residual used in relative convergence check.
NonlinearSystemBase & currentNonlinearSystem()
virtual libMesh::EquationSystems & es() override
static InputParameters feProblemDefaultConvergenceParams()
virtual void checkIterationType(IterationType) const
Perform checks related to the iteration type.
Definition: Convergence.h:48
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:375
MooseConvergenceStatus
Status returned by calls to checkConvergence.
Definition: Convergence.h:33
PerfID _perfid_check_convergence
Performance ID for checkConvergence.
Definition: Convergence.h:80
static InputParameters validParams()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _nl_current_pingpong
Current number of nonlinear ping-pong iterations for the current solve.
Class for containing MooseEnum item information.
Definition: MooseEnumItem.h:18
T & set(const std::string &)
void setInitialResidual(Real r)
Record the initial residual (for later relative convergence check)
unsigned int _nl_forced_its
Number of iterations to force.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:271
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...
const Real _div_threshold
Divergence threshold value.
Default nonlinear convergence criteria for FEProblem.
void ErrorVector unsigned int
static InputParameters validParams()
virtual void checkIterationType(IterationType it_type) const override
Perform checks related to the iteration type.
PetscReal _rel_tol
Nonlinear relative tolerance.