Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Tier III — Eulerian finite-volume transport

Forward model: full PDE solved on a grid. Uses finitevolX for spatial discretisation and spectraldiffx for spectral / periodic-domain operators.

This is the gold-standard physics tier: full mass conservation, arbitrary wind fields, support for chemistry and deposition. Also the most expensive — emulators (Step 3) are essential, not optional.


(1) Simple model

Conservation equation

Operational implementations carry mixing ratio cc (kg/kg), not mass density, because that’s what the satellite observes and what WRF couples to. The conservation form is then:

∂t(ρc)  +  ∇⋅(ρu c)  =  ∇⋅(ρK∇c)  +  S(x,t)  −  λ ρ c\partial_{t} (\rho c) \;+\; \nabla\cdot(\rho \mathbf{u}\, c) \;=\; \nabla\cdot(\rho \mathbf{K} \nabla c) \;+\; S(\mathbf{x},t) \;-\; \lambda\, \rho\, c

with ρ(x,t)\rho(\mathbf{x},t) the dry-air density from the met field. When ρ\rho is approximately constant over the integration window (typical at fixed altitude in a regional basin) this reduces to the textbook ∂tc+∇⋅(u c)=∇⋅(K∇c)+S−λc\partial_t c + \nabla\cdot(\mathbf{u}\, c) = \nabla\cdot(\mathbf{K}\nabla c) + S - \lambda c. Commit to the full ρ\rho-weighted form for any work crossing significant pressure-altitude variation.

Initial and boundary conditions

Both are load-bearing for inversion accuracy and currently underspecified in operational code:

Spatial / temporal discretisation

Cell-centred FV with flux-limited advection via finitevolX; explicit RK or IMEX for stiff diffusion; spectraldiffx for periodic / global domains.

Build order within Tier III

  1. 1D column model. Validates numerics — diffusion against analytical Gaussian, advection against cosine pulse / Burgers’.

  2. 2D horizontal slab. What most satellite work needs (vertical column already integrated by AK).

  3. Full 3D with vertical layers. Needed when injection altitude matters or when assimilating multi-layer in-situ data alongside columns.


(2) Model-based inference

Forward observation operator

Same column + AK pipeline as Tiers I and II:

yt  =  At colz ⁣(c(S,c0,t))  +  cbg  +  εt\mathbf{y}_t \;=\; \mathbf{A}_t\, \mathrm{col}_z\!\bigl(c(S, c_0, t)\bigr) \;+\; \mathbf{c}_\text{bg} \;+\; \boldsymbol{\varepsilon}_t

Ht≔At⋅colz(⋅)\mathbf{H}_t \coloneqq \mathbf{A}_t \cdot \mathrm{col}_z(\cdot) is the observation operator at time tt. The 4D-Var cost below uses Ht\mathbf{H}_t; the column + AK implementation is shared with Tier I and the prereqs.

4D-Var cost — three terms

J(S,c0)  =  12∥S−Sb∥B2  +  12∥c0−cb(0)∥Bc2  +  12∑t∥Ht c(S,c0,t)−yt∥Rt2J(S, c_0) \;=\; \tfrac{1}{2}\lVert S - S_b \rVert^{2}_{\mathbf{B}} \;+\; \tfrac{1}{2}\lVert c_0 - c_b(0) \rVert^{2}_{\mathbf{B}_c} \;+\; \tfrac{1}{2} \sum_{t} \lVert \mathbf{H}_t\, c(S, c_0, t) - \mathbf{y}_t \rVert^{2}_{\mathbf{R}_t}

Three terms — source background, IC background, and time-summed observation mismatch. The IC term drops out only if you commit to a long warm-up that pins c(0)c(0). Treating observations as a single instantaneous mismatch (no time index) is incompatible with multi-hour assimilation windows.

Likelihood model

εt∼N(0,Rt),Rt  =  Rretr,t+Rrepr,t\boldsymbol{\varepsilon}_t \sim \mathcal{N}(\mathbf{0}, \mathbf{R}_t), \qquad \mathbf{R}_t \;=\; \mathbf{R}_{\text{retr},t} + \mathbf{R}_{\text{repr},t}

Prior on SS — spatially correlated, sign-constrained

Same structure as Tier II:

Prior specification on the source field SS.

ChoiceFormNotes
Mean SbS_bfrom emission inventoryEDGAR / GFEI / EPA per-cell median
Covariance B\mathbf{B}Matérn-3/2, ℓ∈[5,50]\ell \in [5, 50] kmspatial regulariser; ℓ\ell tuneable or hierarchical
Positivitylog⁡S∼N(log⁡Sb,Blog⁡)\log S \sim \mathcal{N}(\log S_b, \mathbf{B}_{\log}) (lognormal)non-negative emissions; conjugate when linearised
BC scalingper-face α∼N(1,0.12)\alpha \sim \mathcal{N}(1, 0.1^{2})absorbs lateral-BC bias

Adjoint

The adjoint of the transport equation (backward in time, conservative form) is:

−∂tλ  −  ∇⋅(u λ)  −  ∇⋅(K∇λ)  +  λchem λ  =  ∂L∂c-\partial_{t} \lambda \;-\; \nabla\cdot(\mathbf{u}\, \lambda) \;-\; \nabla\cdot(\mathbf{K} \nabla \lambda) \;+\; \lambda_\text{chem}\, \lambda \;=\; \frac{\partial \mathcal{L}}{\partial c}

The ∇⋅(u λ)\nabla\cdot(\mathbf{u}\,\lambda) term is conservative (matches the forward ∇⋅(u c)\nabla\cdot(\mathbf{u}\,c)); the doc previously had u⋅∇λ\mathbf{u}\cdot\nabla\lambda, which is equivalent only for divergence-free u\mathbf{u} and is incorrect for compressible WRF winds. JAX computes the discretised adjoint exactly via reverse-mode autodiff through the FV solver — no hand-derived adjoint code, no separate adjoint-correctness derivation. The mathematical form above is for reading, not implementation.

Incremental 4D-Var (the operational default)

Linearise around the current iterate SkS^k, solve the linear inner minimisation, update outer iterate:

Sk+1  =  Sk+δS,δS  =  arg⁡min⁡δ Jlin(δ;Sk)S^{k+1} \;=\; S^k + \delta S, \qquad \delta S \;=\; \arg\min_{\delta} \, J_\text{lin}(\delta; S^k)

JlinJ_\text{lin} uses the tangent linear of the FV solver, trivially built via jax.linearize. Inner solves are quadratic in δS\delta S → CG or Lanczos via gaussx. Cuts cost by 1–2 orders of magnitude vs. fully-nonlinear 4D-Var. This is the default; full nonlinear is a sanity check.

Control-variable transform

Direct optimisation in SS-space with B−1\mathbf{B}^{-1} is infeasible — B\mathbf{B} for a 200×200200 \times 200 grid is 400002≈10940000^{2} \approx 10^{9} entries. Standard fix:

χ  =  B−1/2(S−Sb),optimise J(S(χ)) in χ-space (prior = identity Gaussian).\boldsymbol{\chi} \;=\; \mathbf{B}^{-1/2}(S - S_b), \qquad \text{optimise } J(S(\boldsymbol{\chi})) \text{ in } \boldsymbol{\chi}\text{-space (prior = identity Gaussian)}.

B−1/2\mathbf{B}^{-1/2} materialised via the structure-aware Cholesky in gaussx (Kronecker structure for separable correlation). gaussx has no covariance-kernel functions: the spatial Matérn matrix is built in plumax (matern32_covariance), while the temporal axis can use gaussx.MaternSDE + MarkovGaussian, the state-space Matérn with O(T)O(T) solves. This is the load-bearing trick that makes 4D-Var tractable; should be explicit in assimilation/control.py and on the API.

Posterior covariance — three options

4D-Var alone gives MAP; downstream Tier V needs the posterior:

The posterior export to Tier V.A is via the same adapter pattern as Tier I/II — see the posterior-export module.

Cost / performance

For a 200×200200 \times 200 grid, 24-hour assimilation window, with incremental 4D-Var: ~minutes per outer iteration on CPU, seconds on GPU. Inner CG iteration is O(niter×nsteps×ngrid)O(n_\text{iter} \times n_\text{steps} \times n_\text{grid}).


(3) Model emulator

Full 3D FV transport is expensive: O(N3)O(N^{3}) state, repeated time integration. Emulator is essential here, not optional like at Tier I.

State variable — commit to 2D column for v1

Most satellite inversion needs only the column-integrated XCH₄, not the 3D field. Default emulator state is 2D column ccol(x,y,t)c_\text{col}(x, y, t); full 3D is a v2 escalation when multi-layer in-situ assimilation enters scope. Order-of-magnitude difference in training cost.

Architecture options

Training data

Emulator adjoint must be calibrated

Backprop through a trained emulator gives some gradient — whether it matches the true PDE adjoint is empirical.


(4) Emulator-based inference

Replace the FV integrator with the FNO / neural ODE in the 4D-Var loop:


(5) Amortized inference (predictor)

fθ:(yt1,…,tn, u1:T, instrument_id)  ⟼  p(log⁡S(x,t)∣y,u)f_\theta : (\mathbf{y}_{t_1, \dots, t_n},\, \mathbf{u}_{1:T},\, \text{instrument\_id}) \;\longmapsto\; p(\log S(\mathbf{x},t) \mid \mathbf{y}, \mathbf{u})

Output grid commitment

S(x,t)S(\mathbf{x},t) is on the inversion grid (~1–10 km, basin-scoped). Predictor outputs a fixed-size 2D field per basin tile per time slice. Per-instrument predictor heads, dispatched by instrument_id — same pattern as Tier II.

Irregular temporal sampling

Satellite passes are intermittent (1–3 per day per instrument over a basin) with gaps. Input is not regularly sampled — t1,…,tnt_1, \dots, t_n are observation times, not a fixed grid. Architecture: set-transformer with time-encoding over irregular passes, fused with a regular-grid encoder over u1:T\mathbf{u}_{1:T} from the met field. Vanilla seq2seq / ConvLSTM assumes regular sampling and will silently underperform.

Posterior over the spatial source field

Conditional flow over images vs. score-based diffusion — same trade-off as Tier II:


(6) Improve


Module layout

Tier III module layout — step, concern, target module, status.

StepConcernModuleStatus
1FV gridles_fvm/grid.py✓
1Advectionles_fvm/advection.py✓
1Diffusionles_fvm/diffusion.py✓
1Source injectionles_fvm/source.py✓
1Boundary conditionsles_fvm/boundary.py✓
1Time integrationles_fvm/dynamics.py, simulate.py✓
1Eddy diffusivityles_fvm/diffusion.py (EddyDiffusivity, pg_eddy_diffusivity)🚧 PG ✓; MO + Smagorinsky ☐ #94
1Column + AK pipelinereuse gauss_plume.observation from Tier I☐ #83
24D-Var cost (prior + time-summed obs) over the FV transportles_fvm/fourdvar.py (FourDVarProblem)✓
2Differentiable forward (emission → column-obs series) + exact adjoint via ADles_fvm/fourdvar.py (EulerianForward4DVar)✓
2Column observation operator H_tles_fvm/fourdvar.py (ColumnObservationOperator)✓
2Likelihood + temporal prior on the emission series (Matérn-3/2, R = R_retr + R_repr)reuse lagrangian.inversion.matern32_covariance✓
2Spatial source prior (per-cell B)SpatialControl in fourdvar.py — v1 control is a scalar emission rate at a known source☐ #91
2Control vector + whitening transformles_fvm/fourdvar.py (Cholesky whitening of B)✓
24D-Var solver (L-BFGS in whitened space)les_fvm/fourdvar.py (solve_4dvar)✓
2Incremental (Gauss-Newton inner) 4D-Var solverassimilation/solve.py (run_gauss_newton, run_dual_psas exist; not wired to the FV forward)🚧 #93
2Background (SbS_b, cbc_b, BC scaling)assimilation/background.py (B builders exist; not in the 4D-Var cost)🚧 #92
2Diagnosticsassimilation/diagnostics.py🚧
2Posterior covariance (Hessian / Laplace / En4D-Var)les_fvm/fourdvar.py (posterior_covariance, laplace_sample)🚧 Gauss-Newton Laplace ✓; En4D-Var ☐
2Posterior export → Tier Vsamples / prior_logpdf on FourDVarResult☐ #107
3Emulator (UNet / GNN / FNO)plumax.les_fvm.emulator☐ #95
3Emulator-adjoint calibration harnessplumax.les_fvm.emulator_adjoint_test☐ #95
5Sequence predictor (set-transformer)plumax.les_fvm.predictor☐
6Multi-species couplingplumax.les_fvm.multispecies☐

Validation strategy


Open questions