Skip to content

Add NNJAObsSatwnd source for the raw NCEP satwnd AMV dump - #1151

Draft
negin513 wants to merge 2 commits into
NVIDIA:mainfrom
negin513:feat/nnja-satwnd
Draft

negin513 wants to merge 2 commits into
NVIDIA:mainfrom
negin513:feat/nnja-satwnd

Conversation

@negin513

@negin513 negin513 commented Sep 9, 2026

Copy link
Copy Markdown
Member

Earth2Studio Pull Request

Description

Roadmap task: NVIDIA/physicsnemo-roadmap#2986 (feature NVIDIA/physicsnemo-roadmap#2669, Releasing HealDA V2 in E2S).

HealDA-v2 is trained on atmospheric motion vectors from the dedicated NCEP satwnd dump rather than the AMVs merged into PrepBUFR. Earth2Studio had no reader for that dump, so the only AMVs available at inference were the PrepBUFR ones in NNJAObsConv (report types 240-260), which the model never saw.

This PR adds NNJAObsSatwnd, a DataFrameSource over s3://noaa-reanalyses-pds/observations/reanalysis/amv/satwnd/ (1979-present, 6-hourly cycle files, 4-400 MB each), and earth2studio.data.utils_satwnd:

  • Layout-agnostic decode. The dump mixes producer layouts (GOES legacy NC0050xx, GOES-R NC00503x/05x, Meteosat NC00506x, Himawari NC00504x, MODIS/AVHRR/VIIRS, LEO-GEO NC005072, INSAT) and NCEP-local descriptor ids drift between Table B versions (e.g. EHAM is 2162 in 2024 files while 2164 was TCMD in 2015). Fields are resolved by mnemonic from each file's embedded Table B and read as first occurrence, the same as GSI ufbint.
  • GSI report types. The dump has no TYP. SATWND_TYPE_TABLE ports read_satwnd.f90's sattabin (NOAA-EMC/GSI 860d1374): (NC005 subset, SAID, SWCM) -> (report type 240-260, processing case). Winds GSI does not type (SAIDs outside its platform lists, e.g. INSAT-3DR 473; unknown subsets) are dropped, as GSI drops them.
  • Quality indicators per GSI case. GNAP-triplet producers (EUMETSAT 1/2/3, JMA 101/102/103, NESDIS/MODIS/AVHRR/VIIRS 1/3/4) and AMVQIC producers (GNAPS 5 = QI without forecast, 6 = with forecast, 7 or 2 = expected error) resolve to qi, qi_forecast, expected_error.
  • Schema. NCEP_CONVENTIONAL_PUBLIC_SCHEMA plus satellite_id, subset, wind_method (SWCM), height_method (HAMD/EHAM), satellite_za (signed), qi, qi_forecast, expected_error, gsi_case. u/v from WDIR/WSPD; pres is the final height assignment (Pa); elev is null (the dump carries no geometric height; HealDA.prep_conv fills missing conventional heights from pressure via earth2studio.models.da.utils.pressure_to_height_m, USSA-1976); quality is SWQM where the producer encodes it; station is GSI's c_station_id (IR257, CT172, ...); class is SATWND.

Not in this PR, deliberately: GSI-style QC screens (125 hPa floor, GEO zenith > 68 deg, SWCM >= 4 layer winds, speed caps) and the hpx5 / pressure-level / 2 h thinning that training applied. Those are model-side and tracked on the roadmap task, together with dropping PrepBUFR 240-260 in NNJAObsConv when this source is used. The source exposes every field as the dump carries it, with no QC applied.

Not verified: parity with the training archive for subsets GSI itself does not type (its ETL applied fallbacks that are not in read_satwnd.f90).

Real-file checks:

  • gdas.20150101.t00z.satwnd.tm00.bufr_d (35 MB): 275,822 winds across 11 subsets, every one typed as expected (245/246/251 GOES, 252/242/250 MTSAT, 253/243/254 Meteosat, 257/258/259 MODIS), QI resolved for all, SWQM present only for NESDIS/MODIS; 27 s with 8 decode workers vs 125 s single-worker.
  • gdas.20240101.t00z.satwnd.tm00.bufr_d (294 MB): 3,382,615 winds across 15 subsets (GOES-16/18 240/245/246/247/251, Himawari-9 242/250/252, Meteosat-10/11 243/253/254, LEO-GEO 255, Metop AVHRR 244, NOAA-20/21 VIIRS 260); INSAT-3DR (NC005024/026, SAID 473) dropped as GSI drops it; QI resolved for 98% of winds (the remainder are GOES-R rows whose GNAPS 5 is missing); 177 s with 8 workers.

Tests: test/data/test_utils_satwnd.py covers the type table against sattabin spot checks, mnemonic resolution with file-table precedence, section-1 subcategory for editions 3 and 4, USSA inversion, legacy NESDIS / GOES-R / EUMETSAT-310077 / JMA subset layouts, time-window and missing-wind rejection, the end-to-end decode_satwnd path with a mocked decoder, and NNJAObsSatwnd URI/task planning.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.
  • The CHANGELOG.md is up to date with these changes.
  • An issue is linked to this pull request.
  • Assess and address Greptile feedback (AI code review bot for guidance; use discretion, addressing all feedback is not required).

Dependencies

None (uses the existing data extra: pybufrkit, obstore). Touches HealDA.prep_conv alongside #1150; the two merge cleanly (verified locally), only the CHANGELOG bullets are adjacent.

HealDA-v2 NNJA training reads atmospheric motion vectors from the dedicated
NCEP satwnd dump and drops the AMVs merged into PrepBUFR; earth2studio had no
way to read that dump, so inference could only feed the PrepBUFR AMVs the
model never saw. Add a data source for amv/satwnd in the NNJA archive
(1979-present) that decodes every producer layout by resolving mnemonics from
each file's embedded Table B and reading first occurrences the way GSI
ufbint does.

The GSI report type is not in the file. Port read_satwnd.f90's sattabin table
so (subset, SAID, SWCM) maps to the same 240-260 type and processing case GSI
assigns, resolve QI/EE per producer the way each GSI case reads them, and keep
SWQM, SAZA, SWCM, height method and subset in extra columns. Winds GSI does
not type are dropped; QC and thinning are left to the consumer.
@copy-pr-bot

copy-pr-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

The AMV dump only reports a pressure height assignment, so `NNJAObsSatwnd`
no longer fills `elev` from the standard atmosphere. HealDA needs a
geometric height for every conventional row, so `pressure_to_height_m`
moves to `earth2studio.models.da.utils` and `HealDA.prep_conv` fills
missing heights from pressure. Also drops the internal training-archive
reference from the source docstring.
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