Integrate refractivity with shape-preserving quadrature and use virtual temperature - #816
Open
jlmaurer wants to merge 6 commits into
Open
Integrate refractivity with shape-preserving quadrature and use virtual temperature#816jlmaurer wants to merge 6 commits into
jlmaurer wants to merge 6 commits into
Conversation
…temperature
Two independent biases in the zenith delay calculation:
1. Quadrature. The trapezoid rule is exact integration of a piecewise-linear
reconstruction, which systematically overestimates the delay because
refractivity is convex in height. Replaced with exact quadrature of a
shape-preserving piecewise cubic Hermite (PCHIP) reconstruction. PCHIP is
used rather than a natural cubic spline because it introduces no new
extrema and cannot overshoot, so it never manufactures structure the
weather model does not contain -- a natural cubic spline on these profiles
undershoots into negative wet refractivity on most grid columns.
2. Hydrostatic refractivity used k1 * P / T, but all models use the
compensated wet coefficient k2' = k2 - k1*Rd/Rv (0.233 K/Pa), which assumes
the hydrostatic term is written with virtual temperature. Pairing k1*P/T
with k2' double-counts part of the water-vapor contribution (~2% of the wet
delay). Now uses the exact identity
k1 * P / Tv = k1 * (P - (1 - Rd/Rv) * e) / T, matching the GNSS ZHD/ZWD
convention.
Validation: ERA-5 over southern California, four dates (2020-01-01,
2025-01-01, and the two late-summer water-vapour maxima 2020-08-24 and
2025-09-19), comparing the coarse 32-level pressure-level grid against the
145-level native grid at four UNR GNSS station locations. Mean |error| in
total ZTD across all dates and stations:
trapezoid 8.74 mm (max 11.69)
PCHIP 1.46 mm (max 3.73)
The effect is confined to the pressure-level path; on the native model-level
grid every rule agrees to better than 0.3 mm.
The mock weather model in the tests keeps a linear-in-z profile, for which the
shape-preserving cubic is exact, so the closed-form ZTD assertions still hold
with only the virtual-temperature change applied.
The processed fixtures store precomputed wet/hydro refractivity and wet_total/hydro_total, and the tests that assert delay values read those stored cubes rather than recomputing them. They therefore encoded the old k1*P/T refractivity and trapezoid quadrature, and would have kept passing unchanged while silently asserting superseded numbers. Recompute the derived cubes from each fixture's own stored t/p/e. Every step that produces t/p/e is untouched here, so this reproduces exactly what the current pipeline would write for the same raw input, with no re-download. The reconstruction was checked before anything was overwritten: recomputing wet, whose formula is unchanged, reproduced the stored values bit-exactly, as did recomputing hydro under the old k1*P/T form -- confirming both that the stored t/p/e are the true inputs and that the fixtures carried the old physics. All four fixtures behind golden values are native model-level grids, so the shift is dominated by the virtual-temperature correction rather than the quadrature change, and it scales with water vapour as expected: the surface hydrostatic delay drops 1.2 mm over dry HRRR CONUS and 4.95 mm over equatorial Brazil. The four 33.7 MB HRRR inputs under gunw_azimuth_test_data are deliberately left alone: no golden value depends on them, regenerating would add ~135 MB of binary churn, and dbekaert#815 proposes untracking them entirely. The derived GMAO _timeInterp_ products are left alone too; dbekaert#814 untracks them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Herbie tries each source it knows until one has the file, so a dead mirror costs nothing when the file exists and everything when it does not. The University of Utah Pando archive is being wound down in favour of NOAA's Registry of Open Data on AWS, and pando-rgw01/02.chpc.utah.edu now resolve in DNS while accepting no connections. check_hrrr_dataset_availability asks precisely the question that walks the whole source list: is this time available? For an unavailable time Herbie reached both dead hosts and blocked on each until TCP timeout, raising ConnectTimeout after ~150s instead of returning False. Measured on the 2016-08-09 16:00 case the test uses: 151.9s and an exception before, 1.1s and the correct answer after. Filter the retired entries out of the source list the model's own Herbie template declares, rather than hard-coding the survivors. New mirrors are then picked up automatically, and each model keeps Herbie's ordering -- hrrr tries AWS first while hrrrak tries NOMADS first, so a single hard-coded list would silently reorder one of them. Model names are lower-cased first, as Herbie does internally, because the GUNW workflow reaches this code with 'HRRR'. Note this is not fixed by upgrading Herbie: current Herbie main still lists both Pando entries, and no upstream issue tracks it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jlmaurer
force-pushed
the
pr/integration_fix
branch
from
August 16, 2026 00:40
7bccb9d to
76d6bc5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent corrections to how zenith delay is computed from a weather model, plus the fixture regeneration they require.
1. Hydrostatic refractivity from virtual temperature
_get_hydro_refractivityusedk1 * P / T. Every model in the package setsk2 = 0.233 K/Pa, which is the compensated coefficientk2' = k2 - k1 * Rd/Rv(Bevis/Davis:0.716 - 0.776 x 0.6221 = 0.2333). That coefficient pairs withk1 * Rd * rho = k1 * P / Tv, not withk1 * P / T; pairing it withP / Tdouble-counts part of the water-vapour contribution.The fix uses the exact identity
k1 * P / Tv = k1 * (P - (1 - Rd/Rv) * e) / T.This lowers the total delay by roughly 2% of the zenith wet delay — a few mm in typical conditions — so it is not merely a re-split between the hydrostatic and wet components. Absolute delays change for every weather model.
2. Refractivity integrated by shape-preserving quadrature
Every quadrature rule is exact integration of some interpolant. The trapezoid rule integrates a piecewise-linear reconstruction, and refractivity is convex in height, so it systematically overestimates the delay. On the coarse 32-level pressure-level z-grid that bias reaches ~9 mm of zenith delay.
_getZTDnow integrates a shape-preserving piecewise cubic Hermite (PCHIP) reconstruction instead, evaluating its antiderivative analytically. PCHIP rather than a natural cubic spline because it introduces no new extrema and cannot overshoot — a natural spline undershoots into negative wet refractivity on the majority of grid columns, which is unphysical.Validation
ERA-5 across three climate regimes, 596 grid columns, comparing the 32-level pressure-level grid against the 145-level native grid:
The control that matters: on the native grid the two rules agree to 0.32 mm, so the reference is essentially rule-independent rather than flattering PCHIP.
The improvement is climate-dependent, and the wet tropics are the weak case:
In humid equatorial columns PCHIP still leaves ~4 mm (max 13 mm): 32 levels cannot resolve the near-surface water-vapour profile, and no quadrature rule recovers data that is not there. Brazil is also the only case where the trapezoid bias is not one-signed (87% of columns overestimate, versus 100% elsewhere).
Native model-level runs are effectively unaffected, so this matters specifically for pressure-level (
pl) configurations.Memory
Building one PCHIP interpolator over a whole cube costs ~20x the cube in float64 temporaries — several GB for a CONUS-sized grid.
cumulative_integral_from_toptherefore processes columns in chunks against a fixed budget. Peak is now2x cube + ~90 MBrather than~20x cube(measured: a 15.4 MB float32 cube peaks at 129 MB instead of ~320 MB; extrapolated to a CONUS HRRR grid, ~850 MB instead of ~7.5 GB). Columns are independent, so the result is bit-identical for any chunk size — pinned by a test that compares one-column-per-chunk against a single chunk witharray_equal.3. Regenerated test fixtures and golden values
The processed weather-model fixtures store precomputed
wet,hydro,wet_totalandhydro_total, and the tests that assert delay values read those stored cubes rather than recomputing them. They therefore encoded the old physics, and would have kept passing unchanged — silently asserting superseded numbers.Eight fixtures were regenerated by recomputing the derived cubes from their own stored
t/p/e. Every step that producest/p/eis untouched by this PR, so this reproduces exactly what the current pipeline would write for the same raw input, without re-downloading.The reconstruction was validated before anything was overwritten: recomputing
wet(whose formula is unchanged) reproduced the stored values bit-exactly, as did recomputinghydrounder the oldk1*P/Tformula — confirming both that the storedt/p/eare the true inputs and that the fixtures were generated with the old physics.Updated golden values:
test_HRRR_ztd(hydro)test_slant_projtest_ray_tracingtest_gnss_intersectAll four fixtures here are native model-level grids, so the shift is dominated by the virtual-temperature correction rather than the quadrature change. It scales with water vapour as expected — the surface hydrostatic change ranges from -1.2 mm over dry HRRR CONUS to -4.95 mm over equatorial Brazil.
Not regenerated: the four 33.7 MB HRRR inputs under
test/gunw_azimuth_test_data/weather_files/. They backtest_azimuth_timing_interp_against_center_time_interp, which compares azimuth-time against center-time interpolation and is self-consistent either way, so no golden value depends on them. Regenerating would add ~135 MB of binary churn to this PR, and #815 proposes untracking them entirely.4. Unrelated CI fix: retired HRRR mirror
test_hrrr_availability_check_using_gunw_idswas failing in CI with a socket timeout. This turned out to be unrelated to the changes above and pre-existing.Herbie tries each HRRR source it knows until one has the file. The University of Utah Pando archive is being wound down in favour of NOAA's Registry of Open Data on AWS, and
pando-rgw01/pando-rgw02.chpc.utah.edunow resolve in DNS while accepting no connections. Verified directly:noaa-hrrr-bdp-pds.s3.amazonaws.comnomads.ncep.noaa.govstorage.googleapis.comnoaahrrr.blob.core.windows.netpando-rgw01.chpc.utah.edupando-rgw02.chpc.utah.eduA dead mirror costs nothing when the file exists — but
check_hrrr_dataset_availabilityasks exactly the question that walks the entire list. For an unavailable time Herbie reached both dead hosts and blocked on each until TCP timeout:That is why only the negative assertion failed, and why it was intermittent: the positive case (2023, available) stops at AWS immediately.
Measured on the exact case the test uses: 151.9 s and an exception before, 1.1 s and the correct
Falseafter. The previously failing test now passes in 25.9 s.The retired entries are filtered out of the source list the model's own Herbie template declares, rather than hard-coding the survivors: new mirrors are picked up automatically, and each model keeps Herbie's ordering —
hrrrtries AWS first whilehrrraktries NOMADS first, so a single hard-coded list would silently reorder one of them.Note this is not fixed by upgrading Herbie — current Herbie main still lists both Pando entries, and no upstream issue tracks it. Worth reporting there separately, since every Herbie HRRR user hits this on any unavailable date.
Known limitation: the ray-traced path
The ray-tracing path still integrates the trapezoid reconstruction, so zenith and ray-traced outputs will now differ by roughly 9 mm on pressure-level models. This is deliberate — see #817 for the analysis and why it needs its own PR.
Tests
Full suite (
-m "not long"): all pass excepttest_hrrr_availability_check_using_gunw_ids, which hits live HRRR servers and fails with a socket timeout on this network, unrelated to these changes.