Research — operational data assimilation patterns¶
Subject: Sketches of how filterax fits into latency-sensitive, streaming, and online DA settings — the operational tail of the research-to-production arc.
Status: Research note, not API spec. The concrete API commitments live in features/, integrations/, and decisions.md.
1 Why this doc exists¶
filterax's design is shaped by both research workflows (notebooks, papers, sweeps) and operational workflows (alert services, scheduled cycles, retraining loops). The research side is well-covered by vision.md and the feature docs; the operational side is more dispersed. This note collects the operational requirements in one place and traces them to filterax's design commitments.
2 Operational workflows of interest¶
2.1 Methane attribution alert service (plumax)¶
A FastAPI service ingests satellite L2 retrievals as they land, runs an ensemble DA cycle, and emits an alert payload (location, source rate estimate, uncertainty) within a fixed latency budget.
| Characteristic | Value |
|---|---|
| Latency budget | ≤5 s per alert |
| Trigger | New L2 retrieval available on the catalog |
| State carrier | coordax.Array or GeoTensor (coordinate-aware) |
| State dimension | 20 (Tier I Gaussian plume) — 10⁴ (Tier III gridded transport) |
| Ensemble size | 50–1000 |
| Observation dimension | 100–1000 pixels per overpass |
| Restart frequency | Every new overpass; warm-started from disk |
filterax design responses:
save_state/load_statefor warm-start (D15,features/state_persistence.md).JointObsOperatorfor multi-instrument fusion (D12,features/multi_instrument.md).GeoLocalizerfor geographic localization (D14,features/localization_inflation.md).CarrierAdapterfor coordinate-aware particles (D13,integrations/geostack.md).
2.2 Continental reanalysis¶
A scheduled job processes a year of satellite observations as a chain of cycles, producing a reanalysis dataset for downstream science. Latency does not matter; throughput, reproducibility, and post-hoc smoothing do.
| Characteristic | Value |
|---|---|
| Latency budget | Hours per cycle is fine |
| State dimension | 10⁴–10⁶ (continental grid) |
| Ensemble size | 200–500 |
| Smoother | Fixed-lag or full RTS over week-scale windows |
| Output | xarray / zarr dataset of analysis + smoother + uncertainty |
filterax design responses:
LocalEnKF(patcher-LETKF) for domain decomposition (D16).- Smoothers as a first-class deliverable, not an extension (D8,
features/smoothers.md). - xarray orchestration via
xr_assimilate— outside filterax (boundaries.md).
2.3 Online retraining of neural surrogates¶
A neural RTM is continuously retrained against new L1 radiance as it lands. The training signal is observation-space log-likelihood through the full filter.
| Characteristic | Value |
|---|---|
| Loss | -log_likelihood over a rolling time window |
| Gradient path | RTM params → obs operator → analysis → log-likelihood |
| Training cadence | Daily or per-batch |
| Checkpoint frequency | After each batch |
filterax design responses:
- Differentiability by construction (D9,
features/differentiable_da.md). - Filter state checkpointing (D15).
- No special "training mode" —
jax.gradon a filter call is the API.
3 Cross-cutting concerns¶
3.1 Cold-start budget¶
The ≤5 s budget breaks down approximately as:
| Cost | Budget |
|---|---|
| Process start + Python imports | ~1 s |
load_state from disk |
~0.1 s |
| JIT-compile the analysis graph | 1–3 s (first call only) |
| Actual analysis | < 0.5 s for 200-member, 10⁴-state ensemble |
JIT compilation is the dominant cost on cold start. Mitigations:
- Persistent JIT cache.
jax.experimental.compilation_cache.set_cache_dir(...)keeps the compiled XLA computation on disk across process restarts. - AoT compilation.
jax.jit(fn).lower(args).compile()produces a compiled object that can be pickled and reloaded. Experimental but increasingly stable. - Long-lived workers. If the deployment can keep a Python process alive (uvicorn workers, long-running pods), JIT only happens once.
filterax doesn't ship a recipe for any of these — they're deployment concerns. We commit to not making them harder: every JIT-able path through filterax is a single static-shape function, no per-overpass recompilation.
3.2 Streaming observations¶
The alert service consumes observations one at a time as they land. Each analysis is independent (modulo warm-state). The pattern is:
loop:
wait for new overpass
load filter state from disk
propagate ensemble through dynamics
analysis(forecast, new_obs, op, noise)
save filter state to disk
emit alert
filterax supports this pattern directly via the analysis + save_state / load_state surfaces. There is no "streaming filter" abstraction — the streaming loop is user-owned.
For pipekit integration, the streaming loop wraps a filterax filter in StatefulOperator (integrations/pipekit.md §4.3). pipekit's Cycle then drives the loop.
3.3 Async observation fetching¶
Real alert services fetch L1B / L2 data from cloud storage asynchronously. filterax has nothing to say about async — every filterax function is sync, pure-JAX. The async fetch happens in user code; filterax sees only the resulting array.
3.4 Hybrid ensemble-variational for tight latency¶
For latency-critical applications (alert service), pure ensemble methods are usually fast enough at moderate ensemble sizes (~100 members). When they're not, the operational pattern is:
- Use the ensemble for background covariance (flow-dependent, captures uncertainty).
- Run L-BFGS or another gradient method for the analysis update (deterministic, fast).
This is hybrid EnVar; it crosses the boundary between filterax and vardax. We don't ship it. The open-questions section of boundaries.md tracks the eventual cross-library design.
4 What filterax commits to and what it doesn't¶
Commitments¶
- Pure JAX analysis path. No Python control flow per analysis step; everything inside
jax.jit. - Serializable state. D15 —
save_state/load_stateround-trip every state type. - Static-shape API. Observation vector shape is fixed at JIT time; masking handled via
MaskedObsOperatorwith dynamic mask. - No hidden mutation. Every filter is pure; warm-start from disk is bit-identical.
Non-commitments¶
- No latency guarantees. filterax does not measure or budget cold-start time. That's deployment-side.
- No async API. Sync, pure-JAX. Async happens outside.
- No metric emission. Logs, traces, Prometheus metrics — all user-owned.
- No "operational mode." There's no flag that flips filterax into operational behavior. The same library serves notebooks and alert services.
5 Open questions¶
- AoT compilation for filter graphs.
jax.experimental.serialize_executableis maturing. When stable, filterax could ship a recipe for compiling an analysis graph once and reloading per process. - Static-typed observation schema. A
JointObsOperatorover a fixed instrument tuple has a fixed observation shape. Could filterax provide a@filter_for(joint_op)decorator that pre-computes shapes? Defer until pressure is concrete. - Distributed analysis. Patcher-LETKF across multiple devices via
jax.pmaporshard_map. Defer to Wave 4+ once the in-house patcher lands.
These all live in the research column for now. They become design changes only when a downstream consumer (plumax, geostack) puts concrete pressure on them.
6 References¶
vision.md— motivating use case and downstream pressuresintegrations/plumax.md— worked Tier IV recipefeatures/state_persistence.md— full serialization contractfeatures/multi_instrument.md— fusion patternsfeatures/differentiable_da.md— gradient pipe for neural surrogates- pipekit
pipekit-traindesign docs — analogue patterns for training loops