Serve weather data from GHCNh through a generic load_data api - #103
Conversation
9cc2451 to
a725d05
Compare
|
Good thinking on using a coordinate distance search to map GHCNh stations to ISD equivalents when they don't match by
You folks seem to have a pretty robust process for evaluating data quality and ranking stations, so probably not a useful addition here. I was just getting tired of depending on NOAA to update their station inventory file, which hasn't been updated since February. It also provides per-parameter coverage which was important to me. |
|
Thanks, that's a useful find. For the id mapping itself we're in good shape: the ICAO/WBAN/coordinate mapping in this PR was cross-validated against isd-history coordinates and an overlap comparison of served data, so the search endpoint would mostly confirm what the packaged registry already encodes. Where it looks genuinely valuable is the per-station-year dataTypes listing in its responses. The registry's ghcn_inventory table carries total monthly observation counts per station, with no per-variable dimension, so station quality ratings and ranking are effectively temperature-anchored, and a request for something like variables=("wind_speed",) can return an all-NaN column from a station that simply never reports it. Presence-by-variable-by-year from this endpoint is exactly the information needed to close that: it could ship in a future registry update and feed station selection for non-temperature variables. |
|
Yep, exactly my thoughts. You've already validated the mapping by cross comparison of data during overlapping coverage dates so no need to re-invent the wheel there, that analysis was thoroughly convincing. As you mentioned, only potential area of added value from this endpoint is for improving the detail of station quality ratings. Great work so far! |
| return window_start, window_end | ||
|
|
||
|
|
||
| def _quality_from_minimum(minimum): |
There was a problem hiding this comment.
same calculation is written out separately in 3 spots: here, get_station_qualities(), and _compute_station_quality_from_ghcnh() in database.py
should consolidate them or at least share constants if it's an optimization issue
- fetch_isd_raw_temp_data_old / fetch_gsod_raw_temp_data_old, the NOAA FTP connection proxy, and their testing mocks and packaged sample files - ftp.ncei.noaa.gov no longer serves these files; nothing referenced them Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- ghcn_id and ghcn_map_method columns on isd_station_metadata, built by
ICAO join (nearest candidate within 50 km), USW000{wban} id pattern
(within 50 km), then nearest GHCNh station within 5 km
- 349 of 4845 stations have no GHCNh counterpart and are removed from the
packaged database (3 high / 7 medium / 339 low quality)
- rebuild pipeline downloads the GHCNh station list and applies the same
mapping; isd-history/isd-inventory downloads move from dead ftp to https
- ranking/summary snapshots and metadata pins updated for the reduced
registry
Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
Replaces the ISD/GSOD fetch and load stack. ISD and GSOD stopped receiving data 2025-08-27; GHCNh serves the same stations with history back decades and current data. - eeweather/sources/ghcnh.py fetches multi-variable hourly frames from the NCEI access api (endpoint identified by k-wolfe99 in #100) - load_data(usaf_id, start, end, frequency, variables) returns a DataFrame and warnings list, replacing the load_isd_*/load_gsod_* family; daily values are means of hourly values - ISDStation renamed WeatherStation with a load_data method; ghcn_id attribute added - caching stores all fetched variables per station-year under new ghcnh-hourly-* keys; refreshes request the union of requested and cached variables; ISD-era cache entries never match again - ISDDataNotAvailableError/GSODDataNotAvailableError collapse to DataNotAvailableError; inspect-isd-filenames CLI commands deleted - fix WeatherStation.deserialize_tmy3_hourly_temp_data delegating to the ISD deserializer - tests migrated to GHCNh fixtures; pins from captured payloads including truncation (723826, decommissioned 2013-11-04), internal gap (720193 2019), no-observation year (722874 2025), and a cross-source test pinning 2007 means against the ISD-era values Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- docs/ tree deleted; documentation home is opendsm.energy - README documents the load_data api and GHCNh source - scripts/validate_ghcnh_against_isd.py reproduces the ISD overlap validation (38 station-years: median hourly deviation 0.0001 C, max annual-mean deviation 0.05 C, GHCNh coverage >= ISD) Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
…ected coordinates - cross-source ISD pin test removed; overlap validation (38 station-years, median hourly deviation 0.0001 C) is the consistency evidence - isd-history longitude for 725374 is off by 4 degrees (places the station in Lake Michigan); corrected against the physical site and GHCNh, which restores its icao mapping to USW00094889. Correction applied in the rebuild pipeline via ISD_COORDINATE_CORRECTIONS - registry: 4497 stations, all GHCNh-mapped Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- up to 2 high, 1 medium, 1 low quality stations per state and territory: 210 stations, 840 station-years over 2016/2019/2022/2024 - per-station-year results written to validation_results.csv Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- immediate retries land inside the api's intermittent 5xx bursts; retries now wait 5s then 10s - port retry, parsing, empty-year, and duplicate-timestamp tests to the ghcnh source module - validation script skips failed station-years and writes results incrementally Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- ghcn_first_year/ghcn_last_year columns from the GHCNh inventory, on the packaged database and the rebuild pipeline; exposed on WeatherStation and its json - 892 of 4497 stations (846 low, 27 medium, 19 high quality) have no observations after 2023; era columns let ranking and callers filter by data availability instead of discovering empty fetches Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- same thresholds as the ISD-inventory rating (every month of the last 5 full years over 600 observations = high, over 360 = medium), applied to GHCNh monthly counts; the ISD-inventory rating is deleted - tiers move for about a fifth of stations: 1858 high / 393 medium / 2246 low; 332 stations undercounted by the retired ISD inventory upgrade to high, 164 recently-dead stations drop out of high - ranking pins and snapshots updated for the new tiers Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- get_station_quality(usaf_id, start, end) and get_station_qualities (whole-registry, one query) rate stations from GHCNh monthly counts over the five calendar years ending two years after the request's last date, sliding back to end no later than the last full year; every month over 600 observations is high, over 360 medium, less or absent is low - rank_stations(..., rating_period=(start, end)) filters and reports quality for the request's era; stations dead today rate high in their active years - ghcn_inventory table (monthly counts per registry station-year) ships in the packaged database and the rebuild pipeline - a rating_period ranking costs about 70 ms warm; the default path is unchanged Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- test fixture CSVs move from eeweather/resources to tests/fixtures and the shipped testing module folds into tests/conftest.py; nothing outside the test suite consumed either - tmy3-stations.html (rebuild-time primary source; its NREL page no longer exists) moves to scripts/data - the tutorial notebook taught the removed api; documentation lives at opendsm.energy Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
- lives in utils.py; single-station get_ghcn_id remains in stations Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
Signed-off-by: Travis Sikes <124101151+travis-recurve@users.noreply.github.com>
a725d05 to
71fd9d8
Compare
Your checklist for this pull request
Please review the guidelines for contributing to this repository.
Description
Serves observed weather data from NOAA GHCNh, resolving #100. ISD and GSOD stopped receiving data 2025-08-27; GHCNh serves the same stations through the same NCEI access api (endpoint identified by @k-wolfe99 in #100) with history back decades and current data. Based on #102; the commits unique to this pull request start at "Delete dead FTP fetch path".
Because this is a breaking release, the api is consolidated rather than aliased:
load_data(usaf_id, start, end, frequency, variables)returns a DataFrame and a warnings list, replacing theload_isd_*/load_gsod_*family; daily values are means of hourly values. GHCNh variables beyond temperature (dew point, relative humidity, wind speed, ...) are available throughvariablesISDStationis renamedWeatherStation, withghcn_id,ghcn_first_year, andghcn_last_yearattributesStation registry:
USW000{wban}pattern → nearest neighbor within 5 km, with a 50 km sanity guard that caught one ICAO reuse). 349 stations with no GHCNh counterpart are removed; 99.8% of high-quality stations maprank_stations(..., rating_period=...),get_station_quality), rating the five calendar years ending two years after the request's last dateghcn_first_year/ghcn_last_yearrecord each station's data era; about a fifth of the registry, nearly all low quality, has no observations after 2023Validation:
scripts/validate_ghcnh_against_isd.pycompares both sources through the library's pipeline over a stratified sample of 210 stations (every state and territory, all quality tiers) × 4 years: over 572 comparable station-years, the median hourly deviation is 0.0001 °C and the largest annual-mean deviation is 0.14 °C. GHCNh hourly coverage matches or exceeds ISD's at the median