Skip to content

Expose GPS-RO refractivity levels in NCEP gpsro decode; derive pressure/height in HealDA - #1150

Draft
negin513 wants to merge 3 commits into
NVIDIA:mainfrom
negin513:feat/nnja-gpsro-pressure
Draft

negin513 wants to merge 3 commits into
NVIDIA:mainfrom
negin513:feat/nnja-gpsro-pressure

Conversation

@negin513

@negin513 negin513 commented Sep 9, 2026

Copy link
Copy Markdown
Member

Earth2Studio Pull Request

Description

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

HealDA needs a finite pressure coordinate and a refraction-corrected height for every GPS-RO bending-angle level, built from the occultation's own refractivity levels. The NCEP gpsro decode only exposed the bending angle (gps) with a null pres and the geometric impact height in elev, and the refractivity block was discarded, so the wrapper had nothing to derive from.

Following review, the data source stays raw and model-agnostic; the derivation lives with the model:

Data source (NNJAObsConv, NomadsGDASObsConv)

  • New variable gps_refractivity (gpsro::15036) in both lexicons: the message's refractivity levels (ARFR, N-units, first slot per HEIT, mirroring the BNDA value/error slot handling) with elev = the level's geometric height (HEIT) and null pres. Rows carry the occultation's time, type (SAID), station and quality (QFRO) so consumers can regroup them per occultation.
  • gps rows are unchanged from main: null pres, elev = impact parameter minus Earth radius of curvature. No QC and no derived vertical coordinate in the source.

HealDA wrapper

  • New earth2studio.models.da.utils_gpsro: refraction_corrected_height (Bouguer fixed point on n(h)(R_c + h) = a), hydrostatic dry_pressure_hpa from refractivity, USSA-1976 height_to_pressure_hpa, blended_pressure_hpa (0.8 standard + 0.2 dry below 5 km, dry above), gpsro_level_coordinates with the fallback order blended -> dry -> standard at corrected height -> standard at geometric height, qfro_bit_set, and assign_gpsro_coordinates(frame) which groups gps / gps_refractivity rows by occultation (time, type, station) and fills pres / elev on the gps rows, dropping the refractivity rows. A nominal 6371 km radius of curvature is used (metre-level height error versus the message's ELRC).
  • HealDA.input_coords accepts gps_refractivity; HealDA.prep_conv rejects gps-family rows with QFRO bit 5 set when a quality column is present, then calls assign_gpsro_coordinates.

Usage: request ["u", "v", "q", "t", "pres", "gps", "gps_refractivity"] from the source and pass the frame to HealDA as before; without gps_refractivity rows the wrapper falls back to the standard atmosphere at the geometric height.

Out of scope: SAID allowlist and height / bending-angle QC beyond the QFRO reject, NNJA SATWND source (#1151), NNJA-vocabulary HealDA-v2 wrapper (#975).

Tests: test/models/da/test_utils_gpsro.py (analytic exponential column, fixed-point convergence, blend weights, fallback chain, QFRO bit numbering, assign_gpsro_coordinates with and without a profile and across occultations), test/models/da/test_da_healda.py (prep_conv derivation matches a direct call, bit-5 reject, other bits kept), test/data/test_utils_ncep.py (raw refractivity rows exposed with header lat/lon and metadata; none emitted when only gps is requested).

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. Touches HealDA.prep_conv alongside #1151; the two merge cleanly (verified locally), only the CHANGELOG bullets are adjacent.

…decode

HealDA's gpsro_v3 training loader gives every bending-angle level a finite
pressure coordinate built from the occultation's own refractivity levels
(blended standard-atmosphere/dry pressure below 5 km, dry above) and uses the
refraction-corrected tangent height as the Height feature. The e2studio
decoder emitted a null pressure and the geometric impact height, so
NNJAObsConv/NomadsGDASObsConv GPS-RO rows could not feed the model the way
training did.

Add earth2studio.data.utils_gpsro with the pure-numpy derivation and the same
fallback order as the loader, read HEIT/ARFR from the BUFR message, and expose
a gpsro_reject_qfro_bits option on NNJAObsConv for the QFRO-based rejection
training applied.
@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.

Data sources should expose fields as the archive carries them so the model
wrapper, not the source, decides what a field means. The NCEP gpsro decode
now leaves `gps` rows raw (null `pres`, geometric impact height in `elev`)
and exposes the message's refractivity levels as a new `gps_refractivity`
variable (`ARFR`, N-units, `elev` = `HEIT`). The refraction-corrected
height / blended pressure derivation and the QFRO bit-5 reject move into
the HealDA wrapper (`earth2studio.models.da.utils_gpsro`), which derives
them per occultation from those raw rows.
@negin513 negin513 changed the title Derive GPS-RO pressure and refraction-corrected height in NCEP gpsro decode Expose GPS-RO refractivity levels in NCEP gpsro decode; derive pressure/height in HealDA Sep 15, 2026
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