Problem
The location or region of several US station records does not match the station named by the record's identifiers.
- Record: name "Fort Huachuca, Libby Aaf Ft Huachuca", region AZ, location 47.6333, -110.3333, elevation 1438, timezone America/Phoenix.
- Identifiers: WMO 72273, ICAO KFHU, WBAN 03124, USAF 722730, GHCN USW00003124. All refer to Libby Army Airfield, Sierra Vista, AZ.
- NCEI location for 722730-03124: 31.58833, -110.34417 (
global-hourly/access/2023/72273003124.csv). api.weather.gov/stations/KFHU: [-110.33333, 31.58333].
- The record location is in Chouteau County, Montana, 1,785 km from the station.
- The location is unchanged since the first commit of this repository (dc56eb6).
- Record: name "Noorvik / Andrewsville", region AK, location 38.8495, -75.6128, elevation 20, timezone America/New_York.
- Identifiers: ICAO PFNO, WBAN 00113, USAF 704898 (Robert Curtis Memorial Airport, Noorvik, AK).
api.weather.gov/stations/PFNO: [-161.0223, 66.8175], elevation 17 m, timezone America/Anchorage. NCEI: 66.818, -161.022.
- The record location is in Kent County, Delaware.
Name and region belong to a different station than the identifiers, coordinates and data
In these four records the name and region are consistent with each other but describe a different place than the ICAO/WBAN/USAF identifiers and the coordinates. The hourly data follows the identifiers: heating degree-days (base 65 °F) of the 2023 hourly series for each id are close to those of stations near the record coordinates and far from those of stations where the name points.
| id |
name / region in record |
identifiers and coordinates (NCEI ISD) |
HDD65 2023, this id |
HDD65 2023 near the name |
HDD65 2023 near the coordinates |
| KBKL0 |
Brookville / Old Chinatown, PA |
Cleveland Burke Lakefront Airport, OH (KBKL, 725245-04853) |
4,549 |
Jefferson County PA (Brookville): 5,299 |
Lorain County OH: 5,033 |
| KDVP0 |
Davenport / Slayton, IA |
Slayton Municipal Airport, MN (KDVP, 720368-54924) |
7,557 |
Scott County IA (Davenport): 5,320 |
Nobles County MN: 7,286 |
| KMJX0 |
Toms River / Dover Forge, NH |
Ocean County Airport, NJ (KMJX, 720407-00462) |
4,177 |
Rockingham County NH: 5,317 |
Monmouth County NJ: 4,120 |
| 72540 |
Spickard, MI |
Spickard, MO (GHCN USC00237963, USAF 725400) |
4,890 |
Ingham County MI: 5,673 |
Livingston County MO: 4,535 |
NOAA's ISD station list has a separate historical station "BROOKVILLE FAA AP, PA" (WBAN 14741, 41.15, -79.10, no ICAO), so the KBKL0 name appears to come from a join between that station and Burke Lakefront. NWS and FAA tables list KDVP as Slayton, MN; Davenport, IA is KDVN. There is no Toms River in NH and no Spickard in MI.
Records with mixed identities
- 72516: name "Bennington / Napoleon", region VT, location 46.4944, -99.7601 (Napoleon, ND), ICAO K5B5, GHCN USW00003761 (Avondale 2 N, PA). The hourly data for this id is consistent with Napoleon, ND.
- 72555: name "Burwell / Engle", region NE, location 37.3874, -83.2616 (same as KCPF0, Hazard, KY), ICAO KK20, GHCN USW00013301 (Chillicothe 22 ENE, MO).
Effect
Stations().nearby() (1.x) and stations.nearby() (2.x) rank stations by the record location. For points in central Montana, 72273 is returned as the nearest station; for points in Kent County, DE and Caroline County, MD, PFNO0 is. The hourly data served for these ids is from Sierra Vista, AZ and Noorvik, AK. Checked against NCEI: for 2023-07-15, the 72273 series equals 72273003124.csv in 14 of 16 hours to 0.1 °C after the UTC-7 shift; for 2022-01-15, the PFNO0 series and 70489800113.csv are both between -12.2 and -13.3 °C in every hour.
Possible sources of the errors
The records look like joins of several NOAA, NWS and FAA station tables on station codes (ICAO code, FAA identifier, WMO/synop number), without a check that the joined fields describe the same place. What can be traced:
-
72273: the NWS station table nsd_cccc.txt (tgftp.nws.noaa.gov/data/nsd_cccc.txt; 2015 copy here) contains:
KFHU;72;273;Fort Huachuca, Libby AAF Ft Huachuca;AZ;United States;4;46-98N;110-20W;;;1438;;
The latitude field "46-98N" has 98 minutes. 46 + 98/60 = 47.6333. The record name, elevation and longitude also match this row. Other projects that parsed this table carry the same value (GitHub code search for "Libby AAF Ft Huachuca"). The NWS API now returns 31.58333 for KFHU.
-
72516: NWS/AWIPS station tables assign synop number 72516 to "K5B5 Bennington/Wm H Morse State, VT" (for example Unidata/awips2 metarStationInfo.txt: 0000072516|K5B5 | 42.89 | -73.25 | 252|Bennington/Wm H Morse State, VT). The FAA identifier 5B5 now belongs to Napoleon Municipal Airport, ND; Bennington is DDH. A record keyed on K5B5 combines the former holder of the identifier (name, region, synop number) with the current holder (coordinates, elevation, METAR data).
-
PFNO0: the record location 38.8495, -75.6128 is Chorman Airport, Farmington, DE (FAA identifier D74, 38.84955, -75.61278), an airfield without a weather station. How PFNO was joined to D74 is not identified. PFNO is not in the 2015 copy of nsd_cccc.txt.
-
KBKL0, KDVP0: the 2015 nsd_cccc.txt rows are correct (KBKL;--;---;CLEVELAND BURKE LAKEFRONT;OH;...;41-32N;81-40W, KDVP;--;---;Slayton, Slayton Municipal Airport;MN;...), so the names "Brookville" and "Davenport" and the regions PA and IA did not come from that table. The source of the substitution is not identified.
-
KMJX0, 72540, 72555: no source identified. KMJX is not in the 2015 copy of nsd_cccc.txt. The 72555 coordinates equal those of KCPF0 (Hazard, KY).
Import script behaviour
scripts/usa/import.py:
find_duplicate() matches an existing record by Meteostat id, then WMO, then ICAO, then proximity within 10 km.
- If a duplicate is found within 1000 m and 25 m elevation, only the ICAO identifier is updated.
- If a duplicate is found by identifier and the locations differ by more than 1000 m, nothing is updated and nothing is logged.
- The loop body is wrapped in
except BaseException: pass.
scripts/qa_check.py checks the id length and that latitude and longitude are within ±90 and ±180. It does not compare region with coordinates.
A record with a wrong location is therefore not corrected when the upstream source is corrected.
Possible corrections
- Values for the six records, if each record is meant to be the station that its identifiers and hourly data belong to:
scripts/usa/import.py: when find_duplicate() matches by identifier and the distance exceeds 1000 m, log the conflict instead of skipping; replace except BaseException: pass with a handler that logs the station id.
duplicate = find_duplicate(data, stations)
if duplicate:
d = get_distance(lat, lon, duplicate["latitude"], duplicate["longitude"])
if d <= 1000 and abs(elevation - duplicate["elevation"]) <= 25:
if data["identifiers"]["icao"]:
update({"id": duplicate["id"], "identifiers": {"icao": data["identifiers"]["icao"]}})
else:
print(f"CONFLICT {duplicate['id']} <- {row['station_id']}: stored "
f"{duplicate['latitude']},{duplicate['longitude']} vs NWS {lat},{lon} ({d/1000:.0f} km)")
else:
data["id"] = generate_uid()
create(data)
scripts/qa_check.py: compare region with coordinates. A bounding box per ISO 3166-2 region is sufficient; over 2,181 US stations this test flags the eight records above and no others. I can help with this if useful.
Related: #469 (72314, fixed in #470), #484 (KLGA/KEWR, fixed in #505).
Problem
The location or region of several US station records does not match the station named by the record's identifiers.
72273
global-hourly/access/2023/72273003124.csv).api.weather.gov/stations/KFHU: [-110.33333, 31.58333].PFNO0
api.weather.gov/stations/PFNO: [-161.0223, 66.8175], elevation 17 m, timezone America/Anchorage. NCEI: 66.818, -161.022.Name and region belong to a different station than the identifiers, coordinates and data
In these four records the name and region are consistent with each other but describe a different place than the ICAO/WBAN/USAF identifiers and the coordinates. The hourly data follows the identifiers: heating degree-days (base 65 °F) of the 2023 hourly series for each id are close to those of stations near the record coordinates and far from those of stations where the name points.
NOAA's ISD station list has a separate historical station "BROOKVILLE FAA AP, PA" (WBAN 14741, 41.15, -79.10, no ICAO), so the KBKL0 name appears to come from a join between that station and Burke Lakefront. NWS and FAA tables list KDVP as Slayton, MN; Davenport, IA is KDVN. There is no Toms River in NH and no Spickard in MI.
Records with mixed identities
Effect
Stations().nearby()(1.x) andstations.nearby()(2.x) rank stations by the record location. For points in central Montana, 72273 is returned as the nearest station; for points in Kent County, DE and Caroline County, MD, PFNO0 is. The hourly data served for these ids is from Sierra Vista, AZ and Noorvik, AK. Checked against NCEI: for 2023-07-15, the 72273 series equals72273003124.csvin 14 of 16 hours to 0.1 °C after the UTC-7 shift; for 2022-01-15, the PFNO0 series and70489800113.csvare both between -12.2 and -13.3 °C in every hour.Possible sources of the errors
The records look like joins of several NOAA, NWS and FAA station tables on station codes (ICAO code, FAA identifier, WMO/synop number), without a check that the joined fields describe the same place. What can be traced:
72273: the NWS station table
nsd_cccc.txt(tgftp.nws.noaa.gov/data/nsd_cccc.txt; 2015 copy here) contains:The latitude field "46-98N" has 98 minutes. 46 + 98/60 = 47.6333. The record name, elevation and longitude also match this row. Other projects that parsed this table carry the same value (GitHub code search for "Libby AAF Ft Huachuca"). The NWS API now returns 31.58333 for KFHU.
72516: NWS/AWIPS station tables assign synop number 72516 to "K5B5 Bennington/Wm H Morse State, VT" (for example Unidata/awips2 metarStationInfo.txt:
0000072516|K5B5 | 42.89 | -73.25 | 252|Bennington/Wm H Morse State, VT). The FAA identifier 5B5 now belongs to Napoleon Municipal Airport, ND; Bennington is DDH. A record keyed on K5B5 combines the former holder of the identifier (name, region, synop number) with the current holder (coordinates, elevation, METAR data).PFNO0: the record location 38.8495, -75.6128 is Chorman Airport, Farmington, DE (FAA identifier D74, 38.84955, -75.61278), an airfield without a weather station. How PFNO was joined to D74 is not identified. PFNO is not in the 2015 copy of
nsd_cccc.txt.KBKL0, KDVP0: the 2015
nsd_cccc.txtrows are correct (KBKL;--;---;CLEVELAND BURKE LAKEFRONT;OH;...;41-32N;81-40W,KDVP;--;---;Slayton, Slayton Municipal Airport;MN;...), so the names "Brookville" and "Davenport" and the regions PA and IA did not come from that table. The source of the substitution is not identified.KMJX0, 72540, 72555: no source identified. KMJX is not in the 2015 copy of
nsd_cccc.txt. The 72555 coordinates equal those of KCPF0 (Hazard, KY).Import script behaviour
scripts/usa/import.py:find_duplicate()matches an existing record by Meteostat id, then WMO, then ICAO, then proximity within 10 km.except BaseException: pass.scripts/qa_check.pychecks the id length and that latitude and longitude are within ±90 and ±180. It does not compare region with coordinates.A record with a wrong location is therefore not corrected when the upstream source is corrected.
Possible corrections
stations/72273.jsonstations/PFNO0.jsonstations/72540.jsonstations/KBKL0.jsonstations/KMJX0.jsonstations/KDVP0.jsonscripts/usa/import.py: whenfind_duplicate()matches by identifier and the distance exceeds 1000 m, log the conflict instead of skipping; replaceexcept BaseException: passwith a handler that logs the station id.scripts/qa_check.py: compare region with coordinates. A bounding box per ISO 3166-2 region is sufficient; over 2,181 US stations this test flags the eight records above and no others. I can help with this if useful.Related: #469 (72314, fixed in #470), #484 (KLGA/KEWR, fixed in #505).