Incremental 4DVar is the operational fast path for strong-constraint 4DVar. Rather than minimising the full nonlinear cost directly, it solves a sequence of linearised quadratic subproblems — a Gauss–Newton outer loop — each preconditioned by a control-variable transform Courtier et al., 1994Lorenc, 1997. It returns the same analysis as strong-constraint 4DVar, far faster.
The pattern is exactly 3DVar’s Gauss–Newton loop generalised to a time window: each inner problem is a linear-Gaussian (BLUE) analysis through the linearised dynamics.
The Outer / Inner Decomposition¶
Start from the strong-constraint cost. Linearising the dynamics and observations around the current outer iterate ,
gives a quadratic increment cost in ,
where is the innovation at the current iterate. The minimiser solves the Gauss–Newton normal equations
after which the outer update relinearises and repeats.
Convergence is typically 3–5 outer iterations, largely independent of the strength of the nonlinearity.
Control-Variable Transform (CVT)¶
The condition number of inherits the eigenvalue spread of the prior , which for a Matérn covariance on a 2D grid can span hundreds of orders of magnitude — crippling CG without preconditioning. The CVT changes variables to a whitened control,
so the prior term becomes and the Hessian becomes
The square root comes from a structured covariance operator
(e.g. a Matérn .half()); for non-structured priors, factorise via Cholesky
(small grids) or Lanczos (large grids).
Implementation¶
A generic outer/inner loop: linearise the windowed observation map with
jax.linearize, then solve the CVT-preconditioned normal equations with CG.
import jax
from jax.scipy.sparse.linalg import cg
from jaxtyping import Array, Float
def incremental_4dvar(
ub: Float[Array, "N"], # background / initial outer iterate
ys: Float[Array, "T M"], # observations over the window
G, # windowed obs map u0 -> {H_t(M_t(u0))} : (N,) -> (T, M)
apply_R_inv, # (T, M) -> (T, M), block-diagonal R⁻¹ over time
B_half, # χ -> B^{1/2} χ (structured square root, symmetric)
*, n_outer: int = 3, n_inner: int = 20,
) -> Float[Array, "N"]:
u = ub
for _ in range(n_outer):
# 1. linearise the windowed observation map at the current iterate
Gu, G_lin = jax.linearize(G, u) # Gu = G(u) (T,M); G_lin(v) = G'(u) v
G_adj = jax.linear_transpose(G_lin, u) # (G')ᵀ
d = ys - Gu # innovations (T, M)
# 2. CVT-preconditioned Gauss–Newton solve in χ-space:
# (I + B^{1/2} G'ᵀ R⁻¹ G' B^{1/2}) χ = B^{1/2} G'ᵀ R⁻¹ d
def hessian(chi: Float[Array, "N"]) -> Float[Array, "N"]:
v = B_half(chi)
return chi + B_half(G_adj(apply_R_inv(G_lin(v)))[0])
rhs = B_half(G_adj(apply_R_inv(d))[0])
chi, _ = cg(hessian, rhs, maxiter=n_inner)
# 3. outer update: δu = B^{1/2} χ
u = u + B_half(chi)
return uTypical knobs: n_outer ≈ 3 (Gauss–Newton outer iterations), n_inner ≈ 20–50
(CG steps per outer), plus CG tolerances and a cvt on/off switch.
Why It Is the Operational Fast Path¶
Three multiplicative speedups over running a generic nonlinear minimiser on the full strong-constraint cost:
CG converges in iterations instead of — the prior condition number no longer drives the cost. See (5).
The tangent-linear is computed once per outer iteration and reused across all inner CG steps. A nonlinear minimiser on the full cost recomputes the gradient — a full forward and adjoint pass — at every step.
The Gauss–Newton Hessian assembled in the last outer iteration is reused for the Laplace posterior covariance — no separate Krylov pass. Strong-constraint 4DVar needs a fresh one.
For a representative operational problem ( h, grid points, observations), incremental 4DVar converges in minutes where a generic nonlinear solver on the same cost takes hours.
Limiting Case and Scope¶
Strong vs. weak constraint. Incremental 4DVar is strong-constraint by default. The strong/weak choice is structural (does the control include ?); the inner-solver choice (generic vs. incremental) is performance. For weak-constraint problems the incremental machinery over the augmented control is heavier and not always worth it.
When to prefer strong-constraint 4DVar instead — almost never operationally, but:
the prior is exotic (no structured ), so CVT preconditioning is unavailable;
you want a custom minimiser (e.g. Levenberg–Marquardt for very nonlinear cases) rather than the fixed Gauss–Newton + CG.
For most uses, incremental 4DVar is the right default Bannister, 2017.
- Courtier, P., Thépaut, J.-N., & Hollingsworth, A. (1994). A Strategy for Operational Implementation of 4D-Var, Using an Incremental Approach. Quarterly Journal of the Royal Meteorological Society, 120(519), 1367–1387. 10.1002/qj.49712051912
- Lorenc, A. C. (1997). Development of an Operational Variational Assimilation Scheme. Journal of the Meteorological Society of Japan, 75(1B), 339–346. 10.2151/jmsj1965.75.1B_339
- Bannister, R. N. (2017). A Review of Operational Methods of Variational and Ensemble-Variational Data Assimilation. Quarterly Journal of the Royal Meteorological Society, 143(703), 607–633. 10.1002/qj.2982