Skip to content

Faithful model reproductions across all hazards (WIP, 2.0.0) - #36

Draft
XueqiC wants to merge 54 commits into
mainfrom
faithful-wildfire
Draft

XueqiC wants to merge 54 commits into
mainfrom
faithful-wildfire

Conversation

@XueqiC

@XueqiC XueqiC commented Oct 7, 2026 •

Copy link
Copy Markdown

PR Type

  • Model contribution
  • Non-model change

Model Summary

Work in progress: replace the compact stand-ins with faithful reproductions of the original papers, each verified against its pinned reference implementation (tests/oracle) or, when no code was released, rebuilt from the paper. Supersedes #33 and #34.

WildfireSpreadTS baselines, ported to plain PyTorch with the reference parameter names:

  • logistic_regression: Conv2d(C, 1, 3) pixel classifier (WildfireSpreadTS; same model as NDWS LR), 361 parameters at 40 channels.
  • resnet18_unet: re-implementation of smp.Unet("resnet18") from segmentation_models_pytorch 0.3.2, 14,444,241 parameters.
  • convlstm: utae-paps / MTLCC ConvLSTM with the head on the last cell state, 240,449 parameters.
  • utae: U-TAE + L-TAE from utae-paps, 1,099,011 parameters; the official PASTIS checkpoint loads with strict=True.
  • wildfirespreadts: now builds any of the four with the benchmark configuration (breaking change for that name).

CNN-ASPP:

  • wildfire_aspp (alias wildfire_cnn_aspp): rebuilt from Marjani et al., IEEE GRSL 2024, Section II-C and Fig. 2 (no code released), 274,657 parameters for 12 channels. The previous network did not match the paper.

Further faithful ports (each with oracle tests against the pinned reference):

  • wildfire_forecasting: the LSTM (29,652) and ConvLSTM (372,212) danger classifiers of Kondylatos et al., GRL 2022 (Orion-AI-Lab, MIT); task is now classification (breaking change), with a synthetic daily danger dataset for smoke runs.
  • swin_unet (27,224,964 at 40 channels) and the real asufm (35,047,840 / 35,057,056; now 64x64 next-day fire-mask segmentation, breaking change).
  • segformer: MiT-B0..B5 ported from transformers 4.57.6 (Apache-2.0); NVIDIA checkpoints load strictly but are non-commercial and not bundled.
  • attention_unet: MONAI 1.3.2 AttentionUnet including the TS-SatFire variant (shared (1,2,2) strides, 94,555,506 parameters at 43 channels); tcn: Bai et al. 2018 TemporalConvNet.
  • firecastnet: the real FireCastNet (Michail et al., Sci. Rep. 2025), a GraphCast-style encoder-processor-decoder on an icosphere multimesh in plain PyTorch (no DGL); the official Hugging Face checkpoints load strictly and give identical outputs on the global 0.25-degree grid (9,087,568 parameters).
  • prithvi_burnscars and prithvi_eo_2_tl: Prithvi-EO-2.0 300M BurnScars / TL with TerraTorch 0.99.8 necks and decoder; official weights give identical logits on the released example chip.

Third batch (sequence models, segmentation baselines, classical baselines):

  • earthformer: official CuboidTransformer (Apache-2.0) with the SEVIR / ICAR-ENSO checkpoints (Internet Archive copies of the 403'd S3 files); the paper's 15.1M / 7.6M counts are reproduced from the paper's depth settings and explained in the card.
  • earthfarseer (157,518,863) and rainformer (187,661,990): written from the papers (official repos unlicensed, used as test oracles); the official KNMI Rainformer weights load strictly.
  • swinlstm (official Moving-MNIST weights), convgru (the FireCastNet ConvGRU baseline), trajgru (HKO-7 encoder-forecaster, checked against the official MXNet code with released weights).
  • unet3d, unetr, swin_unetr (MONAI 1.3.2 ports with TS-SatFire's modifications) and the ts_satfire preset; Table 3 parameter counts match except UNETR-3D, whose 34.8M is the AF/BA configuration (explained in the card).
  • unet: the original Ronneberger U-Net rebuilt from the paper (31,030,658), checked against the authors' Caffe release weights; deeplabv3: smp DeepLabV3 as used by Shadrin et al. 2024.
  • random_forest (Kondylatos et al. official notebook configuration), xgboost (defaults; hyperparameters pending the paper's SI), deep_ensemble (Lakshminarayanan et al.; the 10 released Kondylatos 2025 ensemble members load strictly).

Simulators:

  • The forefire and wrf_sfire registry entries were fixed 3x3 diffusion kernels, not the simulators; they are removed. pyhazards.simulators.ForeFireSimulator now drives the real ForeFire engine (GPL-3.0, user-installed pip install forefire, imported lazily) and reproduces the official tests/runff reference output; the wrf_sfire_spread dataset reads WRF-SFIRE wrfout fire-grid fields, checked on the official hill case. Appendix A lists both as external simulators.

Salvaged from #33 (credit: runyangxu): the Track-O real-data wildfire occurrence pipeline (three datasets, cache builder, baseline runner, wired to the faithful models; fixes a south-north flip in the LANDFIRE fuel alignment and replaces unpublished Prithvi-WxC inputs with public MERRA-2) and nine corrected reference cards for external sources (FRAP, GeoMAC, GOES-R FDCF, HMS smoke, HRRR, LandScan, NDFD, SNODAS, Wildfire Risk to Communities).

Prompted multimodal-LLM baselines (replacing #33's prompted "models"): pyhazards.prompted implements the SmokeBench protocol (Qi, Li & Barnes, WACV 2026) with the paper's verbatim prompts, tiling/grid geometry, parsers and metrics, a FIgLib dataset adapter using SmokeyNet's released boxes, and optional backends (Qwen2.5-VL, InternVL3, Idefics2 via transformers; Gemini, GPT-4o via official clients). A real Qwen2.5-VL-7B run on all 5,046 smoke images gave 0.375 accuracy vs 0.380 in the paper.

Earthquake, flood and tropical cyclone (an audit found all 19 models were stand-ins and several datasets random data):

  • Earthquake: real phase-picking task (per-sample probabilities, official pick extraction, P/S precision/recall/F1 and residuals as in the PhaseNet/EQTransformer papers); seisbench_waveforms reads SeisBench-format and STEAD/INSTANCE files (no SeisBench import); phasenet (268,443), gpd (1,741,003) and eqtransformer (371,639) ported from the MIT code and checked against the official TF/Keras models and weights (GPD reproduces the shipped Anza pick file exactly). eqnet and wavecastnet are marked experimental until ported.
  • Flood: streamflow task with per-basin NSE/KGE and the NeuralHydrology metric set; real CAMELS-US and Caravan readers; random-data WaterBench/HydroBench/FloodCastBench adapters removed; neuralhydrology_lstm (297,217), neuralhydrology_ealstm (208,641) and google_flood_forecasting (3,402,832, FloodHub weights) checked against NeuralHydrology/googlehydrology; the Kratzert et al. 2019 Table 2 is reproduced from the released runs. hydrographnet, floodcast, urbanfloodcast marked experimental.
  • Tropical cyclone: real IBTrACS, TCND and SHIPS readers; great-circle track error in km; tropicalcyclone_mlp, saf_net and tropicyclonenet restored to their original tasks and checked against the official code/checkpoints. hurricast, tcif_fusion and the FourCastNet/GraphCast/Pangu adapters marked experimental.
  • 11 wrong citations fixed (several DOIs pointed to unrelated papers).

Round 2 (other hazards):

  • Earthquake: wavecastnet ported from the official code (10,093,242; official dense checkpoint), eqnet rebuilt from the paper (backbone and picking heads checked against the official code; shift-and-stack paper-only).
  • Flood: hydrographnet ported from NVIDIA PhysicsNeMo (2,318,722, reproduces PhysicsNeMo's stored regression output), urbanfloodcast rebuilt from the paper with U-NO/FNO blocks (4,470,437, outputs equal the official code); floodcast stays experimental (no released code, paper underspecified).
  • Tropical cyclone: hurricast (encoder 2,969,914 + XGBoost) and tcif_fusion (299,611,263 notebook graph; 65-channel default per the paper) written from the papers and checked against the official code; FourCastNet / GraphCast / Pangu-Weather are now pyhazards.forecasts pipelines (TempestExtremes-equivalent tracker, ECMWF-style tracker, TCBench / WeatherBench 2 readers, earth2studio runner) that reproduce TCBench's published 2023 Pangu track errors exactly; the placeholder networks are removed.

Framework:

  • Model cards gain references and a reproduction block (source: code with an oracle test, or source: paper), rendered on every model page.
  • Wildfire spread metrics now include pixel average precision (the primary WildfireSpreadTS metric).
  • Benchmarks now score models in eval mode under no_grad (dropout was active during scoring).
  • The Oracle workflow runs nine reference stacks as a matrix (default, unet, swin, farseer-rainformer, tssatfire, firecastnet, earthformer, trajgru, prithvi).

Hazard Scenario

Wildfire, Earthquake, Flood, Tropical Cyclone

Registry Name

logistic_regression, resnet18_unet, convlstm, utae, wildfirespreadts, wildfire_aspp (alias wildfire_cnn_aspp), wildfire_forecasting, swin_unet, asufm, segformer, attention_unet, tcn, firecastnet, prithvi_burnscars, prithvi_eo_2_tl, earthformer, earthfarseer, rainformer, swinlstm, convgru, trajgru, unet3d, unetr, swin_unetr, ts_satfire, unet, deeplabv3, random_forest, xgboost, deep_ensemble, phasenet, gpd, eqtransformer, eqnet, wavecastnet, neuralhydrology_lstm, neuralhydrology_ealstm, google_flood_forecasting, hydrographnet, floodcast, urbanfloodcast, tropicalcyclone_mlp, saf_net, tropicyclonenet, hurricast, tcif_fusion, graphcast_tc, pangu_tc, fourcastnet_tc

Paper / Source

Smoke Test

Smoke specs in the model cards. Oracle tests: scripts/fetch_oracles.py then PYHAZARDS_ORACLE_DIR=... python -m pytest tests/oracle (passing locally and in the Oracle workflow): identical seeded initialisation and parameter names, forward outputs in eval and train mode, padded dates, official PASTIS weights, ImageNet stem adaptation. CNN-ASPP: tests/test_cnn_aspp.py checks the paper's layer widths, dilation rates and parameter count.

Parity Notes

  • ConvLSTM reads the spatial size from the input instead of fixing it at construction (identical outputs at the reference size); head padding is kernel_size // 2 (identical for 3x3).
  • U-TAE skips the reference's extra all-zero forward pass used only to read output shapes (no effect with GroupNorm). As in the reference, the output block ends in BatchNorm + ReLU.
  • CNN-ASPP returns logits (the paper's last layer applies a sigmoid); branch concatenation order, padding and initialisation are not stated in the paper (PyHazards: dilation order, size-preserving zero padding, Keras defaults).

🤖 Generated with Claude Code

Xueqi Cheng and others added 30 commits October 7, 2026 17:01
Replace the Conv3d stand-in registered as `wildfirespreadts` with the four
learned baselines of the WildfireSpreadTS benchmark (Gerard et al., NeurIPS
2023 D&B), each ported to plain PyTorch with the reference parameter names:

- logistic_regression: Conv2d(C, 1, 3) pixel classifier (361 params @ 40 ch)
- resnet18_unet: smp 0.3.2 Unet("resnet18") re-implementation (14,444,241)
- convlstm: utae-paps / MTLCC ConvLSTM, head on last cell state (240,449)
- utae: U-TAE + L-TAE from utae-paps (1,099,011; PASTIS weights load strict)

`wildfirespreadts` now builds any of them with the benchmark configuration
(baseline="utae" by default). This is a breaking change for that name.

Model cards gain `references` (wildfire papers that used a model) and a
`reproduction` block (reference code, commit, license, checked config,
parameter count, checks, deviations), rendered on each model page; models
without one say they are not yet verified.

tests/oracle compares each port with its pinned reference: identical seeded
initialisation and parameter names, forward outputs in eval and train mode,
padded dates, and the official U-TAE PASTIS checkpoint. References are pinned
in tests/oracle/repos.yaml, fetched by scripts/fetch_oracles.py, and run by
the new Oracle workflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous `wildfire_aspp` / `wildfire_cnn_aspp` network (32-channel BN stem,
DeepLabV3-style ASPP with a 1x1 branch, image pooling and projection) did not
match the paper. Rebuild it from Section II-C and Fig. 2: conv 64 -> conv 128,
four 3x3 atrous branches (32 filters, dilation 1/3/6/12) concatenated, conv 32
-> conv 32 -> BatchNorm -> 1x1 conv, all at 64x64; 274,657 parameters for the
12 NDWS channels. No code was released, so the card is `variant` with a
paper-sourced reproduction block (new `source: paper` option).

TverskyLoss keeps the Salehi et al. convention (alpha on FP, beta on FN); the
docstring and the NDWS training script now state that the paper's setting is
alpha=0.3, beta=0.7 and default to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/ ConvLSTM

Replace the GRU + attention weekly-count forecaster registered as
`wildfire_forecasting` with the two deep models of Kondylatos et al.,
"Wildfire Danger Prediction and Understanding With Deep Learning" (GRL 49(17),
e2022GL099368), ported from Orion-AI-Lab/wildfire_forecasting @ 2b18bcf (MIT):

- variant="lstm" (default): SimpleLSTM, LayerNorm(25) -> LSTM(25, 64) ->
  last step -> Linear 64-64-32-2, ReLU, dropout 0.5 -> log_softmax
  (29,652 parameters), input (batch, 10, 25)
- variant="convlstm": SimpleConvLSTM, per-pixel LayerNorm -> ConvLSTM(25, 32,
  3x3) -> last hidden state -> conv3x3 + ReLU + maxpool2 -> Linear
  4608-64-32-2 -> log_softmax (372,212 parameters), input (batch, 10, 25, 25, 25)

Both keep the reference parameter names (including SimpleLSTM's duplicate
fc_nn registration) and initialisation order and return log-probabilities as
the reference does. Breaking change: the entry is now task="classification"
on daily sequences / patches instead of weekly FPA-FOD counts.

tests/oracle/test_wildfire_forecasting_oracle.py imports the official
fire_modules.py with fastai (and torchvision when absent) stubbed, since both
imports are unused; Lightning/Hydra are not needed. It checks parameter
counts, seeded initialisation and parameter names, forward outputs in eval
and train mode, a non-paper configuration, and the reference ConvLSTM against
pyhazards.models.convlstm.ConvLSTM.

Adds the synthetic `wildfire_danger_synthetic` dataset (temporal and
spatiotemporal access modes, 2:1 negatives) for the smoke config, drops the
model from the FPA-FOD weekly dataset card, cites the GRL paper with its
Table 1 F1 on the card, and annotates the Appendix A entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Average precision over pixels is the primary WildfireSpreadTS metric (paper
Table 5, torchmetrics AveragePrecision); add it to the wildfire spread
metrics next to IoU, F1 and burned-area MAE, with a test against sklearn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…LSTM

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…acle tests

Add `segformer`, a plain-PyTorch port of Hugging Face transformers 4.57.6
models/segformer/modeling_segformer.py (Apache-2.0). The official NVlabs code
(NVIDIA non-commercial license) was not used.

- Same module/parameter names as transformers <= 5.8 and the Hub checkpoints:
  SegformerForSemanticSegmentation state dicts load into SegFormer, and
  SegformerModel / nvidia/mit-b* (prefix "segformer." stripped, ImageNet
  classifier dropped) into SegFormer.segformer, all with strict=True.
- Same construction and _init_weights order, so seeded initialisation is
  bit-identical; eval and train (drop path, dropout) outputs match exactly.
- variant b0..b5; decoder width 256 (B0/B1) or 768 (B2-B5). Parameter counts
  equal transformers and paper Table 1 (B0 3,752,694; B2 27,461,974 at 150
  classes); the WSTS+ B2 configuration (40 channels, 1 class) has 27,463,425.
- forward() upsamples the 1/4-resolution logits to the input size (bilinear,
  align_corners=False); raw_logits() / upsample=False keep the HF output.
- encoder_weights="imagenet" downloads the revision-pinned nvidia/mit-<variant>
  checkpoint via torch.hub (sha256 prefix checked) and adapts the stem to
  other channel counts with smp's patch_first_conv rule. No new dependency.

Card cites WSTS+ (Lahrichi et al., WACV 2026, arXiv 2502.12003) and notes the
non-commercial NVIDIA weights. Oracle tests pin transformers==4.57.6 (it
co-installs with smp 0.3.2 / timm 0.6.12) and two Hub checkpoints
(nvidia/mit-b0, nvidia/segformer-b0-finetuned-ade-512-512) by sha256.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add `swin_unet` (Swin-Unet-Tiny, Cao et al., ECCVW 2022) as used by the
WSTS+ wildfire benchmark (Lahrichi et al., WACV 2026), and replace the
`asufm` stand-in with the real ASUFM of Li & Rad (IEEE CAI 2024): an
Attention Swin U-Net with focal modulation for next-day fire-mask
segmentation on 64x64 NDWS tiles.

- swin_blocks: Swin blocks ported from microsoft/Swin-Transformer (MIT),
  focal modulation from microsoft/FocalNet (MIT), DropPath and
  trunc_normal_ with timm 0.4.12's random draws (torch 2.14's
  trunc_normal_ now uses rejection sampling). Swin-Unet decoder pieces are
  written from the paper; the official repo has no license.
- swin_unet: SwinTransformerSys parameter names and creation order,
  27,224,964 params at 40 ch / 1 class, 27,168,900 at 3 ch / 9 classes;
  pretrained="imagenet" reproduces the official load_from (Swin-T into
  encoder and mirrored decoder), checkpoint sha256-pinned.
- asufm: fire-asufm get_asfum_6/get_asufm_12 configs, 35,047,840 /
  35,057,056 params, official quirks kept (double skip fusion, unused
  decoder modulation and stem); assembled from MIT blocks because the
  fire-asufm model package derives from the unlicensed AttSwinUNet.

BREAKING: `asufm` was a weekly FPA-FOD count forecaster; it is now a
segmentation model. Its smoke config moves from wildfire.danger to
wildfire.spread on the synthetic spread dataset at 64x64, and it is no
longer linked from the fpa_fod_weekly dataset card.

tests/oracle/test_swin_oracle.py compares both ports with the pinned
official code (Swin-Unet f48f623, fire-asufm 688dda9): identical seeded
initialisation and parameter names, forward outputs in eval and train
mode, and the Swin-T ImageNet initialisation. Its stack (timm 0.4.12)
conflicts with smp 0.3.2, so it gets requirements-swin.txt and its own
entry in the Oracle workflow matrix; a CI test checks that every oracle
test is listed in the matrix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
attention_unet: plain-PyTorch port of MONAI 1.3.2 AttentionUnet (Apache-2.0)
with MONAI's module names and creation order, so MONAI state dicts load
strict and seeds give identical weights. Supports spatial_dims 1/2/3 and
per-level strides that may differ per dimension; stride_mode="shared"
reproduces TS-SatFire's modified copy (one stride, (1, 2, 2), at every level).
TemporalAttentionUnet takes (B, T, C, H, W) and averages the 3D logits over
time as TS-SatFire's prediction script does. Defaults are TS-SatFire's
Attention-U-Net-3D (94,555,506 params at 43 channels); spatial_dims=2 gives
its 2D baseline (31,743,282 at 8 channels). The card cites Oktay et al. and
lists how MONAI's gate differs from the official grid-attention network,
which is not ported.

tcn: port of locuslab/TCN TemporalConvNet/TemporalBlock/Chomp1d (MIT) with
the linear heads of its examples (last-step or per-step readout) for
task='classification'/'regression' on (batch, time, features). Uses
parametrizations.weight_norm; official weight_g/weight_v state dicts load
strict and to_official_state_dict converts back. Defaults are the official
adding-problem model (96,001 params). WildfireIA's TCNClassifier is listed
as a reference with a note that it is a different network.

Oracle tests compare seeded initialisation, parameter names and outputs in
eval and train mode against MONAI 1.3.2, TS-SatFire's file (no license;
fetched at test time only) and the official TCN code, plus causality.
TS-SatFire and TCN are pinned in tests/oracle/repos.yaml and monai==1.3.2 is
added to tests/oracle/requirements.txt (coexists with smp 0.3.2). Both
models are linked from the wildfire benchmark card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
run_benchmark called Benchmark.evaluate on whatever mode the model was in, so
freshly built models were scored with dropout active and BatchNorm using
batch statistics, giving non-deterministic metrics. Switch to eval mode and
no_grad for scoring and restore the previous mode afterwards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…racle tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cle tests

Replace the 2D conv encoder-decoder registered as `firecastnet` (a spread-mask
stand-in unrelated to the paper) with FireCastNet (Michail et al., Scientific
Reports 16:1006, 2025): a Conv3d cube embedding (T x 4 x 4 patches, 64
channels, LayerNorm over the whole embedded cube) on the 0.25-degree global
grid, a GraphCast encoder-processor-decoder between a 1-degree grid and the
icosphere 0-6 multi-mesh (12 processor layers, hidden 64, sum aggregation),
and PixelShuffle(4) of 16 outputs per cell. Breaking change for this name:
input is now (B, T, C, lat, lon) on a configured lat/lon grid.

- Pure PyTorch: DGL message passing replaced by index_select/index_add_;
  GraphCast layers ported from the Apache-2.0 files of SeasFire/firecastnet
  (NVIDIA), graph construction from NVIDIA Modulus v0.5.0 (Apache-2.0); the
  unlicensed rest of the official repo is only a test oracle.
- Icospheres generated deterministically (PyMesh layout); the multimesh,
  grid2mesh and mesh2grid graphs equal the official ones bit for bit.
- Parameter names follow GraphCastCubeNet; official Lightning checkpoints
  load with strict=True via build_model(..., checkpoint=...) after
  stripping the LightningModule `_net.` prefix. 9,087,568 parameters.
- tests/oracle/test_firecastnet_oracle.py (own CI job, DGL 2.4 + CPU torch
  2.4): icosphere assets, graphs, seeded init, forward and gradients on small
  global configs, and the official global cls/regr ts24-h1 and AUST LAM
  checkpoints on the full 720 x 1440 grid (outputs equal).
- Smoke config uses a tiny 2.5-degree global grid; FireCastNet is removed
  from the WildfireSpreadTS ecosystem card (it is a SeasFire model).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cle tests

Add two registry models built from a plain-PyTorch port of the official
Prithvi-EO-2.0 code, with the reference parameter names and initialisation
order so the released checkpoints load with strict=True:

- prithvi_burnscars: Prithvi-EO-2.0-300M-BurnScars (ViT-L/16 encoder,
  SelectIndices[5,11,17,23] -> ReshapeTokensToImage ->
  LearnedInterpolateToPyramidal -> UNetDecoder[512,256,128,64] -> 2 classes),
  324,204,674 parameters. Logits on the HF example chip are identical
  (max |diff| 0) to TerraTorch 0.99.8 with the official checkpoint.
- prithvi_eo_2_tl: Prithvi-EO-2.0-TL encoder (time + location embeddings,
  variant 300m or 600m) wrapped in the official burn-scar head recipe; only
  the encoder is pretrained. 324,204,676 parameters for 300M-TL; the MAE
  port matches the official prithvi_mae.py with the 300M-TL weights.

Sources: prithvi_mae.py from the HF repos (Apache-2.0, IBM), TerraTorch
0.99.8 necks/decoder/head/pixel-wise model (Apache-2.0), smp 0.4.0 U-Net
decoder (MIT), timm 1.0.15 ViT block (Apache-2.0). TerraTorch 0.99.8 + smp
0.4.0 is the stack the checkpoint was trained with; smp >= 0.5 changes the
last U-Net block and this model's logits (documented in the card).

Weights are not bundled: pyhazards.models.prithvi downloads pinned files
(revision + sha256) from Hugging Face over HTTPS on demand and caches them
under torch.hub; weights_path= loads a local copy. No new dependency.

tests/oracle/test_prithvi_oracle.py checks the official config, seeded
initialisation, parameter names/counts and forward outputs against
TerraTorch 0.99.8 and prithvi_mae.py; two tests load the 1.3 GB
checkpoints and are skipped unless those `large: true` assets are fetched
(PYHAZARDS_ORACLE_LARGE=1 makes them mandatory). The reference stack is
pinned in tests/oracle/requirements-prithvi.txt and run by a new Python 3.12
`prithvi` job in the Oracle workflow. fetch_oracles.py skips large assets
unless named or --large is given.

Burn-scar mapping is post-fire mapping, so the models are not linked to the
wildfire benchmark's danger/spread tasks; the benchmark card says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…TCN with oracle tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… with official-weight oracle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…racle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… wildfire starter

The benchmark's multi-day U-Net runs set remove_duplicate_features, keeping the
20 static features (topography, land-cover one-hot) for the last day only: 120
input channels for 5 days and 14,695,121 parameters, the 14.7M of paper
Table 5. `wildfirespreadts` now does the same for the 40-feature layout, and
ResNetUNet takes `static_feature_ids` to flatten 5-D input that way. An oracle
test compares against FireSpreadDataset.flatten_and_remove_duplicate_features_.

The wildfire starter model on the catalog page is now `wildfirespreadts`; the
faithful FireCastNet needs the global SeasFire grid and is no quick start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the spatial-attention gap

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…emphasis

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ests

earthformer: plain-PyTorch port of the official CuboidTransformerModel
(amazon-science/earth-forecasting-transformer @ 7732b03, Apache-2.0,
cuboid_transformer.py + patterns + utils; attribution in the module
docstring). Parameter names, creation order and init modes are the
reference's, so its state dicts load strict and seeds give identical
weights. Presets are the official YAML model sections (sevir v1 =
8,659,677 params, sevir_lr, moving_mnist/nbody = 6,702,109, enso v1).
task="forecasting" maps (B, T, C, H, W) frames to frames;
task="segmentation" is the documented PyHazards next-fire-mask
adaptation (one frame, one channel, no key prefix). pretrained="sevir" /
"icarenso2021" loads the official checkpoints: the S3 bucket answers
403, so they come from the Internet Archive copies (sha256-pinned,
SHA-1 equal to the archived originals).

Paper/config count discrepancy resolved: the official class reproduces
the paper exactly with SEVIR enc/dec depth [2, 2] (paper Table 9) and
global vectors that share the local q/k/v and have no FFN (15,082,069 =
15.1M; 13,075,029 w/o global), Moving-MNIST with t+h+w embeddings
(6,611,997 = 6.61M; 7,610,781 = 7.61M) and ENSO at depth [4, 4]
(6.6M / 7.6M). The released v1 configs are smaller. Recorded in the card.

Oracle (new "earthformer" suite, einops 0.8.2): preset == YAML, counts
at official and paper configs, seeded init, eval/train outputs and
gradients for SEVIR (13x48x48, 13x50x50), Moving-MNIST (10x32x32), ENSO
and six other pattern/option sets, wrappers, and both official
checkpoints at full size. Linked from the wildfire benchmark card with
Sim2Real-Fire Table 2 numbers ("configuration not published").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…acle tests

unet: Ronneberger et al. (MICCAI 2015) rebuilt from the paper's Fig. 1 and
Sections 2-3: 64-1024 channels, unpadded 3x3 conv + ReLU, 2x2 max-pool, 2x2
up-convolutions, centre-cropped skips, 1x1 output, dropout 0.5 at the end of
the contracting path, N(0, 2/n) weights and zero biases; 31,030,658
parameters for 1 input channel / 2 classes, 572 -> 388 output, with
unet_output_size / unet_input_size helpers (valid sizes are 16k + 60, k >= 8)
and padding="same" for fixed-size tiles. The authors' Caffe release (no
license) is not copied; it is a test-time oracle. Modules carry the Caffe
layer names, and variant="phseg_v5" builds the released network (ReLU after
each up-convolution, 128-channel last up-convolution; 31,100,354 params).
The oracle reads phseg_v5.caffemodel with a small protobuf reader, loads it
strict, checks every prototxt layer and the release's patched Gaussian
filler, and matches OpenCV 4.10's Caffe runtime (max abs diff ~1e-5) on a
random 572x572 tile and on a tile of the release's sample image. New oracle
suite "unet" (opencv-python-headless==4.10.0.84; OpenCV 5 dropped the Caffe
importer); asset unet_release pinned by sha256. Card: variant, source: paper.

deeplabv3: Shadrin et al. (Sci. Rep. 14:2606, 2024) describe DeepLabV3 in
smp's terms ("encoder backbone ResNet18, number of stages used in encoder
equals to 3 ... default values") and report smp's micro-imagewise metrics,
so this ports smp 0.3.2 DeepLabV3 (MIT; ASPP file from torchvision, BSD-3)
to plain PyTorch with smp names, creation order and initialisation (smp
never calls initialize() for DeepLabV3). The ResNet encoder is shared with
resnet_unet.py, which gains smp's make_dilated / output_stride and a shared
ImageNet loader. Builder defaults are Shadrin's: ResNet-18, depth 3, 58
channels on 32x32 tiles (13,220,609 params, 2,727,169 used in forward).
smp's DeepLabV3 code is identical from 0.2.0 to 0.3.4. Oracle (default
suite): seeded state dicts, conv geometry and eval/train outputs equal smp
for Shadrin's config, smp defaults and depths 4/5; ImageNet stem; decoder
equals torchvision's DeepLabHead. Card: core, citing Shadrin et al. with
their Table 3 F1 scores. Not DeepLabV3+.

Both are linked from the wildfire benchmark card (18 models); a paper-sourced
reproduction block can now name an unlicensed release used as an oracle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ith oracle tests

Add two Sim2Real-Fire sequence-forecasting baselines. Both official repositories have no
LICENSE, so the models are written from the papers and permissively licensed parts; the
official code is fetched only at test time as the oracle. Parameter names and creation order
follow the official models, so official state dicts load with strict=True and seeded
initialisation is identical.

earthfarseer (Wu et al., AAAI 2024; Alexander-wu/EarthFarseer 258d4bb): FoTF (global Fourier
transformer + local branch, 3 interactions), SimVP encoder/decoder, TeDev (Inception U-net with
12 AFNO blocks) and the fixed-size SimVP skip branch. Default Earthfarseer_model(shape_in=
(10, 1, 64, 64)): 157,518,863 parameters. Official quirks kept (unused fc2 and second encoder,
AFNO imaginary part from the updated real part, shared GF/LC blocks applied 7 times). The
official H % 3 token-grid rule (and odd N_S, non-square inputs) only differs where the official
forward fails; the port uses the true latent size. SimVP Inception/GroupConv2d follow OpenSTL
(Apache-2.0).

rainformer (Bai et al., IEEE GRSL 2022; Zjut-MultimediaPlus/Rainformer c4e04e9): Swin parts
ported from berniwal/swin-transformer-pytorch (MIT), CBAM local branch and gate fusion unit
from the paper. Official KNMI Net: 187,661,990 parameters. Stage sizes are derived from
img_size instead of the hard-coded 288x288 maps; window sizes that do not divide every stage
raise ValueError (256x256 with window 9 does; Sim2Real-Fire's change is unpublished). The KNMI
checkpoint downloads over plain HTTPS from Google Drive; it is pinned (sha256, large: true) as
test data only, and fetch_oracles.py gains an optional `filename` for URLs without one.

Both builders: task="forecasting" (frames -> frames, output length = input length) and the
documented PyHazards task="segmentation" adaptation (first predicted frame -> 1x1 conv logits,
core keys unchanged). Cards are core, linked from the wildfire benchmark (count 16 -> 18).

Oracle suite farseer-rainformer (timm 0.9.16, einops 0.8.2): CI compares reduced models
(Earthfarseer with only the hard-coded GF width/depth overridden in the official call;
Rainformer at 288x288 with narrow widths) for state dicts, seeded init, eval/train outputs,
gradients and BatchNorm statistics; default sizes and the KNMI weights run with
PYHAZARDS_ORACLE_LARGE=1 (all 13 pass locally, bit-identical).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…EVIR/ENSO weights oracle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inUNETR) with oracle tests

Port MONAI 1.3.2 UNet, UNETR and SwinUNETR (Apache-2.0) to plain PyTorch with MONAI's
parameter names and creation order, plus the modifications of TS-SatFire's copies
(zhaoyutim/TS-SatFire @ da75732, no license, used only as a test oracle):

- unet3d: MONAI UNet (incl. residual units) with TS-SatFire's shared (1, 2, 2) stride;
  31,712,970 params at 43 channels (Table 3: 31.7M), 10,552,458 for the 2D U-Net (10.6M).
- unetr: MONAI UNETR with TS-SatFire's patch_size (1, 16, 16), (1, 2, 2) up-sampling
  (kernel_size_up_down) and (1, 3, 3) decoder3 kernel; prediction-script widths (feature 16,
  hidden 384, MLP 1536): 28,816,866 params. Table 3's 34.8M is the AF/BA configuration
  (8 channels, feature 36: 34,806,506). Replaces the unmerged vit_segmenter.
- swin_unetr: MONAI SwinUNETR (merging, mergingv2, use_v2) with TS-SatFire's anisotropic
  patch/window, even-dimension patch merging, Swin-V2 attention option and out.0 naming;
  33,191,942 params with feature 36 and 3 heads (Table 3: 33.2M). The autoregressive
  attention is not ported (the prediction script hard-codes v1).
- ts_satfire: preset building the four prediction baselines as in
  run_spatial_temp_model_pred.py (default SwinUNETR-3D), (B, T, 43, H, W) -> time-averaged
  (B, 2, H, W) logits; card cites TS-SatFire with its correct title.

Oracle tests (new "tssatfire" suite: monai 1.3.2, einops 0.8.0, torchinfo 1.8.0) check
parameter counts, names, seeded initialisation and eval/train outputs against both stock
MONAI and TS-SatFire's files. Registry entries, cards, benchmark links and docs updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p DeepLabV3 (Shadrin et al. 2024)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rapper with oracle tests

random_forest / xgboost (pyhazards/models/classical.py): EstimatorModule is an
nn.Module holding a scikit-learn-compatible estimator. It is fitted with
model.fit(inputs, targets), raises NotFittedError before that, returns
(batch, n_classes) log-probabilities (log of predict_proba) or regression values
as tensors, has an empty state_dict and saves/loads with joblib (trusted files
only). Daily (batch, 10, 25) tensors of wildfire_forecasting are turned into the
35 instance features of Kondylatos et al. (GRL 2022) by
kondylatos_instance_features, as notebooks/RF.ipynb builds them.
random_forest is the notebook's RandomForestClassifier(100 trees, depth 10,
random_state 123); the oracle test executes the notebook's own cells on
synthetic data (served like FireDataset_npy) and requires identical features,
probabilities and labels. xgboost is an optional extra (pyhazards[xgboost]),
imported lazily, with XGBClassifier library defaults (checked against xgboost
3.2.0) because the paper's values are in its unread Supporting Information:
catalog_status variant, reproduction source paper.

deep_ensemble (pyhazards/models/deep_ensemble.py): M members (default 5) of any
registered model, member m built after torch.manual_seed(seeds[m]); uniform
mixture (log mixture probability, logit for one-channel binary outputs, a
moment-matched (mean, variance) for Gaussian or point regression members);
predict_uncertainty gives epistemic / aleatoric / entropy / mutual information
as in uncertainty-wildfires; optional MC-dropout passes; fit() trains members
independently with member-seeded shuffling and optional FGSM adversarial
examples (epsilon = 1% of each input range). The oracle loads the ten released
ensemble LSTMs of Kondylatos et al. (2025) into wildfire_forecasting members
(hidden 128) with strict=True and matches the reference SimpleLSTM,
seeded initialisation and uncertainties(), also with test-time dropout.

Trainer.fit raises TypeError for models declaring custom_fit_reason (these
three); evaluate/predict work. SmokeTestSpec gains optional `fit` (random
training data fitted before the forward call) and `requires` (skip when an
optional package is missing). Oracle default suite: + uncertainty-wildfires,
xgboost-cpu==3.2.0, two new test files; models linked to the wildfire
benchmark family.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om the papers, official-code oracles

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tfire preset (MONAI 1.3.2 ports)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…acle tests

- swinlstm: SwinLSTM-D/B (Tang et al., ICCV 2023) ported from SongTang-x/SwinLSTM @ 4425bcf (MIT),
  reusing swin_blocks (new _window_attention hook). The released Moving-MNIST SwinLSTM-D weights
  (20,191,969 params) load strictly; rollouts, seeded init and train mode match the official code.
  task="forecasting" frames->frames, task="segmentation" one-step logits (PyHazards adaptation).
- convgru: FireCastNet's Conv-GRU baseline (Ballas et al. cell), written from the equations since
  SeasFire/firecastnet has no licence; ConvGRUSeg is the test oracle (1,337,985 params, config
  hidden 128; paper's 64 -> 361,793). Segmentation only, as in the reference.
- trajgru: HKO-7 encoder-forecaster (Shi et al., NeurIPS 2017) ported from sxjscience/HKO-7 @
  57b987b (MIT, MXNet), with the paper's ConvGRU baseline via layer_type. Verified on MXNet 1.9.1
  against the official networks and released HKO-7 / MovingMNIST++ checkpoints (9 configurations).
- Oracle matrix: convgru in default, swinlstm in swin, new trajgru suite (mxnet 1.9.1, numpy 1.23.5).
- Cards, docs, wildfire benchmark links (19 models).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p ensemble wrapper

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Xueqi Cheng and others added 15 commits October 7, 2026 19:17
…7 MXNet oracle)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rop the fake simulator models

`forefire` and `wrf_sfire` were registered as core models but were fixed 3x3 diffusion kernels over
sigmoid/tanh input channels, unrelated to either simulator. Both are removed from the model
registry, model cards, smoke configs and benchmark links. They are physics simulators, so their
faithful form is an interface to the official software:

- pyhazards.simulators.ForeFireSimulator drives the official ForeFire engine through its Python
  bindings (`pip install forefire`, checked with 2.5.0). ForeFire is GPL-3.0: it is imported lazily,
  never vendored and not a dependency. Rasters (fuel codes, altitude, wind fields or ForeFire
  direction-coefficient fields with wind triggers, ignition mask or points) become ForeFire layers
  with the calls of the official Python examples; the result is ForeFire's burning map (arrival
  time, burned masks) plus its reduction to the output grid. Each run is a fresh process by
  default, because ForeFire keeps parameters in a process-wide singleton.
- tests/oracle/test_forefire_oracle.py (new `forefire` suite): fed the rasters, parameters,
  ignitions and wind change parsed from ForeFire's own regression case tests/runff, the adapter
  reproduces the reference arrival-time map ForeFire.0.nc.ref within the case's compare_nc.py
  tolerance with the same burned cells; and it reproduces the official
  tests/python/idealizedwind.py run bit for bit.
- pyhazards.datasets.wrf_sfire reads the fire grid of WRF-SFIRE wrfout files (TIGN_G, LFN,
  FIRE_AREA, FGRNHFX, ROS, ...; names, subgrid padding and TIGN_G semantics from the official
  Registry/registry.fire and SFIRE source of W4.4-S0.1) into north-up spread rasters; registered
  as the `wrf_sfire_spread` dataset with a dataset card and an inspection CLI. Checked on a real
  wrfout of the official ideal case test/em_fire/hill (WRF-SFIRE W4.4-S0.1 built locally); its
  header is kept as tests/fixtures/wrf_sfire_hill_wrfout_header.json and the unit tests write
  synthetic files with exactly that layout.
- Appendix A gains a minimal `external` status ("External simulator") with doc links instead of
  model mappings; ForeFire and WRF-SFIRE use it. New docs page pyhazards_simulators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der replace the fake models

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd runner from PR #33

Salvages the real-data wildfire pipeline of PR #33 ("Doc/Source and PyHazards",
runyangxu, commit ffc68a1): pyhazards/datasets/wildfire/real_track_o_2024.py and
pyhazards/benchmarks/wildfire_benchmark/{cache_builder,real_runner}.py. The dataset
reader and the cache builder are adapted from runyangxu's code; the runner is rewritten
around the current registry.

Kept and fixed:
- wildfire_track_o_{raster,temporal,tabular} datasets (pyhazards/datasets/wildfire/
  track_o.py): cache_dir is required instead of a /home/runyang default; NaN-aware
  train-split standardisation (MERRA-2 land variables are NaN over the ocean); exact
  day of year; temporal windows skip missing days; a too-small grid raises instead of
  silently breaking the spatial multiple; tabular labels are int64; micro=True gives a
  small synthetic cache for smoke runs.
- Cache builder (pyhazards/datasets/wildfire/track_o_cache.py, CLI
  scripts/build_wildfire_track_o_cache.py): reads any NetCDF weather on a regular grid
  (several files per day, time averaged), so public MERRA-2 files replace PR #33's
  unpublished Prithvi-WxC outputs; FIRMS CSVs grouped by acq_date with type 0 kept;
  points outside the grid dropped instead of piled on the border; days streamed.
- Fuel alignment: PR #33 wrote gdalwarp's north-up output onto a south-to-north grid,
  which put CONUS fuels at 22-52 S (reproduced with a synthetic Albers raster), and used
  cell-edge bounds that shifted it by half a cell. It now reprojects with rasterio
  (optional extra pyhazards[geo]) onto the cell edges, flips to the cache row order and
  excludes LANDFIRE's -9999 fill even under a 32767 nodata tag.
- Runner (scripts/run_wildfire_track_o_baselines.py) trains registry models
  (logistic_regression, unet with padding="same", convlstm, random_forest, xgboost) with
  PR #33's protocol and scores them with the wildfire benchmark plus Brier, NLL, ECE and a
  correct day-to-day change (PR #33 took diffs of sorted probabilities). Loss curves need
  the optional extra pyhazards[plot].
- wildfire.danger now scores per-cell danger maps (one logit per cell) and runs the model
  in batches on its device; Track-O smoke config, dataset card and benchmark-card note.

Dropped: the synthetic smoke adapter (it invented loss curves and metrics from a random
generator), the 22/20-model JSON catalogues (superseded by model cards), the experiment
schema/layout/artifact modules, the /home/runyang configs and plan, LightGBM (no
PyHazards model) and the benchmark-card removal of wildfire_forecasting.

Co-authored-by: runyangxu <runyanggg@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR #33 (runyangxu, commit ffc68a1) added 14 hand-written dataset pages that carried the
"generated" marker but had no cards, pointed their inspection commands at /home/runyang
copies, and linked every source to the wildfire benchmark although PyHazards does not use
them. Each source was re-checked against the provider (landing and download URLs fetched,
terms quoted, DOIs resolved), and nine are kept as reference-only dataset cards with
corrected facts:

- frap_fire_perimeters: fire.ca.gov blocks scripted access and the CDFW metadata page is
  down; links to data.ca.gov and the CNRA hub, period 1878-2025, CC BY / free distribution.
- geomac_historical: GeoMAC was shut down on 30 April 2020 and the archive moved to NIFC;
  USGS DS 612 documents the 2008 season only.
- goesr_fdcf: the goes-r.gov product link redirects to a generic page; 10-minute cadence
  only since April 2019; per-satellite AWS buckets (GOES-East after April 2025 is GOES-19).
- hms_smoke: density attribute reliably filled only from June 2010; archive from 2005-08-05.
- hrrr: CONUS and Alaska; forecast length changed with the model version.
- landscan_population: CC BY 4.0 since May 2022; LandScan Global 2024 DOI.
- ndfd: period 2004-present (not 2000); fire-weather and Red Flag grids documented.
- nohrsc_snodas: NSIDC G02158 links, use before October 2004 discouraged, known defects.
- wrc_housing_density: 2nd edition uses 2020 housing data (not 2018); Jaffe et al. 2024.

Dropped: GOES GeoColor (viewer imagery, experimental, no bulk archive or terms), NASA GIBS
(visualisation tiles), HPWREN weather (CC BY-NC-ND 4.0, regional), NWS spot forecasts (no
structured NWS archive) and Synoptic (redistribution restricted).

The dataset page renderer now says plainly when PyHazards has neither a loader nor an
inspection command for a source. Also fixes the FIRMS card's Schroeder et al. (2014) DOI,
which pointed to an unrelated methane paper.

Co-authored-by: runyangxu <runyanggg@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ce cards salvaged from PR #33

Salvaged and corrected from runyangxu's PR #33.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…FIgLib SmokeBench dataset

Replace the idea of registry "prompted" VLM models with a separate, protocol-faithful module that
follows SmokeBench (Qi, Li & Barnes, WACV 2026, arXiv:2512.11215):

- pyhazards/prompted: the paper's verbatim prompts (classification, tile, grid, detection),
  temperature 0.5, 3 x 4 tiles and the numbered 5 x 5 grid overlay, answer parsing, accuracy / mIoU,
  smoke-area and Weber-contrast quintile bins, a resumable runner writing records.jsonl/report.json,
  and backends: Qwen2.5-VL-7B/32B, InternVL3-14B-hf, Idefics2-8B (transformers, extra prompted-hf,
  pinned HF revisions) and Gemini 2.5 Pro / GPT-4o (official clients, keys from the environment).
  Where the paper is silent, behaviour follows the authors' evaluation script (SoraLink/MLLM @ 183cdca,
  no licence: test oracle only); protocol="reference_code" reproduces its two geometry bugs.
- pyhazards/datasets/figlib_smokebench: SmokeBench released no data. The 5,046 boxes are the
  bbox_labels of SmokeyNet's metadata.pkl (Apache-2.0, pinned + sha256, restricted unpickler; their
  area quintiles are exactly the paper's bins), frames stream from the HPWREN FIgLib archives; a seeded
  draw replaces the unreleased 1,000 smoke-free frames. Dataset card + inspection CLI.
- Cards (pyhazards/prompted/cards) with model papers, licences, SmokeBench Tables 1-8 and deviations,
  rendered to docs/source/pyhazards_prompted.rst (scripts/render_prompted_docs.py, CI check); the
  model catalog page links it. No new mandatory dependencies (extras prompted, prompted-hf,
  prompted-gemini, prompted-openai).
- Tests: prompts byte-identical to the paper, tiling/cell geometry, parsers incl. malformed answers,
  hand-computed metrics, the runner with a fake backend, dataset adapter on fixtures; oracle suite
  "smokebench" runs the authors' own functions (grid overlay pixel-identical, tile crops, cell labels,
  parsing/scoring, box IoU vs torchvision, area/contrast, OpenCV grey on all 2**24 colours) and checks
  the SmokeyNet boxes; locally, contrast quintiles of all 5,046 images reproduce the paper's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eck; crop-local contrast; docs sync

- qwen2_5_vl_7b card: PyHazards run on all 5,046 smoke + 1,000 seeded smoke-free images at
  temperature 0.5 gives 0.375 smoke accuracy (paper 0.380) with matching area / contrast bins, and a
  greedy run on a stratified subset (0.382).
- weber_contrast converts only the box and its 20-pixel frame to grey (identical values; 1.4 ms instead of 52 ms
  per 3072 x 2048 frame; oracle tests unchanged and green).
- Sync Generated Docs workflow also renders the prompted-baseline page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pyhazards.prompted)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Net; real IBTrACS/TCND/SHIPS readers; km track error

Models (each now takes its paper's inputs and task instead of the shared 6x8 -> 5x3 stand-in):
- tropicalcyclone_mlp: port of the official 24-h intensity-change Keras MLP (wenweixu/tropicalcyclone_MLP,
  BSD-2): 121 SHIPS predictors -> 2048 sigmoid -> 2048 relu -> 1 (kt), 4,448,257 parameters; outputs equal
  the official model (Keras 3, torch backend) with copied weights.
- saf_net: written from the paper (official notebook has no licence; used only as oracle): wide (96) +
  deep (2,4,31,31,4) -> scaled 24-h intensity, 880,233 parameters; seeded init, eval/train outputs and the
  released SAF_Net.pkl (strict) match.
- tropicyclonenet: port of the CC BY 4.0 TCN_M generator and discriminator (4,767,195 / 231,009
  parameters); the Zenodo checkpoint loads strictly, all-decoder and sampled outputs, train mode, forecast
  post-processing and the best-of-6 metric match the official code. Default sampling visits the sampled
  decoders (official_sample_loop=True reproduces the official index loop, which leaves placeholder 1s).

Data and evaluation:
- ibtracs_tracks reads real IBTrACS v04 CSV / netCDF (PyHazards reader; tests on a real 4-storm cut).
- tropicyclonenet_dataset reads TCND like the official loader (oracle-tested); ships_xu2021 reads the
  Xu et al. (2021) SHIPS table with the official leave-one-year-out folds.
- Synthetic data renamed and labelled: tc_tracks_synthetic, ships_xu2021_synthetic,
  safnet_cma_era_interim_synthetic, tropicyclonenet_dataset_synthetic; tcbench_alpha removed.
- tc benchmark: great-circle track error in km, wind / pressure MAE in the dataset's units, per lead time,
  best-of-k errors as defined by TropiCycloneNet, new tc.intensity task (MAE/RMSE, per year).
- Citations fixed (hurricast, tropicalcyclone_mlp, saf_net, tcif_fusion, tropicyclonenet, graphcast_tc,
  pangu_tc licensing) in cards and references.rst; hurricast and tcif_fusion marked experimental.
- Oracle workflow: new "tc" suite (keras 3.12.4, opencv 5.0.0.93).

BREAKING CHANGES: tropicalcyclone_mlp / saf_net / tropicyclonenet inputs, outputs and builder arguments;
ibtracs_tracks needs a real file; tcbench_alpha dataset and benchmark card removed; tropicyclonenet_dataset
is now the real TCND reader; metric track_error -> track_error_km (km) and intensity units follow the data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Caravan readers, faithful LSTM, EA-LSTM and Google FloodHub ports

Streamflow contract and evaluation
- flood.streamflow samples are NeuralHydrology windows: x_d (seq_length, n_dynamic) daily forcings,
  x_s (n_static,) catchment attributes, y (seq_length, n_targets) discharge; training statistics
  normalise them; evaluation keeps one sample per basin and day.
- pyhazards.metrics.hydrology ports NeuralHydrology's metrics (NSE, MSE, RMSE, KGE, alpha-NSE,
  beta-KGE, beta-NSE, Pearson r, FHV, FMS, FLV, peak timing, missed peaks, peak MAPE; BSD-3).
- The flood benchmark rescales predictions, clips negatives to zero and computes the metrics per
  basin; it reports the median (<metric>) and mean (<metric>_mean) over basins, n_basins and
  n_basins_nse_le_0, with per-basin values in the report metadata. Inundation scoring also accepts
  graph-temporal (mesh-node) datasets.

Data honesty
- caravan_streamflow now reads a local copy of the official Caravan release (netCDF or CSV);
  new camels_us_streamflow reads CAMELS-US as NeuralHydrology does (Kratzert et al. 2019 defaults).
- Removed the random-number adapters waterbench_streamflow, hydrobench_streamflow and
  floodcastbench_inundation (and their dataset / benchmark cards); flood_streamflow_synthetic now
  generates basins in the streamflow layout, the old graph data is flood_mesh_synthetic.

Models
- neuralhydrology_lstm: port of NeuralHydrology CudaLSTM (297,217 parameters at the 2019 setup).
- neuralhydrology_ealstm: port of NeuralHydrology EALSTM (208,641 parameters).
- google_flood_forecasting: port of googlehydrology MeanEmbeddingForecastLSTM with the CMAL head
  (3,402,832 parameters); pretrained=True loads the released FloodHub weights.
- hydrographnet, floodcast, urbanfloodcast are marked experimental; flood citations fixed in cards,
  references.rst and Appendix A.

Oracle tests (new "flood" matrix suite, Python 3.12) compare the models (parameter counts, seeded
initialisation, state dicts, eval/train outputs), the metrics, the CAMELS-US / Caravan readers and
the whole streamflow evaluation with NeuralHydrology @ ea94a40, Google's model with googlehydrology
@ cdda28d and the FloodHub weights; gated tests load the official Kratzert et al. (2019) HydroShare
checkpoints and reproduce Table 2 from the stored simulations.

Breaking changes: model constructor arguments and inputs of the three streamflow models; flood
streamflow metric names (mae removed, per-basin medians); caravan_streamflow needs real data; the
removed dataset names; flood_streamflow_synthetic layout; hydrographnet smoke task is flood.inundation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…evaluator and SeisBench reader

Earthquake phase picking, batch 4 (earthquake lead).

Models (plain PyTorch ports with attribution, verified against the official code and weights):
- phasenet: AI4EPS/PhaseNet @62005c6 (MIT, TF1). 1-D U-Net, 268,443 params, TF "same" padding,
  (batch, 3, T) -> noise/P/S probabilities. Official checkpoint 190703-214543 read without
  TensorFlow (pure-Python TensorBundle reader) and downloaded at runtime (pinned + sha256).
- eqtransformer: smousavi05/EQTransformer @a589da6 (MIT, Keras). Paper model 371,639 params and
  conservative variant 376,423; detection/P/S outputs; official tester picker ported.
- gpd: interseismic/generalized-phase-detection @ea81ef1 (MIT, Keras 2.2.2). 1,741,003 params,
  P/S/noise window classifier plus the gpd_predict.py sliding-window picker.
- Oracle tests run the official TF/Keras models on TensorFlow 2.11 (new suite "earthquake",
  tests/oracle/requirements-earthquake.txt) and SeisBench 0.12.6 (GPL, oracle only).

Evaluation and data:
- earthquake.picking now extracts picks with each model's official post-processing and scores
  per-phase precision/recall/F1 within a tolerance, residual mean/std and MAE (PhaseNet protocol:
  |dt| < 0.1 s; EQTransformer protocol: |dt| < 0.5 s), plus detection P/R/F1 for EQTransformer.
- seisbench_waveforms is now a real reader for SeisBench-format datasets and STEAD's own files
  (h5py + csv, no SeisBench import), checked against SeisBench's writer/reader.
- Synthetic data renamed: earthquake_waveforms -> earthquake_waveforms_synthetic (6000-sample
  windows with P/S arrivals and noise traces).

Breaking changes:
- phasenet/eqtransformer/gpd builders: task "regression" -> "picking" (gpd also "classification");
  outputs (batch, 2) -> original outputs; hidden_dim/num_layers/dropout arguments removed.
- seisbench_waveforms needs path=...; pick_benchmark_waveforms and aefa_forecast removed
  (use earthquake_waveforms_synthetic / earthquake_forecast_synthetic); earthquake_waveforms renamed.
- Picking metrics renamed (p_/s_ precision, recall, f1, residual_mean/std, pick_mae in seconds,
  detection_*); old precision/recall/f1 removed. The forecasting "pyCSEP-style" export removed.
- aefa and pycsep benchmark cards removed (AEFA, pyCSEP, pick-benchmark marked missing in
  Appendix A); eqnet and wavecastnet marked experimental.

Citations fixed: EQNet (doi 10.1029/2021JB023283), SeisBench (Woollam et al. 2022 SRL,
doi 10.1785/0220210324), PhaseNet GJI, pick-benchmark JGR, pyCSEP, AEFA, WaveCastNet repo_url.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…faithful TC-MLP, SAF-Net, TropiCycloneNet

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-US/Caravan readers, faithful NeuralHydrology LSTM/EA-LSTM and Google flood model

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eader, faithful PhaseNet, GPD, EQTransformer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@XueqiC XueqiC changed the title Faithful wildfire model reproductions (WIP) Faithful model reproductions across all hazards (WIP, 2.0.0) Oct 8, 2026
Xueqi Cheng and others added 9 commits October 7, 2026 21:30
Removing a model (forefire, wrf_sfire) made the model-PR review try to load
and smoke-test the deleted cards. touched_card_names now ignores card paths
that no longer exist. Also note in ts_satfire that each baseline validates its
input shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…QNet rebuilt from the paper

WaveCastNet (Lyu et al., Nat. Commun. 2025): port of dwlyu/WaveCastNet @ c859e04 (MIT).
- Dense model (AEConvLEM_dense, 10,093,242 params) and sparse-station model (AEConvLEM_sparse,
  16,535,430 params with the 564 official stations): down-sampling embedding, ConvLEM cells with
  reset gate and per-pixel peepholes, PixelShuffle reconstruction; official names, creation order
  and init. The decoder starts from uniform noise in eval mode too (official); generator= and
  decoder_noise= hooks (and station_mask= for the sparse mask) make outputs deterministic.
  rollout() reproduces the official rolling validation forecast.
- Official Huber-variant loss (delta 0.2) and ACC / RFNE / RMSE per (sample, channel)
  (pyhazards.metrics.wavefield).
- Oracle (tests/oracle/test_wavecastnet_oracle.py): exact equality of seeded init, eval/train
  outputs, BN stats, gradients, rolling forecast; best_lem_dense_.pt loads strictly and matches;
  the sparse checkpoint loads strictly only with 558 stations (released coords list 564).
- earthquake.forecasting is now an honest wavefield task (ACC/RFNE/RMSE, per channel, seeded
  rollout); earthquake_forecast_synthetic -> earthquake_wavefield_synthetic (point-source P/S
  wavefronts; old name kept as deprecated alias). Card: core.

EQNet (Zhu et al., JGR 2022): rebuilt from the paper (official code is non-commercial and has no
shift-and-stack); 1-D ResNet-18 extractor, P/S picking heads, shift-and-stack over candidate
hypocentres, event detector (1,043,619 params), multi-station contract with travel-time tables,
pick/event extraction, paper loss. Oracle (tests/oracle/test_eqnet_oracle.py): extractor equals
AI4EPS/EQNet resnet1d @ af94a08; heads equal the author's a9df49a heads at the paper widths.
Shift-and-stack tested from the paper description. Card: variant (reproduction.source: paper).

Breaking: wavecastnet builder args (temporal_in/out, hidden_dim, num_layers, dropout) removed,
task forecasting, ConvLEMCell signature/names changed, WavefieldMetrics per channel; eqnet task
picking/detection with dict outputs (old transformer stand-in removed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…et rebuilt from the paper

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… ERA5 reader

Both official repositories have no LICENSE file: the models are written from the papers and the official
code is used only as a test oracle (pinned in tests/oracle/repos.yaml, never copied).

- hurricast (Boussioux et al., Weather and Forecasting 2022): the official ExperimentalHurricast
  encoder-decoder (CNN 4096-576-256-128 + Transformer, 2,969,771 / 2,969,914 parameters for intensity /
  displacement) and every preset of scripts/config.py (transformer_config*, recurrent lstm_config*, split
  encoder); same state-dict keys, identical seeded weights, outputs, embeddings and gradients in eval and train
  mode, official state dicts load strictly into Hurricast.network. Second stage: XGBoost (EstimatorModule, one
  regressor per target) on the official feature columns plus the 142-d embeddings, with the defaults of the
  official train_xgb_* functions (depth 8, 140 trees, lr 0.15, subsample 0.7, min_child_weight 5); predictions
  equal XGBRegressor 3.2.0 fitted the official way. Hurricast.fit trains the network (MSE + official L2 term,
  Adam, batch 64; a training step equals src/run.py train_epoch) and then XGBoost; predictor="network" and
  use_embeddings=False (HUML-(stat, xgb)) are options. The paper's GRU decoder is not in the released code and
  is not provided (documented).
- hurricast_ibtracs_era5: 30 statistical features per 3-hour step from IBTrACS (storm cut, interpolation,
  category and displacements equal the official data_processing.py on real rows), 9 storm-centred ERA5 maps
  from user-provided netCDF / zarr (CDS or RDA layouts), 24-hour intensity or position targets, paper season
  splits. Fixture: a real 9-time ERA5 cut around Hurricane Ophelia (CC BY 4.0, tests/fixtures/era5).
- tcif_fusion (Wang, Li and Zheng, ERL 2024): the notebook's TCIF_fusion() graph in PyTorch (3-D branches +
  fusion branch, ALL branch, history MLP, VGG-19 on IR, residual head). Every layer's parameter count and the
  total 299,611,263 equal the summary printed by the authors' run; with Keras weights copied the outputs equal
  the notebook graph rebuilt in Keras 3. The ALL input is not a heat-map input: the paper's Figure 1 builds it
  from U, V, W, SST (65 channels, default: 299,588,223 parameters); all_channels=85 rebuilds the notebook graph.
  Model-knowledge helpers (Grad-CAM heatmaps, |heatmap| x input) follow the paper; the gradient step matches the
  notebook's example.
- Synthetic smoke datasets hurricast_synthetic and tcif_fusion_synthetic; smoke configs score tc.intensity.
- Cards (both core, source: paper), Appendix A, benchmark cards, regenerated docs; tc oracle suite gets the two
  new tests and xgboost-cpu 3.2.0.

BREAKING CHANGES: hurricast and tcif_fusion no longer take the generic (batch, 6, 8) storm history or return
(batch, 5, 3); hurricast takes {"x_stat", "x_viz", "position"} and returns the 24-hour intensity (batch, 1) or
displacement (batch, 2) (the default XGBoost predictor must be fitted with model.fit first); tcif_fusion takes
{"u", "v", "w", "sst", "all", "his", "ir"} (channels last) and returns the 24-hour intensity (batch, 1). Their
builder arguments changed (input_dim / hidden_dim / horizon / output_dim are gone), and their smoke configs now
use tc.intensity on hurricast_synthetic / tcif_fusion_synthetic instead of tc.track_intensity on
tc_tracks_synthetic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ritten from the papers, official-code oracles

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rbanFloodCast DNO; mesh and raster inundation evaluation

HydroGraphNet (Taghizadeh et al., CACIE 2025)
- hydrographnet is a plain-PyTorch port of NVIDIA PhysicsNeMo's MeshGraphKAN @ eb7a329 (Apache-2.0):
  Fourier-KAN node encoder, LayerNorm MLPs, 15 edge/node blocks with sum aggregation, 2,318,722 parameters
  at the example configuration; PhysicsNeMo parameter names and initialisation order (the dropped MLP node
  encoder is created for the RNG stream). rollout() ports the example's inference.py loop;
  hydrographnet_physics_loss / HydroGraphNetLoss port compute_physics_loss and the train.py loss.
- hydrographnet_white_river reads a local copy of the White River release (Zenodo 14969507) exactly like
  HydroGraphDataset (windows, physics data, k=4 graph, normalisation, rollout targets); the release has
  no test list, so test_ids are required. flood_mesh_synthetic now produces random data in this layout;
  write_hydrograph_files writes the release layout.
- Oracle (new "physicsnemo" suite, torch 2.12 + torch_geometric/torch_scatter): parameters, seeded init,
  state dict, eval/train outputs and gradients (two configurations), PyG batching, PhysicsNeMo's stored
  regression output, the physics loss, the rollout loop and the reader (bit-identical on release-layout
  fixtures; a gated test compares real hydrographs, run locally on H1/H2).

UrbanFloodCast (Xu et al., J. Hydrology 2025)
- urbanfloodcast is the DNO-3 deep neural operator written from the paper with U-NO (BSD-2) and FNO (MIT)
  blocks (the official repository has no licence): 4,470,437 parameters, 24 steps at once,
  (B, Sy, Sx, T, 1, 5) -> (B, Sy, Sx, T, 3). prepare_urbanfloodcast_event builds the official one-shot
  inputs; urbanfloodcast_synthetic is a random stand-in in that layout (no Berlin GeoTIFF reader yet).
- Oracle (flood suite): parameters, seeded init, state dict, outputs and gradients on two grids, the
  one-shot pipeline against flood_data, and the metrics against DNO_main's test loop (whose module cannot
  be imported as released; get_eval_pred is executed from its source).

FloodCast stays experimental: the flood-model code was never released and the paper does not report its
widths; FloodCastBench released no model code, so its FNO baseline is not added (card explains).

Evaluation: flood.inundation now uses pyhazards.metrics.inundation (pixel_mae, rmse, iou, f1, CSI at
1/10/50 cm, relative L2, NSE, Pearson r as in the UrbanFloodCast evaluation) and scores mesh hydrographs
by autoregressive rollouts in metres (rollout_rmse, per-step curves in the metadata). Cards, Appendix A,
benchmark / dataset cards (new HydroGraphNet White River ecosystem), docs and count tests updated; smoke
tests accept integer tensors with a value range (SmokeTensorSpec.high).

Breaking changes: hydrographnet and urbanfloodcast constructor / builder arguments, inputs and outputs
(PhysicsNeMo and official DNO signatures); HydroGraphNetLoss semantics; flood_mesh_synthetic layout and
parameters; urbanfloodcast no longer accepts task="segmentation"; inundation_metrics moved to
pyhazards.metrics.inundation (re-exported) and reports more keys; raster inundation predictions are
batched (benchmark param batch_size, default 1); the ERA5 card no longer links hydrographnet;
scripts/train_hydrographnet.py and test.py use the new API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…anFloodCast, FloodCast stays experimental

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Net/GraphCast/Pangu placeholders

FourCastNet, GraphCast and Pangu-Weather are global weather models whose cyclone results come from
tracking their forecast fields. The registered fourcastnet_tc / graphcast_tc / pangu_tc networks
(15K-152K parameters, no forecast fields, weights or tracker) are removed with their cards, smoke
configs and docs pages. New package pyhazards.forecasts:

- tempest: TempestExtremes DetectNodes/StitchNodes rules (TCBench's tracker), written from the
  published algorithm. Identical nodes and track files to the official v2.4.2 binaries on synthetic
  fields and option variants, and byte-identical to TCBench's released unmatched_tracks for four
  2023 Pangu-Weather forecasts (as are the binaries).
- following: ECMWF-style tracker of the Pangu-Weather (arXiv:2211.02556 Sec. 4.2.2) and GraphCast
  (Science supplement 8.1.4) papers, with presets incl. GraphCast's bold hyper-parameters; tested on
  synthetic vortices with known tracks (no official implementation exists).
- matching (HuracanPy rule) and scoring against IBTrACS through the tc benchmark's
  track_intensity_metrics (km, kt, hPa per lead); protocol="tcbench" reproduces TCBench's
  evaluate_tracks incl. its float16 IBTrACS quirk: equal to TCBench's own _DPE/_AE on every evaluated
  row of the released Pangu-Weather and FourCastNet v2 tracks, and the DPE/AE values printed in
  TCBench's notebook are reproduced end to end from raw fields (scripts/reproduce_tcbench_tracks.py).
- sources: TCBench tracks and raw fields (HTTP range reads, pinned revision), WeatherBench 2 GraphCast
  and Pangu-Weather stores (optional extra pyhazards[weather]), optional earth2studio runner
  (user-installed; tested with earth2studio's Persistence model).

Appendix A: new status "Foundation model pipeline" (no model cards, must link docs) for GraphCast,
Pangu-Weather and FourCastNet; TCBench Alpha is now implemented. New TCBench benchmark ecosystem card,
docs page pyhazards_forecasts, oracle suites tc-tracking (TempestExtremes built from source, TCBench
code) and weather (earth2studio 0.19.0, zarr, gcsfs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cker -> IBTrACS pipelines (TCBench reproduced)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant