Native WRF preprocessing and GPU-native limited-area weather modeling
Project description
ArWen
ArWen is an independent, GPU-native implementation of a WRF-ARW-class
regional atmospheric model. It is not affiliated with or endorsed by
NCAR or UCAR. The name is a wordmark for "the ARW solver, GPU-native";
the Python package is currently named gpuwm.
Safety. ArWen is a research and educational tool. It is never a substitute for official forecasts and warnings from your national meteorological service. Do not use it to make safety decisions.
Regional numerical weather prediction at convective scale has mostly required institutional clusters, which means most of the world runs on global-model guidance at 10-25 km. ArWen's aim is to put a verified, kilometer-scale limited-area model on a single consumer GPU: pick a point, size a nest ladder to your card, pull public analysis data, and run a 1 km (or 500 m) simulation of your own area on hardware you own -- especially in places where no national convection-permitting model exists.
Above: unchanged WRF v4.6.1 (left of each pair) and ArWen (right), same case, matched physics. At +3 h on the 3 km domain the two models agree to composite-reflectivity correlation 0.985, with the squall line in the same place with the same structure and >=20 dBZ echo area matching to 3 pixels in 14,227; the numbers behind this figure are in VERIFICATION.md.
What it does
- Integrates a WRF-ARW-class compressible nonhydrostatic core (RK3, split-explicit acoustics, one-way static nesting) in FP32 on CUDA.
- Runs WRF v4.6.1-transcribed physics: 5 microphysics schemes, YSU and MYNN PBL, Noah / Noah-MP / RUC land surface, RTE+RRTMGP and legacy RRTMG radiation, Kain-Fritsch cumulus (PHYSICS.md).
- Initializes directly from ERA5, GFS, or HRRR with a built-in fetch
front door and a fail-closed Rust GRIB decode layer -- no WPS, no
real.exe(DATA.md). - Sizes domains to your GPU with a measured VRAM model
(
gpuwm domain; HARDWARE.md). - Renders reflectivity, T2, 10 m wind, and precipitation products; checkpoints and resumes; re-runs finer nests offline from archived parents (DOWNSCALE.md).
- Feeds unchanged stock WRF: the same preprocessor (
rw-wps) emitswrfinput_d0N/wrfbdy_d01that WRF v4.6.1 has accepted and integrated, serial and MPI (WRF-INTEROP.md).
Measured on one RTX 5090 (Windows 11, driver-default WDDM): a 6 h forecast on a 250x200x49 12-km domain with a full physics suite (Morrison two-moment microphysics, RTE+RRTMGP radiation, YSU, Noah, Kain-Fritsch) completed in 3.6 minutes of wall time using ~6.3 GiB of device memory; GFS input acquisition took 9.7 s and rendering 16 product PNGs took 2.6 s (first-time-user acceptance transcript, 2026-07-29).
Install
One command from the checkout root. install.sh / install.ps1
create .venv, install the [gpu,render] extras, stage the
externalized Thompson tables (gpuwm fetch-tables: a one-time
~243 MiB release-asset download from a checkout, SHA-256-verified
before install, skipped when already present; --no-fetch-tables /
-NoFetchTables defers it), offer to install rustup when cargo is
missing (they ask first; --yes / -Yes consents), build the
vendored Rust GRIB bridges and the production render engine offline
(--no-render / -NoRender skips the renderer build), and finish
with gpuwm doctor. Re-running either script is safe: an existing
.venv, staged tables, and built bridges are reused.
git clone https://github.com/FahrenheitResearch/arwen gpuwm && cd gpuwm
bash install.sh # PowerShell: .\install.ps1
bash install.sh is the universal form and works regardless of how
your checkout landed the file's mode bit. ./install.sh works too;
if it ever answers Permission denied, use the bash form above.
The same scripts also run standalone -- POSIX:
curl -fsSL https://raw.githubusercontent.com/FahrenheitResearch/arwen/main/install.sh | sh
Windows (PowerShell):
iwr -useb https://raw.githubusercontent.com/FahrenheitResearch/arwen/main/install.ps1 | iex
When piped like this, the script clones the repository into ./gpuwm
(set GPUWM_REPO_URL to clone from a fork or mirror instead).
You need Python 3.11+ and git; for GPU runs, an NVIDIA card with
CUDA 12.x/13.x, field-verified through 13.2 driver stacks on sm_89 by
two independent nodes: the toolkit works out of the box with the
cupy-cuda12x pin, because minor-version compatibility plus CuPy's
system-NVRTC discovery covers it -- measured on a Linux RTX 4070 and a
4090, 2026-07-30. The
manual steps, if you prefer them:
POSIX:
git clone https://github.com/FahrenheitResearch/arwen gpuwm && cd gpuwm
python -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[gpu,render]'
gpuwm fetch-tables
gpuwm fetch-geog # WPS_GEOG static tree: ~1.3 GB down, ~16 GB unpacked
(cd tools/grib1_bridge && cargo build --release --locked --offline)
(cd tools/rustwx && cargo build --release --locked --offline)
gpuwm doctor
Windows (PowerShell):
git clone https://github.com/FahrenheitResearch/arwen gpuwm; cd gpuwm
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e '.[gpu,render]'
gpuwm fetch-tables
gpuwm fetch-geog # WPS_GEOG static tree: ~1.3 GB down, ~16 GB unpacked
cd tools\grib1_bridge; cargo build --release --locked --offline; cd ..\..
cd tools\rustwx; cargo build --release --locked --offline; cd ..\..
gpuwm doctor
A plain pip install gpuwm is not enough to read weather data. The
wheel ships no compiled Rust, and every GRIB decode -- ERA5, GFS, GDAS,
HRRR, 20CRv3 -- goes through the fail-closed Rust bridges in
tools/grib1_bridge, which exist only in a clone. So a pip-only
install can size domains and read documentation, and will refuse every
real data source until you clone this repository and run the one
cargo build above (about two minutes). gpuwm doctor prints the
whole sequence, including the rustup line when cargo is missing.
Shipping prebuilt bridges in the wheel is not yet done.
[gpu] installs CuPy (required by gpuwm check/run and the sizing
wizard); [render] installs the pinned wrf-rust package for
gpuwm render's matplotlib fallback engine. The tools/rustwx build
is the production render engine (the vendored Rusty Weather renderer:
coast/state/county basemaps over a 324-entry vendored product catalog,
151 of whose products are implicit-render candidates on any file) --
gpuwm render uses it by default the moment it is built, and works
without it. gpuwm doctor then checks
each piece for real rather than by presence: it imports CuPy and the
render stack in subprocesses, probe-executes every bridge and the
renderer, loads the CPU library and reads its ABI,
hash-validates the staged Thompson tables, parses the Noah tables,
and requires each WPS_GEOG dataset's index file -- anything it can only
see (not prove) is labeled present instead of ok, and every gap
prints a remedy whose every line is a command or a # comment, so the
block survives being pasted whole. Most are exact commands; a few
cannot be, and say so rather than inventing one -- an unset
GPUWM_CASE_DATA_ROOT needs a path only you know. Details, wheel caveats, and the
sealed archives: docs/install.md.
First light
The condensed path from nothing to pictures (full walkthrough with measured timings: FIRST-LIGHT.md):
# 1. Size a domain ladder to your card at your point of interest
gpuwm domain --point 35.3,-97.5 --card 24gb --cycle 1999-05-03T12 \
--hours 6 --out configs/myarea.toml
# 2. Get data (ERA5 shown; the wizard prints the exact command)
gpuwm fetch --source era5 --cycle 1999-05-03T12 --hours 6 \
--area 25.4,-112.0,44.7,-83.0 --out data/myarea
# 3. Preflight, run, render
gpuwm check configs/myarea.toml
gpuwm run configs/myarea.toml --outdir out/myarea
gpuwm render out/myarea/wrfout_d01_* --out out/myarea/png
Live progress is run-progress.json in the output directory (atomic,
schema gpuwm.run-progress/v1); restart checkpoints are written every
restart_interval_s and gpuwm resume continues from the newest valid
one. The tools/ runners write a different file: the domain-tree
route writes <outdir>/evidence/progress.json and the single-domain
runners write <outdir>/progress.json.
What the output looks like
Discrete supercells with 55-60 dBZ cores on the 500 m nest at a
sub-hourly valid time (+5 h 30 m) -- rendered by the built-in
production engine (gpuwm render).
Significant Tornado Parameter on the 3 km domain at +6 h from the same
run. The full catalog is 324 products (severe suite, isobaric charts,
surface fields, accumulations); gpuwm render --list-products shows
what any given file supports. The compute-expensive ECAPE family is
opt-in via --heavy.
Feature matrix
| Area | Shipped in this release |
|---|---|
| Dynamics | WRF-ARW-class RK3 split-explicit core, FP32, CUDA; one-way static nests on Lambert-conformal, Mercator, or polar-stereographic grids |
| Microphysics | Kessler, WSM6, Thompson (default; WRF tables SHA-256-pinned -- the two largest ship as release assets and gpuwm fetch-tables stages whichever are absent, run automatically by install), Morrison 2-moment, NSSL 2-moment |
| PBL / surface layer | YSU + MM5 (classic); MYNN PBL + MYNN surface layer (coupled pair) |
| Land surface | Noah (4-layer), Noah-MP, RUC (9-level) |
| Radiation | RTE+RRTMGP (default); legacy RRTMG (WRF 4/4 transcription, verification tier); Dudhia SW |
| Cumulus | Kain-Fritsch (outer domains) |
| Data | ERA5 (CDS), GFS 0.25-deg (NOMADS), HRRR (NOMADS or AWS S3, incl. a live-cycle --wait-for mode) all initialize a run; GDAS 0.25-deg (NOMADS) is fetch and decode only through f009 -- no initialization route (rw-wps --source gdas refuses). Fail-closed Rust GRIB bridges; gpuwm fetch download front door. Plus an experimental, not-yet-stock-WRF-gated 20CRv3 ensemble-member route for GRIB2 files you supply yourself (no fetch route) -- see DATA.md |
| Domains | gpuwm domain wizard: point + card -> sized experiment TOML (16/24/32 GiB tiers) |
| Products | gpuwm render, two engines: vendored Rusty Weather renderer (default when built), whose vendored catalog carries 324 entries; the runtime lister enumerates 151 of them as implicit-render candidates per file (the rest are explicit-opt-in ensemble/probabilistic families) -- reflectivity composite/1 km, surface T/Td/RH/MSLP/wind/PWAT/cloud-cover families, the 200-850 mb isobaric charts (height/temp/dewpoint/RH/absolute-vorticity + winds), CAPE/CIN/SRH/shear/STP severe suite, heavy ECAPE family (--heavy), and multi-hour windowed accumulations -- everything a file's stored fields prove out renders (measured on the committed 3 km UH-smoke case: 58/58 on a single frame, 238 renders / 0 failures across its four-frame store, transcripts retained in the development tree under evidence/render-receipts/; --list-products prints the per-file verdict with a field-level reason for every unavailable row), with coast/state/county basemaps and sub-hourly leads stamped; matplotlib fallback (composite reflectivity, T2, 10 m wind, accumulated precipitation); --pair A B composes two runs' PNGs into labeled comparison sheets |
| Lifecycle | check (input + VRAM preflight), run, resume, restart checkpoints, failure capsules |
| Downscaling | gpuwm downscale: offline finer nest from archived gpuwm or WRF history (ndown-class) |
| WRF interop | rw-wps emits wrfinput/wrfbdy consumed by unchanged WRF v4.6.1 (see boundaries) |
| Namelists | gpuwm import-namelist: WRF namelist pair -> experiment TOML with an explicit substitution report |
Limits
Stated plainly, up front:
- Projection and location. Lambert conformal (both hemispheres), Mercator, and polar stereographic (both poles) run end to end -- wizard, config, static build, ERA5/GFS ingest, native WRF export -- and antimeridian-crossing domains are supported. What remains refused: domains containing or touching a pole (the lat-lon source interpolation and static-tile windowing are not pole-capable), and forcing footprints wider than 180 degrees of longitude. Latitude-longitude (cylindrical) and rotated grids stay unsupported and fail closed.
- Projection maturity. The new projections (Mercator, polar
stereographic, southern-hemisphere Lambert) are oracle-verified and
smoke-run verified -- transcription gates at binary64 against a
Fortran oracle built from the pinned WRF v4.6.1
share/module_llxy.F, plus short GPU smoke integrations -- not matched-run verified. The deep matched-run validation (the 1974 reference family) exists for northern-hemisphere Lambert only. - Nesting. Static nests. Children may start later on an exact
parent-step and forcing-cadence seam. One-way is the supported
default; two-way feedback (
feedback = 1) ships as an EXPERIMENTAL path -- it runs, it is stamped as experimental in the run's own provenance, and one-way consumers refuse a feedback-modified parent. It feeds back dynamic state only, where WRF also feeds back hundreds of masked land-surface fields, so it is not a WRF-equivalent claim. No moving nests, no vertical refinement, no adaptive time step. - Precision. The model state is FP32 (like WRF's default REAL). No end-to-end bit-identity with WRF is claimed anywhere; see VERIFICATION.md for exactly what is claimed.
- No data assimilation. Cold starts from public analyses only; no observation ingest, no cycling, no ensemble machinery.
- Data routes. All three sources drive ArWen GPU forecasts; they
differ in which door they use AND in which command runs the
forecast. ERA5 uses the config door:
[case_data]in the experiment TOML, read directly bygpuwm run. GFS and HRRR use the preprocessor door:rw-wpsconverts them towrfinput/wrfbdy, which drive unchanged stock WRF andgpuwm downscale-- and which reach the ArWen GPU loop throughtools/prepared_single_domain_forecast.py(one domain) ortools/prepared_domain_tree_forecast.py(a nest ladder), not throughgpuwm run, which refuses a config with no[case_data]table. The complete GFS command sequence, in the order that works, is FIRST-LIGHT.md § 3a. Each step prints the next one with its digests filled in. HRRR remains CONUS (Lambert) only; worldwide points use GFS or ERA5, both global. - Verification depth. One case (3 April 1974, ERA5, four domains to 500 m) is deeply validated against WRF v4.6.1; other configurations inherit component-level evidence only. Physics options carry explicit per-option maturity labels (PHYSICS.md).
- Platforms. Developed and measured on Windows 11 + RTX 5090 and on Linux CUDA 12.x nodes. The sealed Windows archive is CPU-preprocessing only; Windows CUDA is exercised via the developer checkout.
Verification
ArWen is gated against WRF v4.6.1 (commit d66e442f) at three levels:
bit-level kernel oracles against unmodified WRF Fortran, t=0
initialization parity, and matched-run forecast comparisons. A sample
of the measured results:
| Gate | Scope | Measured result |
|---|---|---|
| t=0 parity | 4 domains, 3 Apr 1974 case | T2 MAE 0.000 K, corr 1.000 on every domain vs the WRF initial state |
| Matched 6 h forecast | d02 (3 km), 15Z | composite refl corr 0.985; >=20 dBZ echo area within 3 pixels of WRF's 14,227 |
| Matched 6 h forecast | d03 (1 km), 18Z | T2 MAE 0.347 K; refl corr 0.715 (convective-scale chaos floor; see the page) |
| Component oracles | legacy RRTMG LW/SW engines | max ULP 0 vs the transcription oracle over the full fixture decks |
| Determinism | mid-run kill + relaunch | regenerated output frames SHA256-identical |
What these numbers mean, what is deliberately not claimed, and how to reproduce them: VERIFICATION.md.
Documentation
- First light walkthrough
- Verification
- Physics options and maturity
- Configuration knobs (WRF namelist parity)
- Getting data
- Hardware and VRAM sizing
- Offline downscaling
- Driving stock WRF
- Install and verify
- CLI reference
- Arbitrary but verified GRIB adapters
- Migrating from WPS
- Community support matrix
Credits and provenance
ArWen was designed and directed by its author and implemented with substantial use of AI coding agents (Anthropic's Claude, including Claude Fable 5, with auditing by OpenAI models). All model code was gated by verification against WRF v4.6.1 -- bit-level kernel oracles, matched-run comparisons, and adversarial review -- rather than accepted on generation. The verification methodology and its results are documented in VERIFICATION.md.
The transcription authority for every WRF-derived mechanism is WRF
v4.6.1; deliberate deviations are registered in
PROVENANCE.md. Radiation data files derive from AER's
RRTMG and the RTE+RRTMGP project; rendering uses the wrf-rust
package. See NOTICE for third-party acknowledgments.
License
Apache License 2.0 (LICENSE). Third-party datasets, tables, vendored components, and dependencies retain their own terms (NOTICE).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gpuwm-1.1.2.tar.gz.
File metadata
- Download URL: gpuwm-1.1.2.tar.gz
- Upload date:
- Size: 78.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c7b56ef8e762789cf5aee77a172bc0b5a72952cf7846393e196bcddb90a079a
|
|
| MD5 |
647bdf76ba480c5a9618180957751be1
|
|
| BLAKE2b-256 |
ac647c19b0d1420e2720552da022b1c825abe96b3eb8c0e8945a1e0bfcc98f65
|
Provenance
The following attestation bundles were made for gpuwm-1.1.2.tar.gz:
Publisher:
publish.yml on FahrenheitResearch/arwen
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gpuwm-1.1.2.tar.gz -
Subject digest:
9c7b56ef8e762789cf5aee77a172bc0b5a72952cf7846393e196bcddb90a079a - Sigstore transparency entry: 2292606567
- Sigstore integration time:
-
Permalink:
FahrenheitResearch/arwen@e2a1ba27ec45e4f69e2831f199064a7e479aa89d -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/FahrenheitResearch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e2a1ba27ec45e4f69e2831f199064a7e479aa89d -
Trigger Event:
release
-
Statement type:
File details
Details for the file gpuwm-1.1.2-py3-none-any.whl.
File metadata
- Download URL: gpuwm-1.1.2-py3-none-any.whl
- Upload date:
- Size: 77.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71930732ac05091e2040cfe633a2004a55a37234e2985cc79ff6099fb859f622
|
|
| MD5 |
1ae992574e1dd93e048017f7d9a8ae87
|
|
| BLAKE2b-256 |
78a204f0529ec5b11b321af92d9903dc77c405c4a38b7c6c90c43ce38ab7efba
|
Provenance
The following attestation bundles were made for gpuwm-1.1.2-py3-none-any.whl:
Publisher:
publish.yml on FahrenheitResearch/arwen
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gpuwm-1.1.2-py3-none-any.whl -
Subject digest:
71930732ac05091e2040cfe633a2004a55a37234e2985cc79ff6099fb859f622 - Sigstore transparency entry: 2292606610
- Sigstore integration time:
-
Permalink:
FahrenheitResearch/arwen@e2a1ba27ec45e4f69e2831f199064a7e479aa89d -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/FahrenheitResearch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e2a1ba27ec45e4f69e2831f199064a7e479aa89d -
Trigger Event:
release
-
Statement type: