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 I — Gaussian family

Forward model: closed-form analytical solution for steady/transient point-source dispersion.

This is the first tier to build to completion (all six steps), because:

  1. The forward model is microseconds, so MCMC is feasible end-to-end.

  2. Every downstream tier validates against Tier I in the limit of weak turbulence and stationary winds — Tier I is the analytical reference.

  3. The amortized predictor at Step 5 doubles as the working prototype for the inference UX (input/output shapes, posterior visualisation, uncertainty budget).


(1) Simple model

Gaussian plume (steady-state, continuous source)

c(x′,y′,z)  =  Q2π σy σz uˉexp⁡ ⁣(−y′22σy2)∑n ⁣[exp⁡ ⁣(−(z−Heff−2nL)22σz2)  +  exp⁡ ⁣(−(z+Heff−2nL)22σz2)]c(x',y',z) \;=\; \frac{Q}{2\pi \, \sigma_y \, \sigma_z \, \bar{u}} \exp\!\left(-\frac{y'^{2}}{2\sigma_y^{2}}\right) \sum_{n} \!\left[ \exp\!\left(-\frac{(z - H_\text{eff} - 2nL)^{2}}{2\sigma_z^{2}}\right) \;+\; \exp\!\left(-\frac{(z + H_\text{eff} - 2nL)^{2}}{2\sigma_z^{2}}\right) \right]

The primed coordinates (x′,y′)(x', y') are the source-aligned frame: x′x' is downwind along θwind\theta_\text{wind}, y′y' is crosswind. The image-source sum runs over n∈{…,−1,0,1,… }n \in \{\dots,-1, 0, 1, \dots\} to enforce no-flux at the ground (z=0z=0) and at the capping inversion (z=L=PBL heightz=L = \text{PBL height}). For L→∞L \to \infty only the n=0n=0 pair survives — that’s the unbounded-domain case in most textbooks. For typical PBL L≈1 kmL \approx 1\,\text{km} and σz\sigma_z growing past ∼L/3\sim L/3, the upper image is non-negligible.

Parameters:

For methane super-emitter inversions where stack height is poorly known, HeffH_\text{eff} is part of what you infer; for known facilities HstackH_\text{stack} is fixed and only Δh\Delta h is computed.

Gaussian puff (time-varying, episodic source)

c(x,t)  =  ∑kQk(2π)3/2σ3exp⁡ ⁣(−∥x−xk(t)∥22σ2)c(\mathbf{x}, t) \;=\; \sum_{k} \frac{Q_k}{(2\pi)^{3/2} \sigma^{3}} \exp\!\left(-\frac{\lVert \mathbf{x} - \mathbf{x}_k(t) \rVert^{2}}{2\sigma^{2}}\right)

Each puff kk advects with the wind and diffuses independently — handles intermittent / burst-mode releases that violate the steady-state assumption.

From c(x,y,z)c(x,y,z) to a satellite-comparable observation

The forward used by inference is not c(x,y,z)c(x,y,z) directly. It’s:

ymodel(x,y)  =  A (∫c(x,y,z) dz  +  cbg(x,y))y_\text{model}(x,y) \;=\; \mathbf{A}\,\bigl(\textstyle\int c(x,y,z)\,\mathrm{d}z \;+\; c_\text{bg}(x,y)\bigr)

Extended Gaussian (AERMOD-style)

Adds terrain corrections (plume rise over hills, beyond Briggs), building downwash (Huber–Snyder), and receptor-grid output. See [cimorelli2005aermod]. Useful as a sanity benchmark against operational tools, not a primary research target.


(2) Model-based inference

The plume is analytical, so the full forward H:(Q,x0,Heff,uˉ,θwind,… )→ymodel(x,y)H : (Q, x_0, H_\text{eff}, \bar{u}, \theta_\text{wind}, \dots) \to y_\text{model}(x,y) is differentiable via JAX end-to-end (column integration + AK included).

Likelihood model

yobs(x,y)  =  ymodel(x,y)+ε(x,y),ε(x,y)∼N ⁣(0, σretr(x,y)2)y_\text{obs}(x,y) \;=\; y_\text{model}(x,y) + \varepsilon(x,y), \qquad \varepsilon(x,y) \sim \mathcal{N}\!\bigl(0,\, \sigma_\text{retr}(x,y)^{2}\bigr)

Priors

Tier I prior specifications by parameter.

ParameterPriorRationale
QQLogNormal⁡(μQ,σQ)\operatorname{LogNormal}(\mu_Q, \sigma_Q) with μQ\mu_Q from the emission inventory prior, σQ≈1.0\sigma_Q \approx 1.0positive, heavy-tail; matches inventory uncertainty
x0x_0N(facilitylat,lon,σx0)\mathcal{N}(\text{facility}_\text{lat,lon}, \sigma_{x_0}) with σx0≈\sigma_{x_0} \approx sub-pixelfacility location is known, sub-pixel uncertainty for cluster vs. point
HeffH_\text{eff}Uniform⁡(Hstack, Hstack+Δhmax)\operatorname{Uniform}(H_\text{stack},\, H_\text{stack} + \Delta h_\text{max}) or N(Hstack+Δhbriggs, σH)\mathcal{N}(H_\text{stack} + \Delta h_\text{briggs},\, \sigma_H)depends on whether stack height is known
uˉ\bar{u}N(uˉmet,σuˉ,met)\mathcal{N}(\bar{u}_\text{met}, \sigma_{\bar{u},\text{met}}) — tight prior from metuˉ\bar{u} is data, not a free parameter
θwind\theta_\text{wind}N(θmet,σθ,met)\mathcal{N}(\theta_\text{met}, \sigma_{\theta,\text{met}}) — tight prior from metsame
cbgc_\text{bg}GP or Gaussian per-tile around climatologyregional background varies smoothly

MAP / MCMC

Q/uˉQ / \bar{u} identifiability — corrected

The classic statement is “QQ and uˉ\bar{u} enter only as Q/uˉQ/\bar{u}, so they’re degenerate in a single transect” [varon2018quantifying]. This is true only if uˉ\bar{u} has a flat prior. In production, the tight met-derived prior on uˉ\bar{u} resolves the degeneracy: the posterior p(Q∣y,uˉmet,σuˉ,met)p(Q \mid y, \bar{u}_\text{met}, \sigma_{\bar{u},\text{met}}) contracts as long as σuˉ,met/uˉmet≪σQ/Qprior\sigma_{\bar{u},\text{met}} / \bar{u}_\text{met} \ll \sigma_Q / Q_\text{prior}. The “need two crosswind transects” claim is a special case for fully-free uˉ\bar{u} and should not be the default reading.

When the wind prior is not tight (rare — typically remote regions without good reanalysis coverage), then yes, multiple overpasses with different wind directions break the ratio. But the first-line fix is the prior, not the geometry.

This is the first working end-to-end inverse pipeline. Build it here, validate against synthetic releases with known truth, then move to real controlled-release data (see Validation).


(3) Model emulator


(4) Emulator-based inference

Same inference loop as Step 2, but the forward pass is the neural network. Required validation:

If those pass for Tier I, the same diagnostics apply unchanged at Tier III.


(5) Amortized inference (predictor)

Train a summary network + posterior network mapping observation patches directly to the source posterior:

fθ:(ypatch,context)  ⟼  p(Q,x0,Heff∣ypatch,context)f_\theta : (y_\text{patch}, \text{context}) \;\longmapsto\; p(Q, x_0, H_\text{eff} \mid y_\text{patch}, \text{context})

Input shape — commit to a 2D patch

ypatchy_\text{patch} is a fixed-size 2D image patch of column XCH₄ enhancement (background-subtracted) centred on the facility candidate, plus per-pixel uncertainty and quality-mask channels. Concretely:

This commitment matters because it pins the architecture (CNN-style backbones over set-transformers or graph nets).

Conditioning on context

The predictor is not observation-only. At inference time we know context=(facilitylat,lon,uˉmet,θwind,met,stability_class,Lmet)\text{context} = (\text{facility}_\text{lat,lon}, \bar{u}_\text{met}, \theta_\text{wind,met}, \text{stability\_class}, L_\text{met}). The clean way to wire this in is feature-wise modulation of the summary network — the FiLM / hypernet conditioning primitives being built in pyrox.nn.

summary   = CNN(y_patch)              # observation features
modulated = FiLM(summary, context)    # per-feature γ(context)·summary + β(context)
posterior = NPE_head(modulated)       # conditional flow over (Q, x₀, H_eff)

Architecture options

Training dataset is free: simulate millions of plume configurations in seconds, sampling met context from the WRF/ERA5 climatology. Validation: posterior calibration via simulation-based calibration (SBC) — uniform rank statistics across 1k held-out simulations, stratified by met regime.


(6) Improve


Module layout

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

StepConcernModuleStatus
1Plume forwardgauss_plume/plume.py✓
1Puff forwardgauss_puff/puff.py✓
1Plume rise (Briggs)gauss_plume.plume_rise☐ #82
1Stability + dispersiongauss_plume/dispersion.py🚧 partial
1Puff turbulencegauss_puff/turbulence.py✓
1Column + AK pipelinegauss_plume.observation (shared by Tiers II–III; today split between coupled.column_response and les_fvm.ColumnObservationOperator)☐ #83
1Background cbgc_\text{bg} loaderplumax.priors.background☐ #81
2Likelihoods + priorsgauss_plume.likelihoods☐ #84
2Plume MAP/MCMCgauss_plume/inference.py✓
2Puff inferencegauss_puff/inference.py✓
2Posterior export → Tier Vextended PerEventPosterior on the infer_emission_rate result (mark-likelihood adapter for V.A)☐ #107
3Plume emulatorgauss_plume.emulator— skipped: model is cheap (see cycle)
4Emulator-based MCMCwired in inference.py once emulator exists— skipped with Step 3
5NPE / flow predictorgauss_plume.predictor☐ #87
5Context-conditioning layeruses pyrox.nn FiLM/hypernet primitivesexternal dep
6Multi-source (masked-K v1, RJMCMC later)extend inference.py with a K_max activity mask☐ #85
6MO σ\sigma swapgauss_plume.dispersion_mo☐ #86 (needs #78)

Validation strategy

c  ⟶  Quˉ L 2π σyexp⁡ ⁣(−y22σy2)c \;\longrightarrow\; \frac{Q}{\bar{u}\, L\, \sqrt{2\pi}\, \sigma_y} \exp\!\left(-\frac{y^{2}}{2\sigma_y^{2}}\right)

Tests both branches of the nn-sum.


Aggregating across overpasses

The MAP / MCMC posterior p(Q∣overpass)p(Q \mid \text{overpass}) produced here is the per-event evidence consumed by the population layer. See Tier V.A — Instantaneous emission estimation for the formal interface that turns this posterior into a mark likelihood for the TMTPP fit, and Tier V.D — Total emission estimation for why per-overpass averages systematically misrepresent regional totals.

The multi-source extension (Step 6) makes this interface variable-KK per overpass — the V.A adapter must handle that.

Open questions