SWAT+ production engine
The SWAT+ engine we run in production
SWATGenX runs our fork at ship/v1.0-48 — a pinned SWAT+ build (NetCDF backend, print-filtering, and two engine fixes) unified with opt-in multi-core, PFAS, and MODFLOW 6 — deployed only after a ship-gate certification proves it output-identical on plain models.
Pinned per release: our fork at ship/v1.0-48 (deployed 2026-08-01; commit 6520940 for auditors). Ladder measured on Peace River HUC-8, 94,303 HRUs.
- Current pin: our fork at ship/v1.0-48
- 341× smaller output vs stock
- ~2× faster engine core vs stock
- Ship-gate certified ≤ 1e-5 on plain models
A recurring question is which exact SWAT+ binary builds SWATGenX models, and how it differs from the stock distribution. SWATGenX runs our fork at ship/v1.0-48 — pinned per release — and every speed/size claim on this page is measured against the stock original.
It is an overview, not a re-derivation. The detailed evidence for each contribution lives on its own deep-dive page; here we show the cumulative stock-to-production ladder and a changelog of every contribution and its state — the four output/performance layers are each an open upstream PR, and the multi-core, PFAS, and MODFLOW 6 layers live on the open fork.
The current production build is our fork at ship/v1.0-48 (deployed 2026-08-01; commit 6520940 for auditors): the measured fast engine core plus three opt-in capabilities — shared-memory OpenMP parallelism, PFAS fate-and-transport, and a daily two-way MODFLOW 6 coupling. All three are inert at the plain-model serial default, and a pre-production ship gate certifies each swap output-identical to the previous engine on ordinary models before it deploys.
Production engine pin
SWATGenX runs our fork at ship/v1.0-48.
Key takeaways
- SWATGenX runs our fork at ship/v1.0-48 in production — pinned per release, deployed 2026-08-01 (commit rafiei-vahid/swatplus@6520940 for auditors). Parallel execution is certified byte-identical to a single-threaded run of the same build in 18 of 18 runs — three trials at each of 2, 4 and 8 threads, in both parallel modes, over 935,130 compared values apiece — on a fixture that reproduces the defect 5/5 on the pre-fix binary.
- NetCDF output + the channel_sd print-filter cut output size 341× (695 MB → 2.0 MB) versus stock.
- The two engine fixes then attack compute: the measured engine core runs ~2.0× faster than stock, with byte-identical results — and the unified build is ship-gate certified output-equivalent to that core on plain models (≤ 1e-5).
- The unified engine adds opt-in OpenMP parallelism, PFAS transport, and a MODFLOW 6 coupling — all inert at the plain-model serial default, all deployed today.
Motivation
What SWATGenX runs, and how far it is from stock SWAT+
"Production" should never be a vague word. SWATGenX runs our fork at ship/v1.0-48 — pinned per release — and it differs from the stock distribution in ways we can point to and measure. This page pins down exactly what we run and how far it is from the original.
It is the changelog and the integrator: a stock → fork-production ladder ending at the current unified engine, plus a table of every contribution and its state. The detailed proof for each lives on its own deep-dive page — here we show the cumulative effect, anchored to commits.
Methods
Every engine, pinned to a commit
Four engines are pinned for comparison. The stock baseline is swat-model/swatplus@5ccf6f0. Two fork rungs were each production in turn: 768f1d1 (NetCDF backend + channel_sd print-filter) and 247e95b (the same plus the two engine fixes). Current production is our fork at ship/v1.0-48 (commit rafiei-vahid/swatplus@6520940, deployed 2026-08-01): the 247e95b core consolidated with opt-in OpenMP parallelism (HRU land phase + routing wavefront), PFAS fate-and-transport, and a daily two-way MODFLOW 6 coupling. At its serial default all of that is inert, so a plain model runs exactly as before.
The three measured rungs were run on the same basin and window (Peace River HUC-8 (03100101) — 94,303 HRUs, 90 simulated days, ifx -O3 -ipo), each in its own native output mode — stock writes formatted-text channel_sd for all channels; the fork builds write gauge-filtered NetCDF — so the ladder reflects how each engine would actually be used, not an artificial common setting. The unified rung is deliberately not re-timed here: instead of a new benchmark, it carries a certification.
Before the 6520940 swap the candidate passed the full pre-production ship gate (scripts/ship_gate/gate.py): 75 checks PASS, 0 FAIL. Tier 1 on three plain benchmark models (M_09471300, MID_03100205, and MYAKKA_FERT_03100102 which runs scheduled fertilizer operations): backward-compatibility against the previous production engine byte-clean at exactly 0.00e+00, and parallel-vs-serial byte-identity at EXACT equality (0 differing cells over every output file) in BOTH parallel modes (HRU-parallel and full routing wavefront), at 2 and 4 threads, with 3 repeat trials per check — repeats included because a data race is probabilistic and a single clean run is not evidence. Tier 2 on the coupled SWAT+/MODFLOW-6 PFAS model: flow, nutrients and PFAS byte-clean against the golden reference, MODFLOW mass-balance discrepancy -0%, and coupled byte-identity for both parallel modes at 2 and 4 threads. Log: GenXAppData/ship_gate/runs/2026-08-01_v1.0-48-g6520940_vs_v1.0-45-g6423104_SHIP.log
| Role | Repo @ commit | What it is |
|---|---|---|
| Stock | swat-model/swatplus@5ccf6f0 | stock SWAT+ (upstream/main) — formatted-text output, no filter |
| First fork production | rafiei-vahid/swatplus@768f1d1 | first fork production — NetCDF backend + channel_sd print-filter (deployed until 2026-06-06) |
| Second fork production | rafiei-vahid/swatplus@247e95b | second fork production — NetCDF + print-filter + the two engine fixes (deployed 2026-06-06 → 2026-06-28) |
| Current production | rafiei-vahid/swatplus@6520940 | current production — unified engine (NetCDF + print-filter core, opt-in OpenMP parallelism, PFAS fate-and-transport, MODFLOW 6 coupling). Parallel execution is certified byte-identical to a single-threaded run OF THE SAME BUILD in 18 of 18 runs — three trials at each of 2, 4 and 8 threads, in both parallel modes, over 935,130 compared values apiece — on a 777-HRU fixture that activates scheduled fertilizer and pesticide operations, tile drainage and PFAS transport, and that reproduces the defect 5/5 on the pre-fix binary. "Of the same build" is load-bearing: recompiling changes results at floating-point level, so a rebuild is not the comparison being certified. Deployed 2026-08-01; engine rev 62.0.0-81-g6520940, fork tag ship/v1.0-48 |
- Baseline: swat-model/swatplus@5ccf6f0 (stock).
- Fork productions, in order: 768f1d1 (NetCDF + filter) → 247e95b (+ two engine fixes).
- Current production (deployed 2026-08-01): our fork at ship/v1.0-48 — unified engine, serial default, opt-in parallelism/PFAS/MF6.
- Each measured number on this page is sourced from the release manifest, not hand-edited.
Results and discussion
Stock → fork productions → current unified engine
Peace River HUC-8 (03100101) — 94,303 HRUs · 90 simulated days.
Figure 1. Wall time and output size across the three measured rungs on Peace River HUC-8 (03100101) — 94,303 HRUs (90 simulated days). NetCDF + filtering crushed size; the two fixes crushed runtime. The current unified engine (6520940) is certified output-equivalent to the fastest measured rung on plain models, so it inherits these numbers at its serial default.
Table 1. Stock → fork productions → current unified engine, each pinned to a commit, with wall time, output size, and ratios versus stock for the measured rungs.
| Stage | Commit | Wall (s) | Output | vs stock (wall) | vs stock (size) | State |
|---|---|---|---|---|---|---|
| Stock | 5ccf6f0 | 462 | 695.10 MB | 1.0× (baseline) | 1.0× (baseline) | upstream original |
| NetCDF + print-filter | 768f1d1 | 414 | 2.04 MB | 1.1× | 341× smaller | first fork production (superseded 2026-06-06) |
| Two engine fixes | 247e95b | 227 | 2.04 MB | 2.0× | 341× smaller | second fork production (superseded 2026-06-28); measured core of the current engine |
| Unified engine | 6520940 | — | — | not re-timed | same filtered NetCDF | deployed — current (2026-08-01) |
Unified engine (6520940): Not re-timed on this ladder. The ship gate certifies OUTPUT equivalence (worst-relative ≤ 1e-5) to the 247e95b rung on plain models at the serial default — that is a correctness result, not a wall-time one. The unified build is compiled with OpenMP, and an OpenMP build costs 1.20–1.24× at one thread against a serial-only build of the same core (measured twice on AWS c8a), so its serial wall time is not claimed to match the 247e95b rung. Opt-in multi-core scaling is measured separately on the parallel-engine page.
The contribution families move different axes. NetCDF + print-filtering (stock → 768f1d1) cut output ~341× (695 MB → 2.0 MB) while wall time changed only ~1.1× — because once output is small, the bottleneck is compute, not I/O. The two engine fixes (768f1d1 → 247e95b) then attack the compute: the same run drops to 227 s, ~2.0× faster than stock with byte-identical results. The unified engine (6520940) keeps that measured core — certified output-equivalent on plain models (≤ 1e-5) — and adds the opt-in capabilities: multi-core scaling (measured on the parallel-engine page), PFAS transport, and the MODFLOW 6 coupling.
Contributions and their state
Table 2. Every engine contribution: the axis it moves, its headline effect, its state (output/perf contributions have open upstream PRs; the parallel/PFAS/MF6 layers live on the open fork), and a link to its deep-dive evidence.
| Contribution | Axis | Headline | State | Upstream PR | Details |
|---|---|---|---|---|---|
| NetCDF output backend | output format | enables compact NetCDF output | in production; upstream PR open | #213 | runtime benchmark |
| channel_sd print-filter | output scope | gauge-only channel_sd → 341× smaller | in production; upstream PR open | #214 | runtime benchmark |
| hru_read O(1) name index | runtime (startup) | string name-matching 75 → 7 s | in production; upstream PR open | #219 | performance profiling |
| varinit per-row reset | runtime (daily loop) | array zeroing 28 → 2 s | in production; upstream PR open | #220 | performance profiling |
| OpenMP parallelism (HRU land phase + routing wavefront) | runtime (multi-core) | 5.33× at 24 threads on a 32-core node; byte-identical at 1 thread | in production (opt-in; serial default); fork main | fork only | parallel engine |
| PFAS fate-and-transport | new physics | watershed-scale PFAS transport in SWAT+ (Freundlich sorption) | in production (inert unless configured); fork main | fork only | PFAS fate & transport |
| MODFLOW 6 coupling | new physics | daily two-way recharge/baseflow exchange with MODFLOW 6 | in production (inert without mf6 config); fork main | fork only | SWAT+ × MODFLOW 6 |
Conclusion
- Production is pinned per release — currently rafiei-vahid/swatplus@6520940 (deployed 2026-08-01), the unified engine: the measured 247e95b core plus opt-in OpenMP parallelism, PFAS fate-and-transport, and a MODFLOW 6 coupling, all inert at the plain-model default.
- Versus stock on a 94k-HRU basin, the measured engine core writes ~341× smaller output and runs ~2.0× faster, with byte-identical results; the unified build is ship-gate certified output-equivalent (≤ 1e-5) to that core on plain models.
- Output size and runtime are independent axes: NetCDF + filtering won on size, the two fixes won on speed, and both are in the shipped engine. The four output/perf contributions each have an open upstream PR against swat-model/swatplus (#213/#214/#219/#220); the parallelism, PFAS, and MODFLOW 6 layers live on the open fork's main branch and are documented on their own pages.
FAQ
Which SWAT+ engine does SWATGenX actually run in production?
SWATGenX runs our fork at ship/v1.0-48 — the unified engine deployed 2026-08-01 (commit rafiei-vahid/swatplus@6520940 for auditors), whose parallel execution is certified byte-identical to the serial engine. Its engine core is rafiei-vahid/swatplus@247e95b (built on the stock swat-model/swatplus baseline plus a NetCDF output backend, channel_sd print-filtering, and two engine fixes, PRs #219/#220), consolidated with three opt-in capabilities: OpenMP parallelism (multi-core HRU land phase + wavefront routing), PFAS fate-and-transport, and a daily two-way MODFLOW 6 coupling. Production is pinned per release, not a moving label — and at the plain-model serial default the parallel/PFAS/MF6 code is inert, so an ordinary SWAT+ build runs exactly as the 247e95b core did.
How does production compare to stock SWAT+?
On a 3-month Peace River run (94,303 HRUs), stock writes a 695 MB channel_sd text file in 462 s; the measured engine core writes a 2.0 MB filtered NetCDF file in 227 s — output size ~341× smaller and wall time ~2.0× faster, with byte-identical results. The current unified build (6520940) is ship-gate certified output-equivalent to that core on plain models (worst-relative ≤ 1e-5), so it carries the same numbers at its serial default; its opt-in multi-core scaling (up to ~7.1× end-to-end) is measured on the parallel-engine page.
How do you know the unified engine is safe for ordinary models?
Every engine binary passes a pre-production ship gate before it can replace the deployed one. Tier 1 regresses the candidate against the live production engine on plain benchmark models — flow and nutrient worst-relative differences must be ≤ 1e-5 (compiler-noise band) — and separately requires every parallel run to be byte-identical to a serial run of the same binary: exact equality across every variable of every output file, at two thread counts, in both parallel modes, repeated three times per check because a data race is probabilistic and one clean run is not evidence. Tier 2 validates the coupling and PFAS transport against a committed golden on the Rogue SWAT+/MODFLOW 6 model, with MODFLOW mass-balance discrepancy < 1%. Tier 3 handles deploy safety: it refuses to swap while any model build or calibration is in flight, backs up the previous binary, smoke-tests, and auto-rolls-back on failure. The current 6520940 engine passed all three: 75 checks, zero failures, on 2026-08-01.
Are the engine contributions upstream in official SWAT+?
The four output/performance contributions are each open as an independent pull request against swat-model/swatplus — NetCDF backend (#213), channel_sd print-filter (#214), hru_read O(1) name lookup (#219), and varinit per-row reset (#220) — proposed but not yet merged into the official release, so SWATGenX runs them from the pinned fork today. The parallelism, PFAS, and MODFLOW 6 layers live on the open fork’s main branch (github.com/rafiei-vahid/swatplus) and are documented on their own pages.
Where do the detailed numbers live?
Each contribution has its own deep-dive page that owns its evidence: the performance-profiling page for the two engine fixes, the runtime-benchmark page for output format and print scope, and the parallel-engine page for the multi-core scaling. This page is the changelog/overview that links to them.
Next steps
Last updated 2026-07-13.
