Solvers#
Solvers drive the implicit update at the heart of a rate-form constitutive
model. When a model has no closed form — the state at the end of a step depends
on itself — it is written as a residual \(r(u, g) = 0\) (unknowns \(u\), given
inputs \(g\)), wrapped in an ImplicitUpdate, and handed to a solver
that finds the root. This page is the conceptual map of the available solvers
and when to reach for each; the [Solvers] catalog is the
canonical per-type option list (every field, its meaning, its default).
Two kinds compose:
a nonlinear solver runs the outer Newton iteration over \(r(u) = 0\);
a linear solver solves the linear system in each Newton step (\(J\,\Delta u = -r\), where \(J = \partial r / \partial u\)). The nonlinear solver names it through its
linear_solverfield.
Nonlinear solvers#
Newton — Newton–Raphson. Each iteration assembles the residual and its Jacobian and takes one linear solve; it stops when the relative or absolute residual norm falls below
rel_tol/abs_tol, or errors atmax_its. SetNEML2_LOGS=newton=info(or=debugfor the per-iteration convergence history); see Controlling verbosity. This is the default choice.NewtonWithLineSearch — Newton with a globalized step. When the full Newton step overshoots (stiff or far-from-solution problems), a line search (
BACKTRACKINGorSTRONG_WOLFE) scales it back to guarantee residual decrease. Reach for it when plain Newton stalls or diverges; it inherits everyNewtonoption and adds thelinesearch_*controls.
Linear solvers#
Each Newton step solves \(J\,\Delta u = -r\). The choice trades assembly + factorization cost against per-iteration cost.
Direct — assemble \(J\) and factorize it:
DenseLU — a dense LU solve of a single-group system. The default, and the right choice for the common small dense update (e.g. a \(6\times6\) stress return).
SchurComplement — a block factorization for a two-group system (one
BLOCK+ oneDENSEgroup, e.g. crystal plasticity’s per-grain state coupled to a global unknown). It inverts the primary block and solves the Schur complement, each with its own nested linear solver (primary_solver/schur_solver).
Matrix-free iterative — never assemble \(J\); apply \(J\,v\) directly:
GMRES / BiCGStab — Krylov solvers that reach the solution through a handful of Jacobian-vector products. For the large, well-conditioned systems of implicit backward-Euler updates, a few matvecs beat an \(O(N^3)\) dense factorization, and the win grows with system size and on GPU.
GMRESkeeps a restart window (restart); both takemax_its/abs_tol/rel_tol. The inner tolerance can be loose — the outer Newton re-solves each step, so an inexact inner solve still converges.
Preconditioners#
An iterative linear solver may take a preconditioner \(M^{-1} \approx J^{-1}\)
that clusters the spectrum and cuts the iteration count. Each is an authored
[Solvers] object referenced by GMRES / BiCGStab:
NoPreconditioner (the default), JacobiPreconditioner,
BlockJacobiPreconditioner, and FullPreconditioner.
The cache_strategy field governs how often the preconditioner is rebuilt
across Newton iterations — none (every step), chord (build once, reuse), or
max_its (rebuild when a solve exceeds cache_max_its iterations).
Derivative (sensitivity) solvers#
Differentiating through the converged solve uses the implicit function theorem,
which needs its own linear solves: \(\partial u/\partial g = -J^{-1}\,\partial
r/\partial g\) (inputs) and \(\partial u/\partial \theta = -J^{-1}\,\partial
r/\partial \theta\) (parameters). ImplicitUpdate exposes these as
input_sensitivity_solver and param_sensitivity_solver. Both default to a
direct solve — so derivatives stay exact regardless of the forward solver — and
either can be set to an iterative solver to trade exactness for speed on large
systems.
Wiring it together#
A solver is assembled from the objects it references. A Newton names its
linear_solver; an iterative linear solver may name a preconditioner; an
ImplicitUpdate names the Newton (and, optionally, distinct sensitivity
solvers):
[Solvers]
[newton]
type = Newton
linear_solver = 'gmres'
[]
[gmres]
type = GMRES
preconditioner = 'bjac'
cache_strategy = 'chord'
[]
[bjac]
type = BlockJacobiPreconditioner
[]
[]
[Models]
[model]
type = ImplicitUpdate
equation_system = 'eq_sys'
solver = 'newton'
[]
[]
See also#
The
[Solvers]catalog — the exhaustive per-type option reference (fields, meanings, defaults).Implicit models — a worked implicit update, from residual to Newton solve to differentiating through it.
Compilation pipeline — how the direct and iterative solves are lowered when a model is compiled with
neml2-compile.