Skip to content

Commit

Permalink
more cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuahansel committed Oct 14, 2024
1 parent d5ed50d commit fef1637
Show file tree
Hide file tree
Showing 31 changed files with 336 additions and 217 deletions.
12 changes: 12 additions & 0 deletions framework/doc/content/bib/moose.bib
Original file line number Diff line number Diff line change
Expand Up @@ -609,3 +609,15 @@ @article{liu2015finite
year={2015},
publisher={Taylor \& Francis}
}

@article{rao2018stopping,
title = {A stopping criterion for the iterative solution of partial differential equations},
journal = {Journal of Computational Physics},
volume = {352},
pages = {265-284},
year = {2018},
issn = {0021-9991},
doi = {https://doi.org/10.1016/j.jcp.2017.09.033},
url = {https://www.sciencedirect.com/science/article/pii/S0021999117306939},
author = {Kaustubh Rao and Paul Malan and J. Blair Perot}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# IterationCountConvergence

This [Convergence](Convergence/index.md) specifies:

- $\ell_\text{max}$, the maximum number of iterations,
via [!param](/Convergence/IterationCountConvergence/max_iterations), and
- $\ell_\text{min}$, the minimum number of iterations,
via [!param](/Convergence/IterationCountConvergence/min_iterations).

If [!param](/Convergence/IterationCountConvergence/converge_at_max_iterations)
is set to `true`, then the solve will converge when $\ell = \ell_\text{max}$
instead of diverge.

Other `Convergence` objects may inherit from this class and override
`checkConvergenceInner(iter)` instead of the usual `checkConvergence(iter)`,
to inherit the iteration bounds. An example is [/PostprocessorConvergence.md].

!syntax parameters /Convergence/IterationCountConvergence

!syntax inputs /Convergence/IterationCountConvergence

!syntax children /Convergence/IterationCountConvergence
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# PostprocessorConvergence

This [Convergence](Convergence/index.md) derives from [/IterationCountConvergence.md]
and compares a [Postprocessor](Postprocessors/index.md) value $y$ to a tolerance $\tau$:

!equation
y \leq \tau \,.

For this to work as expected, the `execute_on` parameter of the post-processor
must include values that trigger execution before the desired check. For example, for nonlinear
convergence, the value `NONLINEAR_CONVERGENCE` should be used.

Typically the post-processor used should attempt to approximate the error in a system,
such as [/AverageVariableChange.md].

!syntax parameters /Convergence/PostprocessorConvergence

!syntax inputs /Convergence/PostprocessorConvergence

!syntax children /Convergence/PostprocessorConvergence
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# ReferenceResidualConvergence

This object uses a reference residual for computing relative convergence criteria.
The `ReferenceResidualConvergence` object facilitates the assesment of convergence properties of MOOSE applications and allows extensions to provide the user more control over the application behaviour. This convergence object replaces [ReferenceResidualProblem.md], and as such the capabilities are similar to `ReferenceResidualProblem`.

## Description

See [ReferenceResidualProblem.md]. Similar input as the one used in the `[Problem]` block can now be prescribed in the `[Convergence]` block as below

!listing test/tests/convergence/reference_residual/reference_residual.i block=Convergence
This [Convergence](Convergence/index.md) is a [/ResidualConvergence.md] with a
customized reference residual for its relative convergence checks. See
[ReferenceResidualProblem.md] for more information.

!syntax parameters /Convergence/ReferenceResidualConvergence

Expand Down
70 changes: 45 additions & 25 deletions framework/doc/content/source/convergence/ResidualConvergence.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,64 @@
# ResidualConvergence

By default, MOOSE checks convergence using relative and absolute criteria. Once the residual drops
below either an absolute tolerance or the residual divided by the initial residual for the current
timestep drops below a relative tolerance, the solution is considered converged.
This [Convergence](Convergence/index.md) uses a combination of criteria to
determine convergence, focused on the residual vector.

### +Solver convergence criteria parameters+
Consider the system of algebraic equations:

Parameters for setting absolute convergence, relative convergence etc. are usually set in the `Executioner` block. However, now they can also prescribed in the `Convergence` block.
!equation
\mathbf{r}(\mathbf{u}) = \mathbf{0} \,.

We shall provide a few guidelines for setting convergence parameters. In the following presume we have a partial differential equation, given as
$\mathcal{P}(\mathbf u)=f$, and subsequent residual $\mathcal R(\mathbf u)=\mathcal P(\mathbf u)-f=0$. Convergence with respect to a tolerance $\tau$, implies $|\mathcal R (\mathbf u)|<\tau$, while divergence is encountered when the residual cannot decrease below the value of $\tau$.
This class reports convergence of the solution to this system if
any of the following conditions are true:

If we consider an iterative process to determine the solution $\mathbf u$, we have a set of intermediary solutions $\mathbf u_i$ required to verify the equation $\mathcal R(\mathbf u)\approx 0$, but do not meet the required tolerance $\tau$.
!equation
\|\mathbf{r}\|_2 < \tau_\text{abs} \,,

#### 1. Absolute and relative tolerances
!equation
\frac{\|\mathbf{r}\|_2}{\|\mathbf{r}_0\|_2} > \tau_\text{rel} \,,

- +Absolute Tolerance (`abs_tol`)+: This is a parameter that determines the threshold at which the residual norm of the solution is deemed small enough in absolute terms. For a system of equation this translates into $|\mathbf u_{i+1}-\mathbf u_i|<\tau$.

- +Relative Tolerance (`rel_tol`)+: This parameter sets the threshold for the residual norm in relation to the norm of the right-hand side of the equation. For a system of equation this translates into $|\mathbf u_{i+1}-\mathbf u_i|/|\mathbf u_{i+1}|<\tau$.
!equation
\frac{\|\mathbf{\delta u}\|_2}{\|\mathbf{u}\|_2} < \tau_{\delta u,\text{rel}} \,.

This class reports divergence if any of the following conditions are true:

Considering that nonlinear systems are ultimately solved via linearization the user should append `l_` for linear systems, or `nl_` for nonlinear ones, on a per case base.
!equation
\|\mathbf{r}\|_2 = \text{NaN} \,,

#### 2. Choosing appropiate `abs_tol` and `rel_tol`
!equation
n_\text{evals} \geq n_\text{evals,max} \,,

- To start, apply the same values for both `abs_tol` and `rel_tol` in both preconditioned and non-preconditioned systems. This allows for a straightforward comparison under similar stopping criteria.
- +Preconditioning+ aims to improve the numerical properties of an iterative solver (specifically the condition number). This often results in the preconditioned system converging more quickly or requiring fewer iterations. However, preconditioning modifies the scale and the properties of the problem, which can affect the scale of the residuals.
- The user must make sure that `abs_tol` and `rel_tol` are set in a manner that mirrors the +scaling+ of the problem. If preconditioning significantly changes the scale (which is often the case), the user needs to adjust these tolerances to accommodate the changes.
- The user should +experiment+ with different settings of `abs_tol` and `rel_tol` to observe their effect on convergence and the quality of the solution. To make a fair comparison, one should ensure that the solver’s behavior (in terms of convergence and accuracy) is similar under both settings.
!equation
\|\mathbf{r}\|_2 > \tau_\text{div,abs} \,,

#### Other stopping criteria
!equation
\frac{\|\mathbf{r}\|_2}{\|\mathbf{r}_0\|_2} > \tau_\text{div,rel} \,,

Presuming the user gathered enough knowledge about the solver behaviour and the nature of the problem, addtional stopping requirements can be added, such as `nl_max_its` which instructs after how many iterations to abort the solver, or `nl_abs_step_tol`, which indicates what tolerance to be accepted at each solver step.
!equation
n_\text{ping} > n_\text{ping,max} \,,

## Example input syntax
where

!listing test/tests/convergence/residual_convergence/diffusion_convergence.i block=Convergence

!listing test/tests/convergence/residual_convergence/diffusion_convergence.i block=Executioner
where the [!param](/Executioner/nonlinear_convergence) indicates the convergence type to be `ResidualConvergence` and additional parameters. Curently convergence specific parameters can be still specified in the Executioner block.
- $\|\cdot\|_2$ is the discrete $L_2$ norm,
- $\mathbf{r}_0$ is the initial (guess) residual vector,
- $\mathbf{\delta u} = \mathbf{u}^{(\ell)} - \mathbf{u}^{(\ell-1)}$ is the solution step vector,
- "NaN" is a not-a-number value,
- $\tau_\text{abs}$ is the absolute residual tolerance, provided by
[!param](/Convergence/ResidualConvergence/nl_abs_tol).
- $\tau_\text{rel}$ is the relative residual tolerance, provided by
[!param](/Convergence/ResidualConvergence/nl_rel_tol).
- $\tau_{\delta u,\text{abs}}$ is the relative step tolerance., provided by
[!param](/Convergence/ResidualConvergence/nl_rel_step_tol).
- $\tau_\text{div,abs}$ is the absolute residual divergence tolerance, provided by
[!param](/Convergence/ResidualConvergence/nl_abs_div_tol).
- $\tau_\text{div,rel}$ is the relative residual divergence tolerance, provided by
[!param](/Convergence/ResidualConvergence/nl_div_tol).
- $n_\text{evals}$ is the number of residual evaluations.
- $n_\text{evals,max}$ is the maximum number of residual evaluations, provided by
[!param](/Convergence/ResidualConvergence/nl_max_funcs).
- $n_\text{ping}$ is the number of ping-pong iterations.
- $n_\text{ping,max}$ is the maximum number of ping-pong iterations, provided by
[!param](/Convergence/ResidualConvergence/n_max_nonlinear_pingpong).

!syntax parameters /Convergence/ResidualConvergence

Expand Down
136 changes: 121 additions & 15 deletions framework/doc/content/syntax/Convergence/index.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,130 @@
# Convergence system
# Convergence System

The Convergence system provides the infrastructure for creating MOOSE objects that interact with the
solvers to give the user more control over the application behaviour.
The Convergence system allows users to customize the stopping criteria for the
iteration in various solves:

## Description
- Nonlinear system solves
- Linear system solves (not yet implemented)
- Steady-state detection in [Transient.md] (not yet implemented)
- Fixed point solves (not yet implemented)

By default, MOOSE checks convergence using relative and absolute criteria. Once the residual drops
below either an absolute tolerance, or the residual divided by the initial residual for the current
time step drops below a relative tolerance, the solution is considered converged. This works well for
many problems, but there are some scenarios that are problematic, where the user may desire
interaction with the solver at runtime for better control or analysis.
Instead of supplying convergence-related parameters directly to the executioner,
the user creates `Convergence` objects whose names are then supplied to the
executioner, e.g.,

Currently this object supports algebraic two types of convergence
[/ResidualConvergence.md] and
[ReferenceResidualConvergence.md].
```
[Convergence]
[my_convergence1]
type = MyCustomConvergenceClass
# some convergence parameters, like tolerances
[]
[]
### +Methods supported+
[Executioner]
type = Steady
nonlinear_convergence = my_convergence1
[]
```

- [/ResidualConvergence.md] tracks the residual decay across iterations. This MOOSE object interfaces directly with the PETSc callback function at each iteration and allows the user to prescribe additional requirements and tests which can be performed at every iteration step.
Currently only the nonlinear solve convergence is supported, but others are planned
for the near future.

- [ReferenceResidualConvergence.md] uses a user-specified reference vector for convergence checks, instead of the initial residual. This is beneficial when solution variables have different scaling. Convergence is achieved when the $L_2$ norm of each solution variable’s residual is less than either the relative tolerance times the $L_2$ norm of the corresponding reference variable or the absolute tolerance. As this method computes relative convergence differently, the required nonlinear relative tolerance to achieve the same error can vary from the default approach in MOOSE. Users must ensure appropriate tolerances are used.
## Available Classes

The `Convergence` classes provided by MOOSE are the following:

- [/ResidualConvergence.md]: The default convergence criteria, which includes
several convergence criteria combined together.
- [/ReferenceResidualConvergence.md]: Like `ResidualConvergence`, but
uses a custom norm to define the relative residual convergence criteria.
[/ReferenceResidualProblem.md] uses this as its convergence criteria.
- [/IterationCountConvergence.md]: Specifies minimum and maximum numbers of iterations.
- [/PostprocessorConvergence.md]: Compares the value of a
[Postprocessor](Postprocessors/index.md) to a tolerance.

## Convergence Criteria Design Considerations

Here we provide some considerations to make in designing convergence criteria
and choosing appropriate parameter values.
Consider a system of algebraic system of equations

!equation
\mathbf{r}(\mathbf{u}) = \mathbf{0} \,,

where $\mathbf{u}$ is the unknown solution vector, and $\mathbf{r}$ is the residual
function. To solve this system using an iterative method, we must decide on
criteria to stop the iteration.
In general, iteration for a solve should halt when the approximate solution $\tilde{\mathbf{u}}$
has reached a satisfactory level of error $\mathbf{e} \equiv \tilde{\mathbf{u}} - \mathbf{u}$,
using a condition such as

!equation id=error_criteria
\|\mathbf{e}\| \leq \tau_u \,,

where $\|\cdot\|$ denotes some norm, and $\tau_u$ denotes some tolerance.
Unfortunately, since we do not know $\mathbf{u}$, the error $\mathbf{e}$ is
also unknown and thus may not be computed directly. Thus some approximation of
the condition [!eqref](error_criteria) must be made. This may entail some
approximation of the error $\mathbf{e}$ or some criteria which implies the
desired criteria. For example, a very common approach is to use a residual
criteria such as

!equation
\|\mathbf{r}\| \leq \tau_{r,\text{abs}} \,.

While it is true that $\|\mathbf{r}\| = 0$ implies $\|\mathbf{e}\| = 0$, a
zero-tolerance is impractical, and the translation between the tolerance
$\tau_u$ to the tolerance is $\tau_r$ is difficult. The "acceptable" absolute
residual tolerance is tricky to determine and is highly dependent on the
equations being solved. To attempt to circumvent this issue, relative residual
criteria have been used, dividing the residual norm by another value in an
attempt to normalize it. A common approach that has been used is to use the
initial residual vector $\mathbf{r}_0$ to normalize:

!equation
\frac{\|\mathbf{r}\|}{\|\mathbf{r}_0\|} \leq \tau_{r,\text{rel}} \,,

where $\tau_{r,\text{rel}}$ is the relative residual tolerance. The disadvantage
with this particular choice is that this is highly dependent on how good the
initial guess is: if the initial guess is very good, it will be nearly impossible
to converge to the tolerance, and if the initial guess is very bad, it will be
too easy to converge to the tolerance, resulting in an erroneous solution.

Some other considerations are the following:

- Consider round-off error: if error ever reaches values around round-off error,
the solve should definitely be considered converged, as iterating further
provides no benefit.
- Consider the other sources of error in the model that produced the system of
algebraic equations that you're solving. For example, if solving a system of
partial differential equations, consider the model error and the discretization
error; it is not beneficial to require algebraic error less than the other
sources of error.
- Since each convergence criteria typically has some weak point where they break
down, it is usually advisable to use a combination of criteria.

For more information on convergence criteria, see [!cite](rao2018stopping) for
example.

!alert tip title=Create your own convergence action
The `Convergence` system provides a lot of flexibility by providing several
pieces that can be combined together to create a desired set of convergence
criteria. Since this may involve a large number of objects (including objects
from other systems), it may be beneficial to create an [Action](/Action.md)
to create more compact and convenient syntax for your application.

## Implementing a New Convergence Class

`Convergence` objects are responsible for overriding the virtual method

```
MooseConvergenceStatus checkConvergence(unsigned int iter)
```

The returned type `MooseConvergenceStatus` is one of the following values:

- `CONVERGED`: The system has converged.
- `DIVERGED`: The system has diverged.
- `ITERATING`: The system has neither converged nor diverged and thus will
continue to iterate.

8 changes: 7 additions & 1 deletion framework/include/convergence/Convergence.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include "PostprocessorInterface.h"
#include "PerfGraphInterface.h"

class FEProblemBase;

/**
* Base class for convergence criteria.
*/
Expand Down Expand Up @@ -47,5 +49,9 @@ class Convergence : public MooseObject,
virtual MooseConvergenceStatus checkConvergence(unsigned int iter) = 0;

protected:
PerfID _perf_check_convergence;
/// FE problem
FEProblemBase & _fe_problem_base;

/// Performance ID for \c checkConvergence
PerfID _perfid_check_convergence;
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class ReferenceResidualConvergence : public ResidualConvergence, public Referenc
{
public:
static InputParameters validParams();
static InputParameters validCommonReferenceResidualProblemParams();

ReferenceResidualConvergence(const InputParameters & parameters);

Expand Down
13 changes: 3 additions & 10 deletions framework/include/interfaces/ReferenceResidualInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,15 @@ class InputParameters;
class MooseObject;

/**
* The ReferenceResidualInterface class is designed to provide an interface for
* the ReferenceConvergence class, and allow access to parameters shared by other classes.
* Interface class shared between ReferenceResidualProblem and ReferenceResidualConvergence.
*/

InputParameters validParams();

class ReferenceResidualInterface
{
public:
ReferenceResidualInterface(const MooseObject * moose_object);
virtual ~ReferenceResidualInterface();

static InputParameters validParams();

ReferenceResidualInterface(const MooseObject * moose_object);

/**
* Add a set of variables that need to be grouped together. For use in
* actions that create variables. This is templated for backwards compatibility to allow passing
Expand All @@ -40,8 +35,6 @@ class ReferenceResidualInterface
void addGroupVariables(const std::set<T> & group_vars);

protected:
const InputParameters & _fi_params;

/// Name of variables that are grouped together to check convergence
std::vector<std::vector<NonlinearVariableName>> _group_variables;

Expand Down
4 changes: 4 additions & 0 deletions framework/include/problems/FEProblemBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -2205,7 +2205,11 @@ class FEProblemBase : public SubProblem, public Restartable
_set_nonlinear_convergence_name = true;
}

/**
* Gets the nonlinear convergence object name if there is one
*/
ConvergenceName getNonlinearConvergenceName() const { return _nonlinear_convergence_name; }

/**
* Setter for whether we're computing the scaling jacobian
*/
Expand Down
Loading

0 comments on commit fef1637

Please sign in to comment.