1.4.0: scale out and connect#
Status: proposed · Base: 1.3.0
1.3.0 lets a researcher answer a question with a model. 1.4.0 removes the ceilings on how big that model can be and how close to the real world it can run: distributed populations, GPU and differentiable models, live data and assimilation, multi-scale coupling, and Modelly running in a browser tab. Eleven epics, eight sprints, three pre-releases, all on Windows, macOS and Linux (see Platforms). Backward compatible with 1.3.
Where we start#
1.3.0 gives |
1.4.0 adds |
|---|---|
Experiments with process, thread, Dask, Ray and SLURM executors |
One model split across many processes or machines |
Calibration (ABC, SMM, Bayesian optimisation) |
Gradient-based calibration through differentiable models; history matching |
GPU array backend (preview) |
GPU backend generally available, with cell spaces on the GPU |
Geospatial space and synthetic-population helpers |
A full synthetic-population toolkit from census tables |
Studio in a local browser |
Studio and models running entirely in the browser, shared by a link |
Checkpoints and time travel |
Live data streams and data assimilation over replicate ensembles |
Who 1.4.0 is for#
Field |
What 1.4.0 unlocks |
|---|---|
Epidemiology |
Country-scale populations (tens of millions of agents) split over a cluster; nowcasting with live case data through particle filters |
Ecology |
Landscapes coupled to PDE fields (diffusion of nutrients, heat); GPU runs for large individual-based models |
Economics |
Agent-based macro models with millions of households; gradient calibration of behavioural parameters |
Urban and transport |
City digital twins fed by sensor streams; traffic on full regional road networks |
Climate and energy |
ABMs coupled to system-dynamics or climate emulators; large adoption sweeps on GPUs |
Teaching and outreach |
A model in a web page, no installation, on any computer with a browser |
Epics#
Sizes: S under a sprint, M one sprint, L two sprints, XL three or more.
F1 · Distributed simulation (modelly.distributed)#
Goal: one model whose population and space are split across processes or machines, with the same results as a single-process run for the same seed.
Platforms: MPI through mpi4py (Open MPI or MPICH on Linux and macOS, MS-MPI on Windows);
a Dask and a Ray backend that need no MPI and run on all three.
User stories
As an epidemiologist, I run a 30-million-agent country model on 64 cores of a cluster with the code I wrote for 100,000 agents on my laptop.
As an RSE, I check that a distributed run and a single-process run of a small model give the same output, byte for byte.
Design
Spatial partitioning (grid blocks, graph partitioning for networks, k-d partitioning for continuous space) with ghost cells (halo exchange) at partition borders.
Agents migrate between partitions when they move; migration happens at a phase boundary, in a deterministic order.
Random numbers: one stream per agent (from the agent’s seed), so results do not depend on how the space is partitioned.
Collectors reduce across partitions; checkpoints write one file per partition plus an index.
API sketch
from modelly.distributed import Cluster, partition
with Cluster(backend="mpi", workers=64) as cluster:
model = cluster.build(Epidemic, scenario, partition=partition.grid_blocks(8, 8))
model.run_for(365)
cluster.collect().to_parquet("runs/country.parquet")
Done when: partition-independent results on the zoo’s grid and network models (2, 4 and 16 partitions, identical outputs); weak scaling efficiency of at least 70% from 1 to 64 workers on the grid epidemic playbook; runs on MPI and Dask on all three platforms.
Tasks
[ ] Per-agent random streams (opt-in in 1.4, default in 2.0)
[ ] Partitioners: grid blocks, graph (METIS-style, pure Python fallback), k-d
[ ] Halo exchange and agent migration protocol
[ ] MPI, Dask and Ray backends
[ ] Distributed collectors and checkpoints
[ ] Partition-independence test suite; scaling benchmark
[ ] Guide: from laptop to cluster
Size: XL · Depends on: 1.3 E3, E11
F2 · GPU backend, generally available#
Goal: column phases, cohorts and cell spaces run on a GPU with one setting, with results equal to numpy within documented tolerances.
Platforms: CUDA through CuPy on Linux and Windows; JAX on Linux, Windows (CPU or CUDA) and macOS (Metal where available, CPU otherwise). Every GPU path has a CPU fallback.
Work items: array-API backend for every column operation; CellIndex adjacency, counts and
random-neighbour draws on the GPU; CohortTable binomial thinning on the GPU; counter-based
random streams (Philox) so GPU and CPU draw the same numbers; memory planner for populations
larger than GPU memory (batches); benchmark playbooks with a modelly-gpu variant.
Done when: grid epidemic and insect cohorts playbooks run on CUDA and Metal; results equal the CPU run for integer state and within a stated tolerance for floats; at least 10x faster than the CPU column variant at 10 million agents on a mid-range GPU (measured and published, not assumed).
Size: L · Depends on: 1.3 E11 preview
F3 · Differentiable models (modelly.diff)#
Goal: gradients of model outputs with respect to parameters, for gradient-based calibration and sensitivity, where the model allows it.
Platforms: JAX on all three (CPU everywhere, GPU per F2).
Design: column phases traced with JAX; discrete random choices handled with documented
estimators (straight-through, Gumbel-softmax, score function) and an explicit warning that the
gradient is an approximation; a differentiable flag per phase; gradient checks against finite
differences.
User stories: as an economist, I fit 40 behavioural parameters with gradient descent in minutes instead of an ABC run of days; as a modeller, I get local sensitivities (gradients) at the calibrated point for free.
Done when: gradient-based calibration recovers known parameters on two zoo models; gradients agree with finite differences within tolerance; docs explain when gradients are meaningful and when they are not.
Size: L · Depends on: F2, 1.3 E1
F4 · Modelly in the browser (Pyodide and WebAssembly)#
Goal: run a Modelly model and Studio entirely in a browser tab, with no installation, and share it as a link or a static page.
Platforms: any OS with a current browser (Chrome, Edge, Firefox, Safari); Pyodide build of the pure wheel in 1.3 (smoke test), compiled modules built for WebAssembly in 1.4.
Work items: Emscripten builds of fastrng, fastloop, fastcell; a modelly export-web
command that writes a static site (model code, scenario, Studio) deployable on GitHub Pages;
optional dependencies trimmed for the browser; worker threads for long runs; size budget for
the first load.
Done when: every 1.3 example runs in the browser from a static export; the export of a zoo model loads in under 10 seconds on a typical connection (measured); the docs gallery embeds live models.
Size: L · Depends on: 1.3 E5 Studio
F5 · Live data and data assimilation (modelly.stream)#
Goal: feed real-world observations into running models and keep an ensemble of runs close to reality: the core of a digital twin.
Platforms: pure Python on all three; MQTT and Kafka connectors as optional extras with wheels for all three.
Design: stream sources (files, HTTP polling, MQTT, Kafka); observation operators mapping model state to observed quantities; ensembles of replicates advanced in lock step; assimilation by particle filter (resampling replicates through checkpoints) and ensemble Kalman filter for continuous parameters; a live dashboard in Studio.
User stories: as a public-health modeller, I update tomorrow’s forecast every morning from yesterday’s cases; as a transport researcher, I keep a traffic model in step with loop-detector counts.
Done when: a nowcasting tutorial with a synthetic “truth” run shows the filter tracking it; particle resampling is reproducible for a seed; Studio shows the ensemble band live.
Size: L · Depends on: 1.3 E6 (checkpoint ring), E3
F6 · Multi-scale coupling (modelly.couple)#
Goal: couple agents to continuous processes: system-dynamics stocks and flows, ODEs, and PDE fields over space.
Platforms: numpy and scipy on all three.
Design: a Field type (a property layer with a solver: diffusion, advection, decay) stepped
on its own time step; ODE and stock-flow components through scipy’s integrators; a coupling
schedule (who reads what, when) checked for consistency at build time.
Done when: an ecology model with a diffusing nutrient field and a disease model coupled to a hospital-capacity ODE are in the zoo, with conservation checks (mass balance) as tests.
Size: M · Depends on: 1.3 E8 (rasters)
F7 · Emulators, active learning and history matching#
Goal: answer questions about expensive models with far fewer runs.
Design: Gaussian-process and neural emulators trained on experiment results (1.3 E3); active-learning designs that choose the next runs where the emulator is least certain; history matching (implausibility measures, waves of non-implausible space), widely used in epidemiology and climate science.
Done when: history matching reproduces a published wave sequence on a zoo model; active learning reaches the same emulator accuracy as a Latin hypercube with at most half the runs on two benchmarks.
Size: M · Depends on: 1.3 E1, E2, E3
F8 · Synthetic populations (modelly.population)#
Goal: realistic starting populations from aggregate data, with households and places.
Design: iterative proportional fitting and combinatorial optimisation from census marginals; households, schools and workplaces assigned with distance constraints; contact networks generated from places; privacy notes and no bundled personal data.
Done when: a synthetic population for a sample region reproduces its marginals within tolerance; the age-structured SEIR zoo model starts from it.
Size: M · Depends on: 1.3 E8, E9
F9 · Performance II#
Work items: compiled event scheduler (heap in C, same ordering); compiled DataCollector
gather for column-backed agents; memory-mapped columns for populations larger than RAM;
per-compiler PGO (GCC, Clang, MSVC) shipped where it measures faster;
modelly bench comparison against 1.3 on all three OSs.
Done when: no playbook slower than 1.3 on any OS; event-heavy models (wolf-sheep) measurably faster; a 100-million-row column run on a 16 GB machine.
Size: L
F10 · Studio II#
Work items: ensemble views (bands across replicates); experiment browser over the results store; calibration and assimilation dashboards; map and network views at scale (WebGL); recording a session as a reproducible script.
Size: M · Depends on: F4, F5
F11 · Quality and platforms#
Work items: partition-independence and GPU-equality suites in the determinism suite; WebAssembly in the release matrix; distributed tests on a three-OS MPI matrix (MS-MPI on Windows); deprecations for 2.0 announced in this release’s notes.
Size: M (continuous)
Priorities#
Priority |
Epics |
|---|---|
Must |
F1 Distributed, F2 GPU GA, F5 Live data, F11 Quality |
Should |
F3 Differentiable, F4 Browser, F7 Emulators, F9 Performance II |
Could |
F6 Coupling, F8 Synthetic populations, F10 Studio II |
Won’t |
Breaking changes; a hosted service |
flowchart LR
E3["1.3 Experiments"] --> F1[F1 Distributed]
E11["1.3 Performance"] --> F2[F2 GPU]
F2 --> F3[F3 Differentiable]
E1["1.3 Calibration"] --> F3
E1 --> F7[F7 Emulators]
E5["1.3 Studio"] --> F4[F4 Browser]
E6["1.3 Time travel"] --> F5[F5 Live data]
F4 --> F10[F10 Studio II]
F5 --> F10
E8["1.3 Geospatial"] --> F6[F6 Coupling]
E8 --> F8[F8 Populations]
Sprint plan#
Sprint |
Goal |
Main items |
Exit |
|---|---|---|---|
S1 |
Foundations |
Per-agent random streams; grid-block partitioner; stream sources and observation operators |
Same results with per-agent streams on 1 partition |
S2 |
Distributed core |
Halo exchange, migration, MPI backend; distributed collectors |
Partition-independent grid epidemic on 2 and 4 partitions |
S3 |
GPU and assimilation · a1 |
Array-API backend complete; Philox streams; particle filter |
GPU equals CPU on integer state; filter tracks synthetic truth |
S4 |
Backends and gradients |
Dask and Ray distributed backends; graph partitioner; JAX tracing; ensemble Kalman filter |
Distributed runs on Dask on all three OSs; gradient check passes |
S5 |
Browser |
Emscripten builds; |
Every example runs from a static export |
S6 |
Emulators and Studio II · b1 |
GP emulator, active learning, history matching; ensemble views |
Feature complete; API review closed |
S7 |
Coupling and populations · rc1 |
Fields and ODE coupling; synthetic populations; compiled scheduler |
No open blocker |
S8 |
Hardening · 1.4.0 |
Determinism, partition and GPU suites on all three OSs; scaling report; docs |
All release gates pass |
Release gates#
Release |
Gate |
|---|---|
1.4.0a1 |
Distributed grid model partition-independent; GPU backend equals CPU on integer state; wheels for all platforms |
1.4.0b1 |
Must and Should epics feature complete; public API frozen |
1.4.0rc1 |
No open blocker; tutorials run in the docs build |
1.4.0 |
Determinism, partition-independence and GPU suites green on Windows, macOS and Linux; scaling report published |
Success metrics#
Metric |
1.3.0 |
1.4.0 target |
|---|---|---|
Largest tested population |
single machine |
30 million agents across 64 workers |
Weak scaling efficiency, 1 to 64 workers |
not applicable |
at least 70% |
Platforms with compiled wheels |
8 |
9 (plus WebAssembly) |
Calibration methods |
ABC, SMM, Bayesian optimisation |
plus gradient-based and history matching |
Examples runnable in a browser |
0 |
all |
Risks#
Risk |
Likelihood |
Impact |
Mitigation |
|---|---|---|---|
Partition independence is hard to guarantee for every space |
High |
High |
Per-agent streams and phase-boundary migration; models that cannot be partitioned are detected and refused with a clear error |
MS-MPI on Windows lags Open MPI |
Medium |
Medium |
Dask and Ray backends are first-class; MPI tests on Windows run a reduced matrix |
GPU numerics differ from CPU |
High |
Medium |
Integer state compared exactly; floats with stated tolerances; Philox streams shared by CPU and GPU |
WebAssembly bundle too large |
Medium |
Medium |
Size budget per release; lazy loading of optional modules |
Scope (11 epics) |
High |
High |
Could items move to 1.5 first |
Open questions#
[ ] Default distributed backend: MPI (fastest on clusters) or Dask (easiest everywhere)?
[ ] Per-agent random streams: opt-in in 1.4 and default in 2.0, or default already in 1.4?
[ ] JAX as an optional extra only, or part of
recfor GPU users?[ ] Which public data sets to use for the synthetic-population tutorial (licences)?
Sprint review log#
Sprint |
Shipped |
Slipped |
Notes |
|---|---|---|---|
S1 |
|||
S2 |
|||
S3 |
|||
S4 |
|||
S5 |
|||
S6 |
|||
S7 |
|||
S8 |