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 
76 bool
78  const Real fnorm,
79  const Real ref_norm,
80  const Real rel_tol,
81  const Real abs_tol,
82  std::ostringstream & oss)
83 {
84  if (fnorm < abs_tol)
85  {
86  oss << "Converged due to absolute residual " << fnorm << " < absolute tolerance (" << abs_tol
87  << ")\n";
88  return true;
89  }
90  else if (iter && fnorm <= ref_norm * rel_tol)
91  {
92  oss << "Converged due to relative/normalized residual norm " << fnorm / ref_norm
93  << " < relative tolerance (" << rel_tol << ")\n";
94  return true;
95  }
96  else
97  return false;
98 }
99 
102 {
103  TIME_SECTION(_perfid_check_convergence);
104 
107 
108  SNES snes = system.getSNES();
109 
110  // ||u||
111  PetscReal xnorm;
112  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetSolutionNorm(snes, &xnorm));
113 
114  // ||r||
115  PetscReal fnorm;
116  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetFunctionNorm(snes, &fnorm));
117 
118  // ||du||
119  PetscReal snorm;
120  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetUpdateNorm(snes, &snorm));
121 
122  // Get current number of function evaluations done by SNES
123  PetscInt nfuncs;
124  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetNumberFunctionEvals(snes, &nfuncs));
125 
126  // Get tolerances from SNES
127  PetscReal rel_step_tol;
128  PetscInt max_its, max_funcs;
129  LibmeshPetscCallA(
130  _fe_problem.comm().get(),
131  SNESGetTolerances(snes, &_abs_tol, &_rel_tol, &rel_step_tol, &max_its, &max_funcs));
132 
133 #if !PETSC_VERSION_LESS_THAN(3, 8, 4)
134  PetscBool force_iteration = PETSC_FALSE;
135  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetForceIteration(snes, &force_iteration));
136 
137  // if PETSc says to force iteration, then force at least one iteration
138  if (force_iteration && !(_nl_forced_its))
139  _nl_forced_its = 1;
140 
141  // if specified here to force iteration, but PETSc doesn't know, tell it
142  if (!force_iteration && (_nl_forced_its))
143  {
144  LibmeshPetscCallA(_fe_problem.comm().get(), SNESSetForceIteration(snes, PETSC_TRUE));
145  }
146 #endif
147 
148  // See if SNESSetFunctionDomainError() has been called.
149  // Note: SNESSetFunctionDomainError() and SNESGetFunctionDomainError() were added
150  // in different releases of PETSc. The latter was removed in PETSc 3.25.0.
151 #if PETSC_VERSION_LESS_THAN(3, 25, 0)
152  PetscBool domainerror;
153  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetFunctionDomainError(snes, &domainerror));
154  if (domainerror)
156 #else
157  SNESConvergedReason reason;
158  LibmeshPetscCallA(_fe_problem.comm().get(), SNESGetConvergedReason(snes, &reason));
159  if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
161 #endif
162 
163  // Needed by ResidualReferenceConvergence
165 
166  Real fnorm_old;
167  // This is the first residual before any iterations have been done, but after
168  // solution-modifying objects (if any) have been imposed on the solution vector.
169  // We save it, and use it to detect convergence if system.usePreSMOResidual() == false.
170  if (iter == 0)
171  {
172  system.setInitialResidual(fnorm);
173  fnorm_old = fnorm;
175  }
176  else
177  fnorm_old = system._last_nl_rnorm;
178 
179  // Check for nonlinear residual ping-pong.
180  // Ping-pong will always start from a residual increase
181  if ((_nl_current_pingpong % 2 == 1 && !(fnorm > fnorm_old)) ||
182  (_nl_current_pingpong % 2 == 0 && fnorm > fnorm_old))
184  else
186 
187  const auto ref_residual = system.referenceResidual();
188  std::ostringstream oss;
189  if (iter < _nl_forced_its)
190  oss << "Number of forced iterations not yet reached: " << iter << " < " << _nl_forced_its
191  << '\n';
192  else if (fnorm != fnorm)
193  {
194  oss << "Failed to converge, residual norm is NaN\n";
196  }
197  else if (checkResidualConvergence(iter, fnorm, ref_residual, _rel_tol, _abs_tol, oss))
199  else if (nfuncs >= max_funcs)
200  {
201  oss << "Exceeded maximum number of residual evaluations: " << nfuncs << " > " << max_funcs
202  << '\n';
204  }
205  else if ((iter >= _nl_forced_its) && iter && fnorm > system._last_nl_rnorm &&
206  fnorm >= _div_threshold)
207  {
208  oss << "Nonlinear solve was blowing up!\n";
210  }
211  else if (snorm < rel_step_tol * xnorm)
212  {
213  oss << "Converged due to small update length: " << snorm << " < " << rel_step_tol << " * "
214  << xnorm << '\n';
216  }
217  else if (_nl_rel_div_tol > 0 && fnorm > ref_residual * _nl_rel_div_tol)
218  {
219  oss << "Diverged due to relative residual " << ref_residual << " > divergence tolerance "
220  << _nl_rel_div_tol << " * relative residual " << ref_residual << '\n';
222  }
223  else if (_nl_abs_div_tol > 0 && fnorm > _nl_abs_div_tol)
224  {
225  oss << "Diverged due to residual " << fnorm << " > absolute divergence tolerance "
226  << _nl_abs_div_tol << '\n';
228  }
230  {
231  oss << "Diverged due to maximum nonlinear residual pingpong achieved" << '\n';
233  }
234 
235  system._last_nl_rnorm = fnorm;
236  system._current_nl_its = static_cast<unsigned int>(iter);
237 
238  std::string msg;
239  msg = oss.str();
240  if (_app.multiAppLevel() > 0)
242  if (msg.length() > 0)
243 #if !PETSC_VERSION_LESS_THAN(3, 17, 0)
244  LibmeshPetscCallA(_fe_problem.comm().get(), PetscInfo(snes, "%s", msg.c_str()));
245 #else
246  LibmeshPetscCallA(_fe_problem.comm().get(), PetscInfo(snes, msg.c_str()));
247 #endif
248 
249  verboseOutput(oss);
250 
251  return status;
252 }
registerMooseObject("MooseApp", DefaultNonlinearConvergence)
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
const Real _nl_rel_div_tol
Nonlinear relative divergence tolerance.
Base class for default convergence criteria.
DefaultNonlinearConvergence(const InputParameters &parameters)
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
virtual MooseConvergenceStatus checkConvergence(unsigned int iter) override
Returns convergence status.
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:738
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:385
MooseConvergenceStatus
Status returned by calls to checkConvergence.
Definition: Convergence.h:33
PerfID _perfid_check_convergence
Performance ID for checkConvergence.
Definition: Convergence.h:77
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:281
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...
virtual bool checkResidualConvergence(const unsigned int 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.
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.