Skip to main content
`Ctrl`+`K`

# SNESConvergedReason

reason a `SNESSolve()` was determined to have converged or diverged

## Synopsis

    typedef enum {                       /* converged */
      SNES_CONVERGED_FNORM_ABS      = 2, /* ||F|| < atol */
      SNES_CONVERGED_FNORM_RELATIVE = 3, /* ||F|| < rtol*||F_initial|| */
      SNES_CONVERGED_SNORM_RELATIVE = 4, /* Newton computed step size small; || delta x || < stol || x || */
      SNES_CONVERGED_ITS            = 5, /* maximum iterations reached */
      SNES_BREAKOUT_INNER_ITER      = 6, /* Flag to break out of inner loop after checking custom convergence, used in multi-phase flow when state changes */
      SNES_CONVERGED_USER           = 7, /* The user has indicated convergence for an arbitrary reason */
      /* diverged */
      SNES_DIVERGED_FUNCTION_DOMAIN      = -1, /* the new x location passed the function is not in the domain of F */
      SNES_DIVERGED_FUNCTION_COUNT       = -2,
      SNES_DIVERGED_LINEAR_SOLVE         = -3, /* the linear solve failed */
      SNES_DIVERGED_FUNCTION_NANORINF    = -4,
      SNES_DIVERGED_FNORM_NAN_DEPRECATED = -4,
      SNES_DIVERGED_MAX_IT               = -5,
      SNES_DIVERGED_LINE_SEARCH          = -6,  /* the line search failed */
      SNES_DIVERGED_INNER                = -7,  /* inner solve failed */
      SNES_DIVERGED_LOCAL_MIN            = -8,  /* || J^T b || is small, implies converged to local minimum of F() */
      SNES_DIVERGED_DTOL                 = -9,  /* || F || > divtol*||F_initial|| */
      SNES_DIVERGED_JACOBIAN_DOMAIN      = -10, /* Jacobian calculation does not make sense */
      SNES_DIVERGED_TR_DELTA             = -11,
      SNES_CONVERGED_TR_DELTA_DEPRECATED = -11,
      SNES_DIVERGED_USER                 = -12, /* The user has indicated divergence for an arbitrary reason */
      SNES_DIVERGED_OBJECTIVE_DOMAIN     = -13,
      SNES_DIVERGED_OBJECTIVE_NANORINF   = -14,

      SNES_CONVERGED_ITERATING = 0
    } SNESConvergedReason;

## Values

- `SNES_CONVERGED_FNORM_ABS` - \( ||F|| \le abstol \)

- `SNES_CONVERGED_FNORM_RELATIVE` - \( ||F|| <= rtol*||F(x_0))|| \) where \(x_0 \) is the initial guess

- `SNES_CONVERGED_SNORM_RELATIVE` - The 2-norm of the last step \( \le stol * ||x|| \) where \( x \) is the current solution

- `SNES_CONVERGED_USER` - The user has indicated convergence for an arbitrary reason

- `SNES_DIVERGED_FUNCTION_COUNT` - The user provided function has been called more times than the maximum set in `SNESSetTolerances()`

- `SNES_DIVERGED_DTOL` - The norm of the function has increased by a factor of divtol set with `SNESSetDivergenceTolerance()`

- `SNES_DIVERGED_FUNCTION_NANORINF` - the 2-norm of the current function evaluation is not-a-number (NaN) or infinity, (this is usually caused by a division of 0 by 0) and the solver could not recover from this (by, for example, cutting the step size)

- `SNES_DIVERGED_OBJECTIVE_NANORINF` - the object function evaluation is not-a-number (NaN) or infinity, (this is usually caused by a division of 0 by 0) and the solver could not recover from this (by, for example, cutting the step size)

- `SNES_DIVERGED_FUNCTION_DOMAIN` - the function evaluation occurred outside the function’s domain (function callback provided by `SNESSetFunction()` called `SNESSetObjectiveDomainError()`) and the solver could not recover from this (by, for example, cutting the step size)

- `SNES_DIVERGED_OBJECTIVE_DOMAIN` - the object function evaluation occurred outside the function’s domain (function callback provided by `SNESSetObjective()` called `SNESSetObjectiveDomainError()`) and the solver could not recover from this (by, for example, cutting the step size)

- `SNES_DIVERGED_JACOBIAN_DOMAIN` - the Jacobian evaluation occurred outside the function’s domain (function callback provided by `SNESSetJacobian()` called `SNESSetJacobianDomainError()`)

- `SNES_DIVERGED_MAX_IT` - `SNESSolve()` has reached the maximum number of iterations requested

- `SNES_DIVERGED_LINE_SEARCH` - The line search has failed. This only occurs for `SNES` solvers that use a line search

- `SNES_DIVERGED_LOCAL_MIN` - the algorithm seems to have stagnated at a local minimum that is not zero.

- ***`SNES_CONVERGED_ITERATING -*** this only occurs if` SNESGetConvergedReason()`is called during the`SNESSolve()`

## Notes

The two most common reasons for divergence are an incorrectly coded or computed Jacobian or failure or lack of convergence in the linear system (in this case we recommend testing with `-pc_type lu` to eliminate the linear solver as the cause of the problem).

`SNES_DIVERGED_LOCAL_MIN` can only occur when using a `SNES` solver that uses a line search (`SNESLineSearch`). The line search wants to \( \min Q(\alpha) = 1/2 || F(x + \alpha s) ||^2_2 \) this occurs at \( Q'(\alpha) = s^T F'(x+\alpha s)^T F(x+\alpha s) = 0\). If \(s\) is the Newton direction \( - F'(x)^(-1)F(x)\) then \( Q'(\alpha) = -F(x)^T F'(x)^(-1)^T F'(x+\alpha s)F(x+\alpha s)\); when \(\alpha = 0\) \(Q'(0) = - ||F(x)||^2_2 \) which is always NEGATIVE if \(F'(x)\) is invertible. This means the Newton direction is a descent direction and the line search should succeed if \(\alpha \) is small enough.

If \(F'(x)\) is NOT invertible AND \(F'(x)^T F(x) = 0 \) then \(Q'(0) = 0 \) and the Newton direction is NOT a descent direction so the line search will fail. All one can do at this point is change the initial guess and try again.

An alternative explanation: Newton’s method can be regarded as replacing the function with its linear approximation and minimizing the 2-norm of that. That is \(F(x+s) \approx F(x) + F'(x)s\) so we minimize \( || F(x) + F'(x) s ||^2_2\) using Least Squares. If \(F'(x)\) is invertible then \(s = - F'(x)^(-1)F(x)\) otherwise \(F'(x)^T F'(x) s = -F'(x)^T F(x)\). If \(F'(x)^T F(x)\) is NOT zero then there exists a nontrivial (that is \(F'(x)s \ne 0\)) solution to the equation and this direction is \(s = - [F'(x)^T F'(x)]^(-1) F'(x)^T F(x)\) so \(Q'(0) = - F(x)^T F'(x) [F'(x)^T F'(x)]^(-T) F'(x)^T F(x) = - (F'(x)^T F(x)) [F'(x)^T F'(x)]^(-T) (F'(x)^T F(x))\). Since we are assuming \((F'(x)^T F(x)) \ne 0\) and \(F'(x)^T F'(x)\) has no negative eigenvalues \(Q'(0) < 0\) so \(s\) is a descent direction and the line search should succeed for small enough \(\alpha\).

Note that this RARELY happens in practice. Far more likely the linear system is not being solved (well enough?) or the Jacobian is wrong.

`SNES_DIVERGED_MAX_IT` means that the solver reached the maximum number of iterations without satisfying any convergence criteria. `SNES_CONVERGED_ITS` means that `SNESConvergedSkip()` was chosen as the convergence test; thus the usual convergence criteria have not been checked and may or may not be satisfied.

## See Also

SNES: Nonlinear Solvers, `SNES`, `SNESSolve()`, `SNESGetConvergedReason()`, `KSPConvergedReason`, `SNESSetConvergenceTest()`, `SNESSetTolerances()`

## Level

beginner

## Location

include/petscsnes.h

## Examples

src/snes/tutorials/ex48.c
src/snes/tutorials/ex5f.F90
src/ts/tutorials/ex48.c
src/snes/tutorials/ex42.c
src/snes/tutorials/ex2.c
src/ts/tutorials/ex14.c
src/snes/tutorials/ex15.c
src/snes/tutorials/ex30.c
src/snes/tutorials/ex6.c
src/snes/tutorials/ex69.c

Index of all SNES routines
Table of Contents for all manual pages
Index of all manual pages