GlobalDiffEq: Global Error Estimation and Control
Standard adaptive ODE solvers control the local error of each step. The local tolerances only indirectly control the global (accumulated) error of the solution, which can grow arbitrarily large over long integrations or on unstable problems even when every step satisfies its local tolerance. The GlobalDiffEq sublibrary provides solvers and solver wrappers that estimate the global error, and in several cases control it to a requested global tolerance.
To use these methods:
using GlobalDiffEqThe global-error-estimating solvers GLEE24, GLEE35 (Constantinescu 2016), and the Dormand-Prince-based MM5GEE (Makazaga and Murua 2003) carry a running, asymptotically correct estimate of the solution's global error at every time point, at the cost of a few extra stages per step. They report it through the standard SciMLBase global-error interface: solving returns an ordinary solution (sol.u and sol(t) are the solution), with the estimate in sol.global_error — sol.global_error[i] is the estimated global error of sol.u[i] at sol.t[i], and SciMLBase.has_global_error is true for these algorithms. global_error_estimate returns sol.global_error.
GlobalErrorEstimation wraps any adaptive solver with global error estimation and gtol-based control by integrating a defect-driven companion equation. Two orthogonal choices configure it: GlobalErrorEquation selects the companion ODE — the nonlinear DefectCorrection (no Jacobian) or the linearized ErrorTransport (matrix-free Jacobian-vector products) — and GlobalErrorMode selects how it is integrated — InterpolatingMode (store the dense solution, integrate the companion in a second pass) or SimultaneousMode (advance the companion inline over each step for O(1) extra memory and no second solve). global_error_estimate(prob, alg) exposes the standalone estimator.
To control the endpoint global error to a tolerance gtol, wrap any adaptive solver in GlobalAdjoint (adjoint-based, for endpoint functionals; requires SciMLSensitivity to be loaded); adjoint_error_estimate exposes the standalone estimator. Its GlobalAdjointScope selects whether the estimate is reported only at the endpoint (EndpointError) or along the whole trajectory (TrajectoryError, filling sol.global_error at every saved time), and its GlobalAdjointControl selects whether gtol is met by tolerance tightening (ToleranceRefinement) or by re-solving non-adaptively on the accepted step grid (StepGridRefinement).
GlobalRichardson wraps any fixed-step method in global Richardson extrapolation over whole solves, interpreting abstol and reltol as global tolerances. It is the most robust and most expensive option.
For example, solving while tracking the global error along the trajectory:
using GlobalDiffEq
function lorenz!(du, u, p, t)
du[1] = 10.0(u[2] - u[1])
du[2] = u[1] * (28.0 - u[3]) - u[2]
du[3] = u[1] * u[2] - (8 / 3) * u[3]
return
end
prob = ODEProblem(lorenz!, [1.0; 0.0; 0.0], (0.0, 10.0))
sol = solve(prob, GLEE35(); abstol = 1.0e-8, reltol = 1.0e-8)
errs = global_error_estimate(sol) # global error estimate at every sol.tGlobal-error-estimating solvers
GlobalDiffEq.GLEE23 — Type
GLEE23()3-stage, second-order explicit general linear method with global error estimation (Constantinescu 2016, eq. (4.6); PETSc's TSGLEE23). The cheapest GLEE method: only the first decoupling condition holds, so prefer GLEE24 for long-time integration or mildly stiff problems.
GLEE methods propagate the solution y together with an asymptotically correct estimate ε of its global (accumulated) error, at the cost of a few extra stages per step. Solving any ODEProblem with a GLEE method returns an ordinary solution — sol.u[i] is the solution at sol.t[i] and sol(t) interpolates it at full order — with the global error estimate reported through the standard SciMLBase interface: SciMLBase.has_global_error is true, and sol.global_error[i] is the estimated global error of sol.u[i] (also available as global_error_estimate(sol)). The per-step increment of ε is an asymptotically correct local error estimate, which drives standard step-size adaptivity, so local tolerances behave exactly as for ordinary adaptive Runge-Kutta methods while the global error is estimated for free.
Only explicit, mass-matrix-free ODEs are supported. The reference for the methods and their theory is:
Emil M. Constantinescu, Estimating Global Errors in Time Stepping, SIAM Journal on Numerical Analysis 54(6), 2016. arXiv:1503.05166
GlobalDiffEq.GLEE24 — Type
GLEE24()4-stage, second-order explicit general linear method with global error estimation (Constantinescu 2016, eq. (A.3); PETSc's TSGLEE24). Satisfies both decoupling conditions (B·U and B·A·U diagonal), which keeps the error estimate faithful in long-time integration; this is the recommended second-order GLEE method.
GLEE methods propagate the solution y together with an asymptotically correct estimate ε of its global (accumulated) error, at the cost of a few extra stages per step. Solving any ODEProblem with a GLEE method returns an ordinary solution — sol.u[i] is the solution at sol.t[i] and sol(t) interpolates it at full order — with the global error estimate reported through the standard SciMLBase interface: SciMLBase.has_global_error is true, and sol.global_error[i] is the estimated global error of sol.u[i] (also available as global_error_estimate(sol)). The per-step increment of ε is an asymptotically correct local error estimate, which drives standard step-size adaptivity, so local tolerances behave exactly as for ordinary adaptive Runge-Kutta methods while the global error is estimated for free.
Only explicit, mass-matrix-free ODEs are supported. The reference for the methods and their theory is:
Emil M. Constantinescu, Estimating Global Errors in Time Stepping, SIAM Journal on Numerical Analysis 54(6), 2016. arXiv:1503.05166
GlobalDiffEq.GLEE35 — Type
GLEE35()5-stage, third-order explicit general linear method with global error estimation (Constantinescu 2016, eq. (4.9); PETSc's TSGLEE35). Satisfies both decoupling conditions and has a large negative-real-axis stability region; this is the recommended third-order GLEE method.
GLEE methods propagate the solution y together with an asymptotically correct estimate ε of its global (accumulated) error, at the cost of a few extra stages per step. Solving any ODEProblem with a GLEE method returns an ordinary solution — sol.u[i] is the solution at sol.t[i] and sol(t) interpolates it at full order — with the global error estimate reported through the standard SciMLBase interface: SciMLBase.has_global_error is true, and sol.global_error[i] is the estimated global error of sol.u[i] (also available as global_error_estimate(sol)). The per-step increment of ε is an asymptotically correct local error estimate, which drives standard step-size adaptivity, so local tolerances behave exactly as for ordinary adaptive Runge-Kutta methods while the global error is estimated for free.
Only explicit, mass-matrix-free ODEs are supported. The reference for the methods and their theory is:
Emil M. Constantinescu, Estimating Global Errors in Time Stepping, SIAM Journal on Numerical Analysis 54(6), 2016. arXiv:1503.05166
GlobalDiffEq.MM5GEE — Type
MM5GEE()Fifth-order Dormand-Prince-based scheme with cheap global error estimation (Makazaga and Murua, BIT Numerical Mathematics 43, 2003). Propagates the standard DOPRI5 solution together with an order-6 companion solution through three extra stages (9 function evaluations per step in total), whose difference is an asymptotically correct global error estimate. This is the recommended method of the Runge-Kutta triple family of Dormand, Duckers and Prince, as it is the coefficient-complete published scheme of that type.
GLEE methods propagate the solution y together with an asymptotically correct estimate ε of its global (accumulated) error, at the cost of a few extra stages per step. Solving any ODEProblem with a GLEE method returns an ordinary solution — sol.u[i] is the solution at sol.t[i] and sol(t) interpolates it at full order — with the global error estimate reported through the standard SciMLBase interface: SciMLBase.has_global_error is true, and sol.global_error[i] is the estimated global error of sol.u[i] (also available as global_error_estimate(sol)). The per-step increment of ε is an asymptotically correct local error estimate, which drives standard step-size adaptivity, so local tolerances behave exactly as for ordinary adaptive Runge-Kutta methods while the global error is estimated for free.
Only explicit, mass-matrix-free ODEs are supported. The reference for the methods and their theory is:
Emil M. Constantinescu, Estimating Global Errors in Time Stepping, SIAM Journal on Numerical Analysis 54(6), 2016. arXiv:1503.05166
- J. Makazaga and A. Murua, New Runge-Kutta based schemes for ODEs with cheap global error estimation, BIT Numerical Mathematics 43 (2003).
GlobalDiffEq.global_error_estimate — Function
global_error_estimate(prob, alg::GlobalErrorEstimation; abstol=1e-6, reltol=1e-3, kwargs...)Solve an ODE problem and estimate the 2-norm of its global error at the final time using the companion equation selected by alg.equation and integrated in the mode selected by alg.mode. abstol and reltol control the forward solve; companion_abstol and companion_reltol control the companion error solve.
global_error_estimate(sol)
global_error_estimate(sol, i)Extract the global error estimate from a solution computed with a GLEE method (GLEE23, GLEE24, GLEE35, MM5GEE).
These solvers report the global error through the standard SciMLBase interface: sol.global_error is a vector matching sol.u, with sol.global_error[i] the estimated global error of sol.u[i] at sol.t[i] (see SciMLBase.has_global_error). global_error_estimate(sol) returns that vector and global_error_estimate(sol, i) its i-th element.
Global error controlling wrappers
GlobalDiffEq.GlobalRichardson — Type
GlobalRichardson(alg)Wrap an ODE algorithm with global Richardson extrapolation.
GlobalDiffEq.GlobalErrorEstimation — Type
GlobalErrorEstimation(alg; equation=DefectCorrection, mode=InterpolatingMode,
companion_alg=alg, autodiff=ADTypes.AutoForwardDiff(),
gtol=nothing, maxiters=6, safety=0.8,
companion_abstol, companion_reltol)Wrap an ODE algorithm with global error estimation and control based on a defect-driven companion equation. After a dense forward solve producing the interpolant P(t), the global error ε(t) ≈ y(t) - P(t) is estimated by integrating a companion ODE driven by the dense-output defect d(t) = f(P(t), p, t) - P'(t), with ε(t₀) = 0.
Two orthogonal choices control the estimator:
equation (GlobalErrorEquation) selects the companion ODE:
DefectCorrection(default): the nonlinear correctionε' = f(P + ε, p, t) - P'(t), requiring no Jacobian.ErrorTransport: the linearized transportε' = J(P, p, t) ε + d(t), withJ = ∂f/∂uapplied matrix-free as a Jacobian-vector product throughautodiff(anyADTypesbackend supported by DifferentiationInterface).ErrorTransportis the first-order linearization ofDefectCorrection.
mode (GlobalErrorMode) selects how the companion is integrated:
InterpolatingMode(default): run the forward solve with dense output andsave_everystep, keep it, and integrate the companion against its interpolant in a second solve. Solver-agnostic butO(n_steps)memory.SimultaneousMode: drive the forward integrator one accepted step at a time and advance the companion across each step using that step's live dense output, storing no dense solution (O(1)extra memory) and running no second solve. Its estimate closely agrees withInterpolatingMode.
Set the requested absolute endpoint error with gtol:
solve(prob, GlobalErrorEstimation(Tsit5(); gtol = 1.0e-6))The solver then tightens local tolerances until the estimated endpoint global error 2-norm is at most gtol. Omit gtol when using the algorithm only with global_error_estimate. companion_alg selects the solver for the companion equation, and companion_abstol / companion_reltol control its tolerances.
Every combination requires the wrapped solver to provide a genuine dense first-derivative interpolation (a solver with only the trivial fallback interpolation is rejected). This implementation supports forward-time, standard-mass-matrix ODEs with real vector states and no callbacks.
References
- P. E. Zadunaisky, On the estimation of errors propagated in the numerical integration of ordinary differential equations, Numerische Mathematik 27 (1976).
- J. R. Dormand, R. R. Duckers and P. J. Prince, Global error estimation with Runge-Kutta methods, IMA Journal of Numerical Analysis 4 (1984).
- L. F. Shampine, Global error estimation with one-step methods, Computers & Mathematics with Applications 12A (1986).
- J. Lang and J. Verwer, On global error estimation and control for initial value problems, SIAM Journal on Scientific Computing 29 (2007).
GlobalDiffEq.GlobalErrorEquation — Type
GlobalErrorEquationWhich companion ODE GlobalErrorEstimation integrates for the global error. One of DefectCorrection or ErrorTransport.
GlobalDiffEq.DefectCorrection — Constant
DefectCorrectionIntegrate the nonlinear correction equation ε' = f(P + ε, p, t) - P'(t), ε(t₀) = 0, where P is the numerical solution's dense interpolant. Requires no Jacobian, only extra evaluations of f on the perturbed argument P + ε. The "solving for the correction" technique of Zadunaisky (1976) and Dormand, Duckers and Prince (1984).
GlobalDiffEq.ErrorTransport — Constant
ErrorTransportIntegrate the linearized error-transport (first variational) equation ε' = J(P, p, t) ε + d(t), ε(t₀) = 0, where d(t) = f(P, p, t) - P'(t) is the dense-output defect and J = ∂f/∂u is applied matrix-free as a Jacobian-vector product (via autodiff). The error-transport approach of Shampine (1986) and Berzins (1988). It is the first-order linearization of DefectCorrection.
GlobalDiffEq.GlobalErrorMode — Type
GlobalErrorModeHow GlobalErrorEstimation integrates the companion ODE. One of InterpolatingMode or SimultaneousMode.
GlobalDiffEq.InterpolatingMode — Constant
InterpolatingModeRun the forward solve with dense output and save_everystep, keep that dense solution, and integrate the companion ODE against its interpolant in a second solve. Solver-agnostic, but stores the whole dense solution (O(n_steps) memory) and runs a second solve.
GlobalDiffEq.SimultaneousMode — Constant
SimultaneousModeCo-integrate the error estimate in a single forward pass: drive the forward integrator one accepted step at a time and, over each just-completed step, advance the companion ODE using that step's live dense output as the interpolant. Stores no dense solution (O(1) extra memory) and runs no second solve. Gives an estimate closely agreeing with InterpolatingMode.
GlobalDiffEq.GlobalAdjoint — Type
GlobalAdjoint(alg; gtol=nothing, adjoint_alg=alg, sensealg=nothing, samples=2,
rng=Random.default_rng(), scope=EndpointError,
control=ToleranceRefinement, maxiters=6, safety=0.8,
adjoint_abstol, adjoint_reltol)Wrap an ODE algorithm with adjoint-based global error estimation and control. Set the requested absolute endpoint error with the gtol constructor keyword:
using SciMLSensitivity
solve(prob, GlobalAdjoint(Tsit5(); gtol = 1.0e-6))The algorithm solves the ODE with local tolerances, estimates the 2-norm of the endpoint error using samples orthogonal random projections, and tightens the local tolerances until the estimate is at most gtol. The estimate is probabilistic for systems with more than one state; the default of two samples is accurate within a factor of ten with probability greater than 99% under the small-sample estimate in Cao and Petzold (2004).
The estimate is a dual-weighted residual: for a projection direction v, the error component ⟨v, y(T) - P(T)⟩ equals ∫ λ(t)ᵀ (f(P(t)) - P'(t)) dt, where P is the dense numerical solution, d(t) = f(P) - P' its defect, and λ the adjoint with terminal condition λ(T) = v. This is computed by the adjoint system itself (via SciMLSensitivity.adjoint_sensitivities), not by a hand-rolled quadrature: the defect is introduced as a scalar forcing whose sensitivity is exactly that integral.
When solved with a gtol, the returned solution carries the estimate in its global_error field (SciMLBase.has_global_error is true for GlobalAdjoint). scope (GlobalAdjointScope) selects what is estimated: EndpointError (default) fills only sol.global_error[end], while TrajectoryError fills sol.global_error[i] at every saved time. control (GlobalAdjointControl) selects how gtol is met: ToleranceRefinement (default) tightens tolerances and re-solves adaptively, while StepGridRefinement re-solves non-adaptively on the accepted step grid. Control always targets the endpoint error estimate.
Omit gtol when using the algorithm only with adjoint_error_estimate. maxiters limits the number of forward-solve refinements, while safety controls each local-tolerance reduction. The adjoint_abstol and adjoint_reltol constructor keywords control the reverse-time adjoint solves.
The adjoint machinery lives in a package extension: SciMLSensitivity must be loaded to solve with GlobalAdjoint. sensealg selects the adjoint sensitivity algorithm and is passed straight through to SciMLSensitivity.adjoint_sensitivities: any adjoint method works, and the default (nothing) defers to that function's own default. adjoint_alg selects the solver for the reverse-time adjoint problems.
This implementation supports forward-time, standard-mass-matrix ODEs with real vector states. The wrapped solver must provide a dense first-derivative interpolation.
References
- Y. Cao and L. Petzold, A posteriori error estimation and global error control for ordinary differential equations by the adjoint method, SIAM Journal on Scientific Computing 26 (2004).
GlobalDiffEq.adjoint_error_estimate — Function
adjoint_error_estimate(prob, alg::GlobalAdjoint; abstol=1e-6, reltol=1e-3, kwargs...)Solve an ODE problem and estimate the 2-norm of its global error at the final time. The estimate evaluates the dense interpolation defect and projects it through reverse-time adjoints constructed by SciMLSensitivity, which must be loaded to enable the implementation.
abstol and reltol control the forward solve. adjoint_abstol and adjoint_reltol control the reverse-time adjoint solves. The random directions come from alg.rng; their number is alg.samples, capped at the state dimension.
GlobalDiffEq.GlobalAdjointScope — Type
GlobalAdjointScopeWhat GlobalAdjoint estimates and reports in sol.global_error. One of EndpointError or TrajectoryError.
GlobalDiffEq.EndpointError — Constant
EndpointErrorEstimate the global error 2-norm only at the final time: sol.global_error[end] holds it and earlier entries are zero. The default; one adjoint solve per sample.
GlobalDiffEq.TrajectoryError — Constant
TrajectoryErrorEstimate the global error 2-norm at every saved time: sol.global_error[i] is the estimate at sol.t[i] (sol.global_error[1] = 0), filled along the whole trajectory. Costs one reverse-adjoint solve per saved time per sample, and the returned solution is dense and saved at every solver step.
GlobalDiffEq.GlobalAdjointControl — Type
GlobalAdjointControlHow GlobalAdjoint drives the solve to meet gtol. One of ToleranceRefinement or StepGridRefinement.
GlobalDiffEq.ToleranceRefinement — Constant
ToleranceRefinementTighten the solver's local abstol/reltol and re-solve adaptively until the estimated endpoint error is at most gtol. The default.
GlobalDiffEq.StepGridRefinement — Constant
StepGridRefinementTighten tolerances the same way to find a step grid that meets gtol, then return a solution obtained by re-solving non-adaptively on exactly that grid (adaptive = false, stepping on the adjoint-informed dts). Yields a reproducible fixed-step schedule rather than an adaptive solve.