Skip to content

Feat/ic generation - #13

Merged
zyhu-hu merged 9 commits into
NVlabs:mainfrom
zyhu-hu:feat/ic-generation
Nov 10, 2026
Merged

zyhu-hu merged 9 commits into
NVlabs:mainfrom
zyhu-hu:feat/ic-generation

Conversation

@zyhu-hu

@zyhu-hu zyhu-hu commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

Initial conditions from ERA5 and ECMWF HRES

Adds scripts/initial_conditions/, which builds STRATA initial conditions on the SCREAM ne1024pg2 physics grid with the E3SM L128 vertical grid, as one-frame Zarr stores with flat ncol and the 32 levels STRATA uses. These are STRATA inputs, not ICs EAMxx can start from (EAMxx reads its ICs on the np4 GLL grid).

  • fast_ic.py: a torch port of the E3SM HICCUP steps (fv2fv_flx horizontal remap, surface-pressure adjustment, L128 vertical remap, remove_supersaturation), then potential temperature and hydrostatic z_mid. It builds one IC from ARCO ERA5 in about 80 s on one GPU. On ten tropical-cyclone cases its output matched ICs built by HICCUP itself bit for bit, apart from last-bit differences in a few values.
  • hres_ic.py: the same steps on the ECMWF HRES analysis (WeatherBench2 hres_t0, 2016-2022). HRES has no data above 50 hPa; STRATA reads only the levels from 100 hPa down.
  • build_map.py: builds the ERA5 -> ne1024pg2 first-order conservative map (ncremap -a fv2fv_flx --lrg2sml, same TempestRemap commands) in parallel pieces of destination columns, in about 32 min instead of 13-18 h serially. The merged map matches a serial ncremap map; area_a and frac_a are recomputed after the merge.
  • ic_store.py, layout.py: static inputs, coszr, store creation and checks, constants.
  • run_screamcast_nudged.py --ic-store <store> --correction none starts a forecast from such a store at its initial_time. ScreamData.to_data_source now passes the catalog's reference_time to the reader instead of relying on the reader's 2020-10-01 default, which is also the SCREAM archive's, so existing runs are unchanged.
  • README.md and docs/initial_conditions.md: inputs, commands, validation, timing.

License. fast_ic.py contains code ported from HICCUP, released under the 3-Clause BSD license (Copyright 2026, Lawrence Livermore National Security, LLC; LICENSE added in E3SM-Project/HICCUP@0dec8bb). The full HICCUP notice is kept at the top of fast_ic.py, and the docs have a License section. The L128 coordinate file is downloaded from the HICCUP repository at 0dec8bb. The SCREAM static fields come from the nvidia/STRATA-SCREAM-sdy1 Hugging Face dataset.

Tests:

  • tests/test_era5_fast_ic.py and tests/test_hres_ic.py use ground truth the code never sees: an isothermal atmosphere at rest, standard-atmosphere surface pressure, Murphy-Koop saturation, hypsometric heights with virtual temperature, a hand-built map with 1-based unordered links, lat/lon units checks, and the readers on small synthetic stores in the ARCO and WeatherBench2 layouts.
  • tests/test_ic_store_source.py (3 tests): a one-frame store is read at its initial_time, has no frame 10 min later, and a catalog entry's frame n is reference_time + n * 10 min.
  • tests/test_build_map.py (3 tests, about 5 s; skipped unless nco and tempest-remap are on PATH) compares the parallel build with a serial ncremap map on a small grid, and checks that parts from other grids and incomplete maps are not reused.

In the STRATA GB300 image: 24 passed, 3 skipped (build_map, no nco there); the 3 build_map tests pass in a conda env with nco and tempest-remap. python -m scripts.initial_conditions.{fast_ic,hres_ic,build_map} --help run. make lint passes. A v1 forecast from a HICCUP-built IC store (Maria, 2017-09-14T00) on one GB300 loaded all 145 input channels and finished the first model forward; the full 2-step --ic-store forecast on 4 GPUs has not been run yet.

🤖 Generated with Claude Code

zyhu-hu and others added 7 commits November 4, 2026 18:59
Builds EAMxx/SCREAM atmospheric initial conditions on ne1024pg2 with the
E3SM L128 vertical grid, in the 32-level Zarr v3 layout of the SCREAM stores:

- fast_ic.py: a torch port of the E3SM HICCUP steps (horizontal fv2fv_flx
  remap, surface-pressure adjustment, L128 vertical remap,
  remove_supersaturation, PotentialTemperature and hydrostatic z_mid). One
  GPU builds an IC from ARCO ERA5 in about 80 s; it matches the HICCUP
  pipeline bit for bit apart from last-bit differences in a few qv values.
- hres_ic.py: the same steps on the ECMWF HRES analysis (WeatherBench2
  hres_t0, 2016-2022).
- run_hiccup_eamxx.py + hiccup_l128_to_zarr.py: the reference pipeline that
  calls HICCUP directly (2.5-3 h per IC), with hiccup_time_calendar.patch
  for current xarray; run_tc_batch.py builds the ten tropical-cyclone cases.
- docs/initial_conditions.md: inputs, commands, validation and timing. The
  SCREAM phis/sgh30/landfrac come from the nvidia/STRATA-SCREAM-sdy1
  Hugging Face dataset; run_hiccup_eamxx.py now requires the local phis
  array instead of copying it from internal storage.

Checked: tests/test_era5_fast_ic.py and tests/test_era5_hiccup_ic.py pass,
and fast_ic run from this tree with the Hugging Face static arrays rebuilt
the 2021-07-15T12 IC bit-identical to the reference store in every variable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
The surface geopotential is checked against the closed form for an
isothermal atmosphere, inside the pressure profile and below its lowest
level. fetch_hres_t0 is run on a 3-level 5x8 Zarr v2 store in the
hres_t0 layout: it must pick the requested time, flip the grid to
north-to-south and reject off-hour timestamps, missing times and omega
in hPa.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
ncremap -a fv2fv_flx --lrg2sml runs GenerateOverlapMesh and
GenerateOfflineMap serially, 13-18 h at this size, and no copy of the
map is published. The map is first order, so a destination column's
weights depend only on its own overlaps. build_map.py runs the same two
TempestRemap commands on contiguous ne1024pg2 column ranges in a
process pool and stacks the parts; it also writes the ERA5 SCRIP file
with HICCUP's ncremap -G command and keeps the reuse/adopt rules of
build_ne1024_map.sh, which it replaces.

On 72 Grace cores the full map took 32 min (144 parts; the two polar
parts finish last). Against the serial map built on x86 with NCO 5.3.6:
row and col identical (38,299,240 links), 31,590 weights differ in
float32 (max rel 1.3e-5 on sliver overlaps), and a smooth field
remapped with both maps differs by at most 1.8e-5 K. Two different
splits agree to 7e-9 with identical float32 weights.

tests/test_build_map.py builds a 10-degree lat-lon -> ne4pg2 map in
three uneven parts and checks it against serial ncremap (skipped when
nco/tempest-remap are not on PATH).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
build_map.py:
- Recompute source-side area_a (summed overlap area) and frac_a from all
  links after the merge; per-part values only see that part's overlaps.
  On the full map frac_a now matches the serial map to 1e-15 (was 1.2e-5).
- Build parts in "<map>.parts" under --tmp-dir and remove only that, not
  a user's --tmp-dir.
- Run TempestRemap inside the part dir with short relative names; the
  conda-forge 2.2.0 build aborts on output paths of 98+ characters.
- Name parts by column range and record the input grids, so parts from a
  run with other --parts or other grids are never merged.
- Stop all parts on the first failure; adopt an existing map only if its
  links run from the first to the last column; history and sidecar record
  the module command with absolute paths.

Readers and converter:
- fast_ic/hres_ic check the store's time epoch and dimension order
  (both real stores pass); fast_ic rejects omega in hPa like hres_ic.
- hiccup_l128_to_zarr checks the NetCDF time against --timestamp, and
  load_latlon stops when lat units are missing or do not match the values
  (degree values labelled "rad" scaled coszr's latitudes by 57.3).
- run_hiccup_eamxx no longer stamps the map command with the IC's time.

Tests: new end-to-end checks of the ps adjustment (standard atmosphere,
including the extrapolated surface T), subsaturated qv kept and virtual
temperature in z_mid, supersaturated qv clipped to within 2.5% of
Murphy-Koop saturation, 1-based map links, the ARCO reader, the HRES
epoch/dimension checks, the IC time check and lat/lon units. Eight
mutations that the previous tests missed (hPa/Pa, dry Tv, top-level T,
no T*, mean remap, Bolton constant, raw qv, map col offset) now fail.

Docs: map and output paths under $WORK in every example, a download for
the L128 file, fsspec/aiohttp in the HICCUP env, batch skip rule, and
corrected numbers (3.2 GB map, 175k-column parts, 2.5-3 h).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
Mention IC generation in the intro and give it a top-level section: what
the pipeline does, the three entry points, the one-time inputs, the map
build and an example fast_ic command. Say plainly that
run_screamcast_nudged.py does not take a one-frame IC store as its
initial state yet; the docs no longer say the rollout loaders read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
run_screamcast_nudged.py --ic-store <store> reads the initial state from a
one-frame store built by initial_conditions/ instead of
SCREAM_MAIN_ZARR_PATH. The forecast starts at the store's initial_time;
--initial-time must match it if given, and --correction must be none
because the store has no later truth.

ScreamData.to_data_source now passes its reference_time to
ScreamDataSource instead of relying on the reader's 2020-10-01 default
(the same date the SCREAM archive entry uses, so that path is unchanged).
data_catalog.ic_store() builds the catalog entry for an IC store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
- Move initial_conditions/ to scripts/initial_conditions/ instead of a new
  top-level package; run commands are python -m scripts.initial_conditions.*.
- Remove the HICCUP reference pipeline (run_hiccup_eamxx.py, run_tc_batch.py,
  the HICCUP calendar patch, the NetCDF-to-Zarr converter and
  tests/test_era5_hiccup_ic.py) and fast_ic's --era5-atm/--era5-sfc input.
  The store helpers the converter shared move to ic_store.py, and the
  lat/lon units test moves to test_era5_fast_ic.py.
- test_build_map.py imports build_map at the top (netCDF4 is a core
  dependency), so it no longer needs importorskip or noqa.
- fast_ic.py carries HICCUP's BSD-3-Clause notice (Copyright 2026 Lawrence
  Livermore National Security, LLC; added in E3SM-Project/HICCUP@0dec8bb).
  The docs gain a License section, pin the L128 coordinate download to
  0dec8bb, and say these are STRATA ICs on the pg2 physics grid, not ICs
  EAMxx can start from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
@zyhu-hu
zyhu-hu requested a review from nbren12 November 5, 2026 22:23
@zyhu-hu

zyhu-hu commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator Author

@nbren12, this replaces #12 and addresses your review there:

No new top-level package: everything is under scripts/initial_conditions/, and tests import scripts.initial_conditions.* the way scripts/ace/run_pipeline.py imports scripts.ace.

Reference implementation: removed run_hiccup_eamxx.py, run_tc_batch.py, the HICCUP patch, the NetCDF-to-Zarr converter and tests/test_era5_hiccup_ic.py. The one test there that covered kept code (lat/lon units) moved to test_era5_fast_ic.py. The HICCUP comparison is described in the docs as a past validation.

noqa in test_build_map.py: it was only needed because importorskip("netCDF4") came first. netCDF4 is a core dependency, so both are gone.

Test time: the three build_map tests take about 5 s with nco and tempest-remap installed, and are skipped without them.

License: HICCUP now has a BSD-3 LICENSE (E3SM-Project/HICCUP@0dec8bb, © 2026 LLNS). fast_ic.py carries the full notice, and the docs have a License section.

Comment thread screamcast/catalog_core.py Resolved
@nbren12

nbren12 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Can you put all the python modules code that is imported in the main source folder strata/ please? I think this will make it easier to avoid PYTHONPATH issues since it will be isntalled alongside the package. Currenly the code will only run when the working directory is the repo root. scripts/ should only contain thin wrapper scripts or code that are not imported anywhere.

zyhu-hu and others added 2 commits November 10, 2026 07:35
Address review on PR 13: the modules that are imported (fast_ic, hres_ic,
build_map, ic_store, layout) now live in the installed package as
screamcast.initial_conditions, so they import without PYTHONPATH or running
from the repository root. scripts/initial_conditions/ keeps only thin
command-line wrappers around each module's main().

Also update the README's IC forecast example to the recommended v1
settings (no cross-face halo adjoint, SHT omega lmax 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
The tools run as `python -m screamcast.initial_conditions.<name>`, which works
whenever the wrappers did (installed package or repository root), and every
example already uses that form. scripts/ keeps code that is not imported
anywhere; a second entry point per tool adds nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Zeyuan Hu <zeyuanh@nvidia.com>
@zyhu-hu

zyhu-hu commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@nbren12 the IC modules now live in screamcast/initial_conditions/ and run as python -m screamcast.initial_conditions.<name>. I dropped the wrapper scripts, so nothing under scripts/ is imported anymore. Docs and tests are updated, and the IC tests pass locally.

@zyhu-hu
zyhu-hu merged commit d56a78c into NVlabs:main Nov 10, 2026
1 check passed
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.

2 participants