fluctifex
Differentiable Earth-system modeling in JAX — assimilate raw observations, forecast, and control.
fluctifex — Latin fluctus (wave, flow) + -fex (maker), by analogy with opifex, artifex. The name points at the physics, not the weather: continuum flow, which is as true of the ocean and the climate as of the atmosphere.
Status: alpha (v0.1.0). APIs are unstable and will change. This is research infrastructure.
The thesis
Most machine-learning weather models are very good correlational forecasters. They train on reanalysis — itself the output of a physical assimilation system — and map one gridded state to the next. That is useful, and it is rung one.
fluctifex is built around a different claim: if the entire pipeline is differentiable, from raw
sensor readings through to the predicted field, then estimation and control fall out of the same
machinery.
- Differentiating the model backward through time against past observations is data assimilation (4D-Var) — the adjoint comes free from autodiff instead of being hand-written.
- Differentiating it forward against a future objective is control (differentiable MPC) — the intervention gradient falls out of the same rollout.
Estimation and control are mirror images: same forward model, opposite directions in time.
flowchart TD
OBSERVE["OBSERVE<br/>raw multi-sensor data<br/>(satellite · radar · stations · buoys)"]
ASSIMILATE["ASSIMILATE — backward · estimation<br/>optimize the STATE to match PAST obs"]
FORECAST["FORECAST<br/>roll the differentiable model forward"]
DECIDE["DECIDE — forward · control<br/>optimize future ACTIONS toward an OBJECTIVE"]
ACT["ACT<br/>apply the first action only (receding horizon)"]
OBSERVE --> ASSIMILATE --> FORECAST --> DECIDE --> ACT
ACT -->|world advances · repeat each cycle| OBSERVE
Every arrow is differentiable. The same jax.grad supplies the adjoint going backward and the
action gradient going forward.
Why differentiability has to start at the raw data
If the pipeline only becomes differentiable after preprocessing, then assimilation can only ever
reach as far back as the preprocessed state — which means you inherit whatever a conventional
assimilation system already decided. Beginning at raw, heterogeneous, gappy sensor readings is what
makes end-to-end assimilation possible at all. That is why the data layer is designed to build on
datarax, whose pipeline stages are themselves Flax NNX
modules: the windowed series and the padded station observations are datarax sources, and
normalization is a datarax operator stage, so a training epoch is a datarax Pipeline.
Architecture
| Module | Responsibility |
|---|---|
fluctifex.data |
Leakage-safe temporal splits; datarax sources for windowed grids and masked sparse station observations |
fluctifex.models |
Forecast backbones (spherical/planar neural operators) and multi-sensor fusion |
fluctifex.assimilation |
Variational (4D-Var) and sequential (Kalman) state estimation |
fluctifex.control |
Differentiable model-predictive control with safety constraints |
fluctifex.training |
Rollout-through-training (a-posteriori) for long-horizon stability |
fluctifex.evaluation |
Latitude-weighted and probabilistic verification (WeatherBench-2 style) |
Ecosystem
fluctifex is the Earth-system domain layer of the Avitai stack. It
composes rather than reimplements:
- opifex — neural operators (SFNO, FNO, …), PINNs, UQ, assimilation primitives, differentiable MPC
- datarax — differentiable, DAG-structured, shardable data pipelines
- calibrax — metrics, calibration, FLOP/roofline profiling
- substrax — device meshes, batch placement, checkpoints
Its sibling cellifex applies the same substrate to cellular dynamics.
Install
The Avitai siblings (opifex, datarax, calibrax, substrax) are core dependencies,
installed from PyPI.
From source (recommended — auto-detects CUDA / Metal / CPU):
git clone https://github.com/avitai/fluctifex.git
cd fluctifex
./setup.sh && source ./activate.sh
uv run pytest
Force a backend or add optional extras as needed:
./setup.sh --backend cpu # or cuda12, metal
uv sync --extra data # xarray / zarr / netCDF4 for Earth-system formats
Quickstart
import jax
from flax import nnx
from fluctifex.models import ForecasterConfig, build_forecaster
from fluctifex.training import rollout_loss
model = build_forecaster(ForecasterConfig(in_channels=8, out_channels=8), rngs=nnx.Rngs(0))
state = jax.random.normal(jax.random.key(0), (2, 8, 32, 64)) # (B, C, H, W)
next_state = model(state)
# Train through the rollout, not on single steps — a-posteriori stability.
loss = rollout_loss(model, state, targets, steps=4)
Assimilate sparse observations into a state estimate:
from fluctifex.assimilation import four_dvar
analysis = four_dvar(model, background=x_b, observations=y, observation_operator=H, num_steps=50)
Then plan an intervention through the forecast:
from fluctifex.control import DifferentiableMPC, MPCConfig
mpc = DifferentiableMPC(MPCConfig(horizon=8), dynamics=model)
action = mpc.solve(analysis, objective) # apply only the first step, then re-plan
Design commitments
- Differentiable end to end, beginning at raw observations.
- Composition over reimplementation — the Avitai siblings do the heavy lifting.
- Stability is a first-class result, not a footnote: train through rollouts, report drift.
- Uncertainty gates action. A forecast does not drive a recommendation unless its uncertainty is calibrated.
- Honest baselines. Persistence, climatology, and matched-cost references, always.
Honest limitations
- Alpha software; APIs will break between minor versions.
- No pretrained weights are shipped yet.
- Single-host SPMD is exercised; multi-host is untested.
- Physical intervention (
control) is a research capability, validated only in simulation. Nothing here is fit for real-world atmospheric intervention, and it should not be represented as such.
License
MIT — see LICENSE.
Release files for fluctifex 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fluctifex-0.1.1.tar.gz | 28.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fluctifex-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.8 kB
Release files / fluctifex-0.1.1.tar.gz
| Download URL | fluctifex-0.1.1.tar.gz |
|---|---|
| Size | 28.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a552bae35cecf8efb1196bf9add3b567fb1f640732b6d397d2a72c88c120fe03
|
|
BLAKE2b-256 checksum How to use checksums |
6f09ea5f6717c767fe44322d77d218d3576e467bb3658dec765f81ebd1f1d62b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency logRelease files / fluctifex-0.1.1-py3-none-any.whl
| Download URL | fluctifex-0.1.1-py3-none-any.whl |
|---|---|
| Size | 33.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ef7cbe2a464c7f72ca5934a1997063c14d176a7d5dd77fd4aa4550530f445e5b
|
|
BLAKE2b-256 checksum How to use checksums |
90ee92e474724b53ed49c9054db1c3fb5819985c3d00c9e45d157f8666c8b47c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency log