Differentiable port of the SVMC vegetation process model to JAX (Python) and @hamk-uas/jax-js-nonconsuming (TypeScript/browser).
The goal is a numerically faithful, fully differentiable reimplementation suitable for gradient-based parameter calibration and interactive browser-based exploration.
🤖 AI generated code & documentation with gentle human supervision.
packages/
svmc-ref/ Fortran reference test harness (driver program that exercises
original routines), fixture generation, branch audit
svmc-jax/ JAX reimplementation (float64, autodiff, invariant tests)
svmc-js/ TypeScript reimplementation (float32/float64, browser-ready)
vendor/
SVMC/ Original Fortran model (git submodule)
scripts/ CI tooling (branch coverage audit)
issues/ Upstream bug reports for SVMC
Each submodel is ported bottom-up (leaf functions — the lowest-level routines with no internal sub-calls — first), following the phased plan in PLAN.md:
- Fortran reference logging — the test harness (a driver program that calls each original Fortran routine over a grid of inputs) captures inputs and outputs as JSONL (newline-delimited JSON) fixtures (saved reference data used as ground-truth test cases).
- Branch audit — every conditional branch in the Fortran source is annotated with a
PORT-BRANCHtag, registered in a coverage manifest, and evaluated for whether the fixtures exercise it. - JAX port — differentiable reimplementation using
jnp.wherefor branch-free autodiff (automatic differentiation). Tested with fixture playback, metamorphic invariants (tests that check mathematical properties like monotonicity or conservation rather than exact values), and gradient/out-of-distribution validation. - TypeScript port —
@hamk-uas/jax-js-nonconsumingreimplementation tested against the same fixtures, withcheckLeaks(runtime verification that every GPU array is properly disposed) memory safety and epsilon-derived (computed from the floating-point precision limit) tolerance bounds.
See CONTRIBUTING.md for the PORT-BRANCH convention.
- The TypeScript
matrixExphelper currently uses a bounded masked-squaring policy (MAX_J = 20) because the presentlax.foriLoopAPI requires a static loop bound. The current reference fixtures explicitly stay within that bound; widening or removing it is required before using the helper on materially larger matrix norms. - Both the JAX and TypeScript
mod5c20transient solvers split theexp(At)·z₁ − bcomputation intoexp(At)·(A·init) + (exp(At) − I)·band use a first-order Taylor approximation (At·b) for the second term when‖At‖ ≤ √ε. The Fortran reference computesexp(At)·(A·init + b) − bdirectly. The split avoids catastrophic cancellation when‖At‖is small (e.g. extreme cold), where the direct subtractionexp(At)·b − bloses theO(At·b)contribution. Boundary tests verify smooth transition across the threshold in both languages.
| Phase | Scope | Status |
|---|---|---|
| 0 | Project foundation | ✅ Complete |
| 1 | All leaf functions | ✅ Complete |
| 2 | P-Hydro assemblies & optimizer | ✅ Complete |
| 3 | SpaFHy canopy & soil water balance | ✅ Complete |
| 4 | Carbon allocation & Yasso20 | In progress |
| 5 | Main SVMC integration loop | Planned |
| 6 | Interactive web application | Planned |
- Node.js ≥ 20, pnpm
- Python ≥ 3.11, pip
- gfortran (for fixture regeneration only)
# Python (JAX tests + branch audit)
pip install -e .[dev]
pytest
# TypeScript (browser-based tests via Playwright)
pnpm install
pnpm vitest run
# Branch coverage audit
python scripts/verify_branch_coverage.pyThe TypeScript port supports configurable numeric precision:
# Default: float32 (fast, GPU-friendly)
pnpm vitest run
# Higher accuracy: float64
SVMC_JS_DTYPE=float64 pnpm vitest runOlli Niemitalo (Olli.Niemitalo@hamk.fi) — Supervision of AI coding agents.
The vendor/SVMC/ directory contains the original SVMC Fortran model as a git submodule, copyright (c) 2023 huitang-earth, licensed under the MIT License. See vendor/SVMC/LICENSE.