Skip to content

NNJA Sat Obs: ATMS/AMSUA/MHS/AMSUB (stacked on #966)#968

Draft
aayushg55 wants to merge 14 commits into
NVIDIA:mainfrom
aayushg55:nnja-sat
Draft

NNJA Sat Obs: ATMS/AMSUA/MHS/AMSUB (stacked on #966)#968
aayushg55 wants to merge 14 commits into
NVIDIA:mainfrom
aayushg55:nnja-sat

Conversation

@aayushg55

@aayushg55 aayushg55 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Earth2Studio Pull Request

Description

Stacked PR — draft until #966 merges. This branch is stacked on the NCEP observation refactor, so that PR’s changes appear here until it lands. Once merged, this branch will be rebased onto main, leaving only the NNJA satellite-observation implementation, tests, documentation, and validation. Until then, review only the commits starting with 57fdf2e (feat: add NNJA aggregate microwave observations).

This PR adds earth2studio.data.NNJAObsSat, a historical NCEP aggregate
microwave observation source backed by NNJA. It supports ATMS, MHS, AMSU-A,
and AMSU-B through one source-faithful long DataFrame API while reusing the
private NCEP request and NNJA S3/cache foundation.

What Changed

  • Add a private store-neutral aggregate microwave BUFR adapter.
  • Add NNJA product/catalog routes for ATMS, MHS, AMSU-A, and AMSU-B.
  • Expose encoded ATMS TMBR as atms and encoded TMANT explicitly as
    atms_antenna_temperature.
  • Preserve physical CHNM channels, source time, platform/FOV identity,
    location, view/solar geometry, available source quality/calibration fields,
    and message/subset ordering provenance.
  • Fail closed when any requested file, decode task, batch, or BUFR message is
    incomplete instead of returning an apparently successful partial result.
  • Preserve disjoint requested intervals rather than widening them into one
    continuous decode window.

Compatibility

  • Existing NNJAObsConv behavior is unchanged and retains its permissive
    missing-cycle policy.
  • The new source returns the standard long pandas.DataFrame; no compact or
    streaming API is introduced.
  • No GSI physical transform, QC, scoring, background sampling, or thinning is
    applied by the source.

Validation

The public source was executed on complete six-hour NNJA files, producing
117,615,825 ATMS/MHS/AMSU-A rows plus a 9,150,780-row AMSU-B historical
holdout. External evidence is kept separate by product boundary:

  • NNJA-AI has exact six-hour profile populations and finite masks for ATMS,
    MHS, and AMSU-A; values agree at binary roundoff.
  • UFS/GSI diagnostics are matched without using observation values or reusing
    candidates. ATMS is compared after the official beamwidth transform; the
    other sensors use the aggregate TMBR value.
  • Healthy 2004 AMSU-B diagnostics close exactly for NOAA-15/16. NOAA-17 has
    no unmatched UFS rows, 160 ambiguous identities, and zero residual on all
    38,025 unique pairs.
  • Provider-native comparisons independently cover JPSS ATMS and EUMETSAT
    Metop overlaps; the Metop conversion remains tolerance-qualified.
  • The existing NNJAObsConv same-input output remains exact.

On the current reviewed head, 40 focused NNJA data/lexicon tests pass with two
slow network tests deselected; Ruff, Black, source-module mypy, and
git diff --check also pass. The complete execution packet must be rerun on the
final reviewed commit before the PR is marked ready.

Reviewer figures cover every channel and platform. Each page shows the full
unthinned NNJA population, UFS, NNJA-minus-UFS residuals at unique identities,
and overlaid full-population histograms. Temperature maps share a scale; the
residual map uses a separate zero-centered scale. Maps use opaque points and no
geographic binning or display thinning.

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

@aayushg55

Copy link
Copy Markdown
Collaborator Author

AMSU-A validation — NNJA aggregate vs UFS/GSI

Reviewer question: Does the new NNJA AMSU-A datasource preserve the aggregate microwave observations used by the selected UFS/GSI replay across every represented platform and physical channel?

Validation layer: NNJA aggregate-to-UFS/GSI inclusion and value parity for the six-hour cycle centered on 2024-01-01 00 UTC.

  • Platforms: Metop-B, Metop-C, NOAA-15, NOAA-18, and NOAA-19; all 15 channels per platform.
  • Population: 4,889,113 finite, unthinned NNJA rows. Maps and histograms use the complete populations with no display sampling or geographic binning.
  • Matching: identity fields only (observation values excluded), unique one-to-one pairs, and no NNJA-row reuse.
  • Result: all 466,837 UFS/GSI rows have unique NNJA matches. Maximum channel RMS is 7.04e-6 K and maximum absolute residual is 1.47e-5 K.
  • Limitations: UFS/GSI is a selected diagnostic, not a raw-population oracle. Sixteen platform/channel cells have no diagnostic rows and are shown explicitly. Metop-B channel 15 and NOAA-15 channels 11 and 14 have no finite NNJA rows in this cycle. The captured replay uses ta2tb=false, so this validates the encoded TMBR values used by that replay, not an antenna-temperature correction.

The numeric source for these figures is reviewer-microwave/channel_metrics.csv; exact input hashes and figure paths are recorded in reviewer-microwave/manifest.json. Figures were generated by scripts/plot_nnja_microwave_review.py.

Metop-B — channels 1–15 (4 pages)

AMSU-A Metop-B channels 01–04

AMSU-A Metop-B channels 05–08

AMSU-A Metop-B channels 09–12

AMSU-A Metop-B channels 13–15

Metop-C — channels 1–15 (4 pages)

AMSU-A Metop-C channels 01–04

AMSU-A Metop-C channels 05–08

AMSU-A Metop-C channels 09–12

AMSU-A Metop-C channels 13–15

NOAA-15 — channels 1–15 (4 pages)

AMSU-A NOAA-15 channels 01–04

AMSU-A NOAA-15 channels 05–08

AMSU-A NOAA-15 channels 09–12

AMSU-A NOAA-15 channels 13–15

NOAA-18 — channels 1–15 (4 pages)

AMSU-A NOAA-18 channels 01–04

AMSU-A NOAA-18 channels 05–08

AMSU-A NOAA-18 channels 09–12

AMSU-A NOAA-18 channels 13–15

NOAA-19 — channels 1–15 (4 pages)

AMSU-A NOAA-19 channels 01–04

AMSU-A NOAA-19 channels 05–08

AMSU-A NOAA-19 channels 09–12

AMSU-A NOAA-19 channels 13–15

@aayushg55

Copy link
Copy Markdown
Collaborator Author

Validation method — locating NNJA observations at UFS/GSI diagnostic locations

The UFS/GSI files are treated as a selected diagnostic population, not as the raw-source population oracle. The comparison asks whether each diagnostic row can be traced uniquely to the corresponding NNJA aggregate observation and whether its value agrees after any documented GSI-side transform.

  1. Read the complete six-hour NNJA aggregate and the UFS/GSI diagnostic for the same cycle.
  2. Restrict both sides to the same sensor, platform, physical channel, variable, and finite physical range.
  3. Build candidate identities from observation metadata: platform, sensor, channel, scan position, and bounded latitude/longitude/time agreement. Observation values are never used to choose a match.
  4. Require a unique one-to-one assignment. An NNJA row cannot be reused; unmatched and ambiguous diagnostic identities are counted separately rather than forced.
  5. For AMSU-A, AMSU-B, and MHS, compare aggregate TMBR directly. For ATMS, first apply the documented GSI spatial/beamwidth averaging to NNJA TMANT, then compare that transformed value with the diagnostic.
  6. Only after identities are frozen, compute per-channel bias, RMS, maximum absolute residual, and matched/unmatched counts.
  7. Plot the complete finite NNJA population, selected UFS/GSI population, uniquely matched NNJA population, residuals, and full-population histogram overlays. No geographic binning or display thinning is used.

This establishes UFS/GSI inclusion and value parity. It does not prove that every finite NNJA observation is scientifically usable, or that UFS/GSI selection is the only valid quality policy. Exact input hashes, matching manifests, and figure paths are in reviewer-microwave/manifest.json; channel metrics are in reviewer-microwave/channel_metrics.csv.

@aayushg55

Copy link
Copy Markdown
Collaborator Author

AMSU-B validation — 2004 UFS/GSI parity and late-life NOAA-16 source degradation

Reviewer questions: Does NNJA reproduce the AMSU-B observations selected by UFS/GSI, and do the aggregates expose enough metadata to identify late-life channel degradation?

The identity and one-to-one assignment rules are documented in the shared matching procedure. Observation values are not used to choose matches.

2004 UFS/GSI selection-parity result

  • Cycle: 2004-01-01 00 UTC; NOAA-15, NOAA-16, and NOAA-17; all five physical channels.
  • Complete finite NNJA population: 9,150,780 rows (unthinned).
  • UFS/GSI diagnostic population: 118,460 rows.
  • Unique one-to-one matches: 118,300. The remaining 160 diagnostic identities are explicitly ambiguous NOAA-17 cases (32 per channel); none are forced or counted as value matches.
  • Every unique pair has an exact 0 K residual. Thus this establishes value parity for the uniquely traceable UFS/GSI-selected population.
2004 platform/channel evidence (3 figures)

NOAA-15 — channels 1–5

AMSU-B NOAA-15 channels 1–5

NOAA-16 — channels 1–5

AMSU-B NOAA-16 channels 1–5

NOAA-17 — channels 1–5

AMSU-B NOAA-17 channels 1–5

Historical NOAA-16 source-quality finding

The late-life behavior is best described as progressive distribution broadening, not assigned a causal label such as “corruption.” Channels 3–5 broaden substantially from 2004 through 2012/2013 and into 2014; by May 2014, channels 4–5 are absent from the audited aggregate. An independent Earth2Bufr decode agrees with Earth2Studio on all 36 public fields for the January 2014 sample (channel RMS differences approximately (5–8 × 10^{-6}) K), so the abnormal distributions are source content rather than an Earth2Studio decoding artifact.

The audited NNJA aggregate’s channel-, scan-, granule-, and geolocation-quality fields are null, and the available correction field is constant rather than observation-varying QC. In other words, NNJA does not expose a usable per-row flag that says when these late-life channels remain scientifically usable.

Historical GSI satinfo is therefore useful operational evidence: iuse=1 means the channel was active in that configuration, while iuse=-1 means it was not used. The pinned replay files already make all amsub_n16 channels passive by May 2009 and keep them passive in 2013. This is an assimilation-policy signal—not a universal sensor-health oracle—and can be conservative. The available UFS replay/configuration record ends in 2025; later periods need newer operational configuration plus instrument-status evidence or an explicitly reviewed manual extension.

Practical consequence: finite late-life NOAA-16 AMSU-B values should not automatically be treated as training-ready. A platform × channel × time validity policy is required.

NOAA-16 historical source audit (2 figures)

January 2014 independent-source parity

AMSU-B NOAA-16 January 2014 independent source parity

Distribution evolution: 2004, 2012, and January 2014

AMSU-B NOAA-16 source distributions 2004 2012 and January 2014

Reproduction details and exact source hashes are in reviewer-microwave/manifest.json; per-channel match statistics are in reviewer-microwave/channel_metrics.csv; the historical interpretation and pinned satinfo evidence are documented in .pr-material/artifacts/AMSUB_DEGRADED_2014.md.

@aayushg55

Copy link
Copy Markdown
Collaborator Author

MHS validation — NNJA aggregate vs UFS/GSI

Reviewer question: Does the new NNJA MHS datasource preserve the observations selected by the UFS/GSI replay across every represented platform and physical channel?

The identity and one-to-one assignment rules are documented in the shared matching procedure. Observation values are excluded from matching.

  • Cycle: 2024-01-01 00 UTC; Metop-B, Metop-C, and NOAA-19; all five physical channels.
  • Complete finite NNJA population: 10,742,456 rows (unthinned).
  • UFS/GSI diagnostic population: 131,967 rows.
  • Result: all 131,967 diagnostic rows have unique one-to-one NNJA matches, with no ambiguous identities and no NNJA-row reuse.
  • Across the represented platform/channel cells, the maximum RMS residual is 8.06 × 10⁻⁶ K and the maximum absolute residual is 1.47 × 10⁻⁵ K.
  • NOAA-19 channel 3 has finite NNJA observations but no UFS/GSI diagnostic rows in this replay; the figure marks that cell explicitly rather than treating it as a failed match.
  • The captured replay uses ta2tb=false, so this establishes parity for the encoded aggregate TMBR used by that replay, not validation of an antenna-temperature correction.

UFS/GSI is a selected diagnostic population, not a raw-population completeness oracle. The maps and histograms show the complete finite NNJA population alongside the selected and uniquely matched populations; no geographic binning or display thinning is used.

MHS platform/channel evidence (3 figures)

Metop-B — channels 1–5

MHS Metop-B channels 1–5

Metop-C — channels 1–5

MHS Metop-C channels 1–5

NOAA-19 — channels 1–5

MHS NOAA-19 channels 1–5

The numeric source is reviewer-microwave/channel_metrics.csv; exact input hashes and figure paths are in reviewer-microwave/manifest.json. Figures were generated by scripts/plot_nnja_microwave_review.py.

@aayushg55

Copy link
Copy Markdown
Collaborator Author

ATMS validation — NNJA aggregate vs UFS/GSI after GSI spatial averaging

Reviewer question: Does the new NNJA ATMS datasource reproduce the observations selected by UFS/GSI across every represented platform and physical channel when the diagnostic’s preprocessing is modeled correctly?

The identity and one-to-one assignment rules are documented in the shared matching procedure. Observation values are excluded from matching.

Result

  • Cycle: 2024-01-01 00 UTC; Suomi-NPP, NOAA-20, and NOAA-21; all 22 physical channels.
  • Complete finite NNJA population: 50,992,128 rows (unthinned).
  • UFS/GSI diagnostic population: 497,279 rows.
  • Result: all 497,279 diagnostic rows have unique one-to-one NNJA matches, with no ambiguity and no NNJA-row reuse.
  • Across all diagnostic-bearing platform/channel cells, the maximum RMS residual is 8.38 × 10⁻⁶ K and the maximum absolute residual is 6.88 × 10⁻⁵ K.

Why ATMS uses a transformed comparison

For ATMS, the UFS/GSI diagnostic is not compared directly with a single raw aggregate sample. The validation first applies the documented GSI spatial/beamwidth averaging to NNJA TMANT, then compares that transformed value with the diagnostic. This distinction is material: comparing the diagnostic to the untransformed brightness-temperature path produces a roughly 0.45 K bias, while the GSI-equivalent transformed antenna-temperature comparison closes to numerical precision.

The figures therefore show both the complete untransformed NNJA source population and the correctly transformed uniquely matched population. This validates the GSI-facing preprocessing path without hiding the raw NNJA distribution.

NOAA-21 has finite NNJA observations for all 22 channels but no diagnostic rows because the replay configuration marks that platform passive (iuse=-1). All 22 no-diagnostic platform/channel cells are shown explicitly; they are not NNJA missing-data failures. UFS/GSI remains a selected diagnostic population, not a raw-population completeness oracle.

Suomi-NPP — channels 1–22 (6 figures)

ATMS Suomi-NPP channels 01–04

ATMS Suomi-NPP channels 05–08

ATMS Suomi-NPP channels 09–12

ATMS Suomi-NPP channels 13–16

ATMS Suomi-NPP channels 17–20

ATMS Suomi-NPP channels 21–22

NOAA-20 — channels 1–22 (6 figures)

ATMS NOAA-20 channels 01–04

ATMS NOAA-20 channels 05–08

ATMS NOAA-20 channels 09–12

ATMS NOAA-20 channels 13–16

ATMS NOAA-20 channels 17–20

ATMS NOAA-20 channels 21–22

NOAA-21 — channels 1–22, passive in replay (6 figures)

ATMS NOAA-21 channels 01–04

ATMS NOAA-21 channels 05–08

ATMS NOAA-21 channels 09–12

ATMS NOAA-21 channels 13–16

ATMS NOAA-21 channels 17–20

ATMS NOAA-21 channels 21–22

Maps and histograms use complete populations with no geographic binning or display thinning. The numeric source is reviewer-microwave/channel_metrics.csv; exact input hashes, transform metadata, and figure paths are in reviewer-microwave/manifest.json. Figures were generated by scripts/plot_nnja_microwave_review.py.

@aayushg55

aayushg55 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

Important Notes

Encoded field versus physical quantity

ATMS is the only feed in this PR that encodes separate TMANT and TMBR
fields. The legacy 1bamua, 1bamub, and 1bmhs products encode only
TMBR, but that mnemonic is overloaded.

Feed Encoded fields Audited physical interpretation
ATMS TMANT and TMBR Explicit antenna temperature (Ta) and scene brightness temperature (Tb)
NOAA-15/16 AMSU-A TMBR only Upstream antenna-corrected brightness temperature (Tb)
Other AMSU-A platforms TMBR only Interpreted by GSI as antenna temperature (Ta)
MHS TMBR only Ta interpretation supported by GSI and producer comparisons
AMSU-B TMBR only Interpreted by GSI as Ta; no independent producer-level closure is available

For the legacy feeds, TMBR therefore does not guarantee a common physical
antenna-correction state. The pinned
GSI normal-feed reader
treats NOAA-15/16 AMSU-A as already corrected upstream and interprets the other
audited legacy platform feeds as antenna temperature, applying the Ta-to-Tb
correction downstream. NOAA satingest independently confirms the NOAA-15/16
AMSU-A exception through its
coefficient selection
and Ta-to-Tb implementation. This is a limitation of the NCEP processing.

NNJAObsSat preserves the encoded value and platform identity exactly. It does
not normalize this platform-dependent convention or apply a Ta-to-Tb
conversion. The ta2tb correction is a simply affine transormation. We could expose it ourselves, we just require the coefficients.

For reference, see these NOAA GSI issues https://redirect.github.com/NOAA-EMC/GSI/issues/341 (traditionally assimilated ta not tb) and the follow up https://redirect.github.com/NOAA-EMC/GSI/issues/380 (identified N15/N16 AMSU-A was actually tb).

Quantization

NCEP already quantized the input to 0.01 K. This is what the GSI consumes.

@aayushg55
aayushg55 requested a review from NickGeneva July 15, 2026 00:28
self._handle_fetch_failure(file_uri_set, exc)
raise

df = self._compile_dataframe(async_tasks, schema)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this loses the fix from #971: _compile_dataframe is CPU-bound (and internally blocks on pool futures), so calling it synchronously inside fetch stalls the shared fsspec IO loop that _sync_async dispatches every data source's fetch onto. #966 kept it as df = await asyncio.to_thread(self._compile_dataframe, async_tasks, schema) in utils_ncep.py, but the move into _NCEPObsSourceBase.fetch here dropped the to_thread wrapper. Suggest restoring:

df = await asyncio.to_thread(self._compile_dataframe, async_tasks, schema)

@aayushg55 aayushg55 Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I will update this once the base PR is merged, bringing in the fix from main. (This branch is also out of date with the base PR branch since it is currently being revised.)

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