wrf-rust0.4.1

WRF post-processing diagnostics, reimplemented in Rust, with a wrf-python-compatible Python API.

Validation and scientific rigor

Reimplementing a diagnostics library invites a specific failure mode: silently diverging from the reference while claiming compatibility. wrf-rust addresses this with pinned reference implementations, a differential parity harness that compares real outputs field-by-field, and a science audit whose findings are published with their numerical magnitudes — including the cases where wrf-rust's previous values were wrong and the corrected values changed.

1 Pinned references

Every compatibility or correctness claim is made against a fixed, named authority. "Matches wrf-python" always means the pinned commit below, not whatever upstream happens to be today.

AuthorityPinRole
NCAR wrf-python 1.3.4.1 31c9233 Primary numerical oracle for compatible fields; source of the strict *_wrfpython CAPE/SRH semantics (RIP Fortran, psadilookup.dat)
SHARPpy 1.4.0a5 a5405e2 Oracle for sounding-derived parameters (STP terms, SHIP, critical angle, mean-wind conventions, interpolation)
NOAA/SPC mesoanalysis definitions current pages Definitions for severe composites: SCP, effective STP, TEHI, DCP, MUCAPE, VTP
Primary literature DOIs Hampshire et al. (2018) for VTP; Evans and Doswell (2001) for DCP
ecape-rs 414cac6 Entraining-CAPE implementation, pinned by revision in wrf-core; upstream-golden test included

2 Differential parity methodology

The parity framework deliberately separates three questions that are easy to conflate:

  1. Does the public API have compatible names, options, units, axes, component ordering, and missing-value behavior?
  2. Where wrf-python is a valid oracle, are fields numerically within an explicit per-field tolerance?
  3. Where wrf-rust intentionally goes beyond or corrects wrf-python, does it match the appropriate scientific authority instead?

Question 3 is never answered by loosening a wrf-python tolerance; such fields are marked contract_only until they gain an independent oracle. Mechanically: WRF fixtures are registered by exact byte length and SHA-256 and never checked into the repository; wrf-python and wrf-rust run in separate environments (both import as wrf, so the extractors refuse to run if the other distribution is present); each produces an implementation bundle; and a comparator checks provenance, shapes, missing-value masks, and numerical tolerances against a resolved per-field contract. A second contract, derived from a real downstream consumer (WRF-Runner), regression-tests the literal call patterns that consumer makes.

Verification snapshot

Results of the most recent full run (2026-07-09, science-audit branch codex/science-audit-wave2 at 59b380c, which extends the released 0.3.0 line):

GateResultNotes
wrf-python differential (pinned 1.3.4.1) 16 / 16 passed, 0 failures All required comparisons in the 43-entry contract; one documented non-gating native theta_e difference; 26 contract_only extension products
SHARPpy differential (pinned 1.4.0a5) 23 / 23 passed, 0 failures Maximum absolute error 3.47 × 10−18
Rust workspace tests 723 passed, 0 failed 22 ignored (live/external); baseline at the 0.3.0 base was 693 passed, 0 failed
ECAPE goldens 12 / 12 + 1 / 1 Algorithm and goldens unchanged by the audit; pinned upstream-golden test passes

Reproducibility hashes for that run — WRF fixture SHA-256 0d950786…28a77e6; wrf-python bundle cd499cff…ef994af; wrf-rust bundle 40a34461…cc7d61f; comparison report 86136ada…54ec1e3 (full values in the audit record).

3 Corrections shipped in 0.3.0

The 0.3.0 release notes state it plainly: values change where the old ones were wrong. The corrections below shipped in 0.3.0; magnitudes are measured examples from the audit, not worst-case bounds.

CorrectionReferenceExample magnitude
Saturated parcel lifts above 1000 hPa no longer clamp to the 1000 hPa adiabat (satlift guard) SHARPpy thermo Affects any parcel starting below the 1000 hPa surface
Sub-LCL CIN integrates every model level instead of one midpoint slab; parcel trace uses dry physics below the LCL NCAR RIP CAPE Column-dependent; changes low-level CIN on most soundings
CIN no longer accumulates negative buoyancy above the LFC; LFC/EL selection uses accumulated-energy minimum and highest valid EL under multiple crossings NCAR RIP CAPE Removes spurious CIN in multi-crossing profiles
AVO and PVO apply WRF map-scale factors; PVO retains full baroclinic terms NCAR wrf_pvo Stretching-only vs full PVO sample delta −0.186 PVU (13.2%); AVO +3.15% at map factor 1.02
theta-e and theta-w no longer double-add 273.15 NCAR EQTHECALC, SHARPpy thermo Regression pins 344.93 K (not 618.08 K) and 292.11 K (not 565.26 K)
Theta diagnostics return their registered Kelvin units; helicity alias maps to srh registry contract Metadata/lookup correctness
Non-pressure-weighted mean wind resamples in pressure; 0–1 km fixed shear anchors at the 10 m wind; Southern-Hemisphere Bunkers movers mirror correctly SHARPpy winds NPW mean-wind example 33.33 → 50.36 m/s; shear example 15 → 20 m/s; mirrored SRH +112.5 → −112.5 m²/s²
Storm-relative inflow sign for the critical angle (storm motion minus surface wind) SHARPpy winds Canonical case 135° → 45°
Registered SHIP uses the most-unstable parcel's mixing ratio with SHARPpy bounds and corrections SHARPpy params Example case 0.5 → 1.2 (2.4×) where environmental vs MU mixing ratio differ 5 vs 12 g/kg

4 Wave-two audit corrections — shipped in 0.4.0

Status: the corrections in this section were developed on codex/science-audit-wave2, merged to main via pull request #2 (merge 6c5fbed), and shipped in v0.4.0. The full audit closed every lead: 12 fixed, 7 already resolved in the shipped line, 4 resolved by documentation, 2 refuted, 0 deferred.

FindingReferenceExample magnitude
Exported SHIP helper aligned with the registered (already-correct) implementation SHARPpy SHIP 0.5 → 1.2 (2.4×) in the canonical case
SCP: exported EBWD gate/cap fixed; registered SCP applies the current SPC MUCIN term SPC SCP MUCIN of −80 / −160 J/kg changes the old magnitude by −50% / −75%
Exported critical angle now requires the surface wind (arity change prevents silent stale use) SHARPpy winds Calm-surface example 135° → 45°
Effective STP gains the elevated-inflow zero gate SPC effective STP An otherwise-normalized elevated case: 1.0 → 0.0
TEHI assigns the high-ML3CAPE term exactly 1.0 per the literal SPC instruction SPC TEHI High-ML3CAPE fixture 2.4 → 1.6 (−33.3%)
Exported fixed-layer STP applies SHARPpy edge clamps SHARPpy fixed STP LCL 250 m term 1.75 → 1.0; 8 m/s shear term 0.4 → 0.0
Exported DCP uses 0–6 km mean wind with knot conversions SPC DCP, Evans–Doswell Canonical case 1.09 → 2.36 (+116.5%)
Relative humidity computed as q/qs rather than e/es NCAR DCOMPUTERH At 1000 hPa, 30 °C, q = 0.020: 73.38% → 74.52% (+1.14 points)
Gravity constant 9.81 m/s² (WRF's value) replaces 9.80665 NCAR wrf_constants Heights decrease 0.0341% (−0.34 m per km)
Height-at-pressure uses log-pressure interpolation SHARPpy interp Linear-p heights were high by 2.6 / 5.8 / 11.1 m in three layer examples
Dewpoint vapor-pressure floor matches NCAR NCAR DCOMPUTETD At 100 hPa, q = 0: −128.5 → −80.4 °C
Updraft-helicity boundary handling matches DCALCUH (asymmetric zero halo) NCAR DCALCUH Halo covers 5.91% of a 100×100 grid, 1.99% of 300×300
Southern-Hemisphere earth-rotation of winds matches wrf-python NCAR wrf-python projection semantics WPS alpha of 7° yields a 14° old-vs-reference separation

5 Documented conventions, not silent forks

Some differences from the references are deliberate. They are named differently, documented, and pinned by regression oracles rather than hidden:

6 What this does and does not claim