prop/docs/algo-reports/2026-05-04-recalibration.md
Graham McIntire 58f4a7714b
test: add Mox deps + SnmpClient poll/3 tests, RoadProximity, Buildings.Loader
- Add {:mox, "~> 1.0", only: :test} to deps
- Commercial.SnmpClient: injectable snmp_runner for poll/3 tests (62→92%)
- Rover.RoadProximity: pure road_distances/3 tests with injectable fetch (37→82%)
- Buildings.Loader: ensure_loaded/1 with real tile file + quadkey tests (69→100%)
- Buildings.Index: records_near, mark_loaded, loaded? tests (72→96%)

Coverage: 77.96% → 78.93% (+0.97%)
2026-05-07 13:36:22 -05:00

21 KiB
Raw Blame History

Recalibration Analysis Report — 2026-05-04

Auto-generated by scripts/recalibrate_algo.py. This report is the input for algo.md updates — diff against the prior dated section to see what's actually moved.

Connection: postgres://prop:***@10.0.15.30:5432/prop Statement timeout: 20min

Row counts and date ranges

tbl n lo hi
contacts 82084.000 1991-05-04 2026-05-02
hrrr_native_profiles 11472.000 2019-03-09 2025-09-21
hrrr_profiles 81302322.000 2016-09-17 2026-05-02
iemre_observations 28936.000
narr_profiles 395.000 1991-05-04 2014-09-19
nexrad_observations 7286.000 2019-08-17 2024-09-22
propagation_scores nan
soundings 27745.000 1990-06-07 2026-05-04
surface_observations 648809.000 1991-05-03 2026-05-04
terrain_profiles 82084.000

Data gaps and ingestion health

Severity legend: BROKEN = table is empty and feeds an active scoring path; WARN = populated but coverage is low enough to skew per-band statistics; OK = within spec or informational. Each non-OK row carries a one-line remediation hint.

metric value severity remediation
narr_rows 395 OK
narr_pre2014_rows 395 OK
hrrr_climatology_rows 0 BROKEN Should self-heal within 24h via the daily 02:30Z cron that runs AdminTaskWorker(task=climatology). If still 0 after a day, check Oban dashboard for failed admin jobs.
hrrr_complete_contacts 81278 OK
hrrr_pending_contacts 806 OK
pre2014_contacts 207 OK

HRRR enrichment completeness: 99.0% (81,278 complete / 806 pending).

NARR coverage by year

Year-bucketed counts. NARR is supposed to span 1979 → 2014-10 at 3-hourly cadence (~2,920 timestamps per year per grid cell). Years far below the others are partial backfills the worker hasn't finished.

year profiles
1991.000 31.000
1992.000 4.000
1993.000 18.000
1994.000 19.000
1996.000 3.000
1997.000 8.000
1998.000 2.000
1999.000 11.000
2000.000 10.000
2001.000 14.000
2002.000 12.000
2003.000 36.000
2004.000 23.000
2005.000 49.000
2006.000 20.000
2007.000 44.000
2008.000 15.000
2009.000 17.000
2010.000 31.000
2011.000 4.000
2012.000 15.000
2013.000 3.000
2014.000 6.000

HRRR enrichment status by year

Locate the pending backlog: a year with high queued/failed/unset counts is where HrrrFetchWorker needs to be rerun. Recent years dominating queued usually means the live Oban queue is stuck rather than a historical backfill gap.

year complete queued failed unset
2014.000 0.000 0.000 0.000 0.000
2015.000 0.000 0.000 0.000 0.000
2016.000 2.000 0.000 0.000 0.000
2017.000 26.000 0.000 0.000 0.000
2018.000 2658.000 0.000 0.000 0.000
2019.000 13036.000 0.000 0.000 0.000
2020.000 10300.000 0.000 0.000 0.000
2021.000 11266.000 0.000 0.000 0.000
2022.000 14487.000 2.000 0.000 0.000
2023.000 13461.000 5.000 0.000 0.000
2024.000 13378.000 0.000 0.000 0.000
2025.000 2640.000 0.000 0.000 0.000
2026.000 24.000 0.000 0.000 0.000

Contacts by band (≥50 MHz)

band_mhz contacts avg_km max_km
222 7595 229.000 2306.000
432 9177 200.000 1752.000
902 1794 171.000 915.000
1296 2996 160.000 1752.000
2304 749 153.000 655.000
3400 351 151.000 643.000
5760 336 126.000 505.000
10000 54280 211.000 2393.000
24000 3815 96.000 710.000
47000 774 65.000 343.000
75000 117 57.000 289.000
122000 70 18.000 139.000
134000 5 65.000 157.000
142000 4 47.000 79.700
145000 2 40.000 79.600
241000 14 31.000 114.400
288000 1 1.000 1.246
322000 1 1.000 1.400
403000 1 1.000 1.400
411000 1 0.000 0.050

Monthly sounding ducting

month soundings ducting_pct avg_min_grad avg_pwat
1 103 27.200 -179.200 10.400
2 131 29.000 -163.100 7.900
3 93 17.200 -157.200 8.900
4 330 24.200 -155.500 11.300
5 360 48.100 -269.200 23.900
6 396 68.900 -352.900 31.600
7 304 67.100 -292.500 29.600
8 5045 55.200 -255.800 35.100
9 2345 56.300 -280.000 27.300
10 179 55.300 -304.800 18.300
11 194 45.400 -237.300 11.600
12 158 25.900 -182.400 10.800

HRRR native-profile duct distribution (best supportable band)

band_bin profiles avg_inv_top_m avg_theta_e_jump avg_richardson
15-30 GHz 10 2091.000 5.900 8.690
30-75 GHz 4 3860.000 5.000 12.120
5-15 GHz 98 4408.000 25.700 12.550
<5 GHz 1432 2097.000 5.400 18.420
none 9928 11497.000 80.500 38.270

Contact ↔ HRRR per-band Pearson correlations (matched n=81547)

band_mhz n rho_pr rho_dpc rho_pwat rho_sref rho_grad rho_tc rho_hpbl
222.000 7518.000 -0.014 0.077 0.068 0.087 0.040 -0.081 -0.039
432.000 9073.000 0.074 0.134 0.111 0.132 0.008 -0.088 -0.063
902.000 1754.000 0.080 0.097 0.050 0.090 -0.039 -0.070 -0.029
1296.000 2951.000 0.025 0.103 0.053 0.110 -0.077 -0.041 -0.051
2304.000 719.000 0.079 0.165 0.130 0.192 -0.126 -0.059 -0.086
3400.000 335.000 -0.026 0.154 0.150 0.221 0.061 -0.061 -0.024
5760.000 320.000 0.156 0.076 0.099 0.091 0.003 -0.068 -0.057
10000.000 54150.000 -0.086 -0.022 -0.029 0.000 0.030 -0.004 0.007
24000.000 3794.000 -0.221 -0.338 -0.362 -0.241 0.023 -0.211 -0.009
47000.000 757.000 -0.256 -0.215 -0.233 -0.054 -0.021 -0.113 -0.079
75000.000 109.000 -0.768 -0.699 -0.620 -0.582 0.434 -0.680 0.365
122000.000 63.000 -0.041 -0.129 -0.127 -0.248 0.355 0.039 0.400

Per-band HPBL bin distance distribution

One table per band with ≥50 matched contacts. A band-specific effect here means HPBL belongs in the scorer for that band.

222 MHz:

bin n avg_km p50_km
<200 1224 266.100 205.500
200-500 1556 225.600 167.000
500-1000 1754 213.300 167.500
1000-1500 1426 223.700 170.000
1500-2000 1239 224.700 178.000
>=2000 319 233.800 158.000

432 MHz:

bin n avg_km p50_km
<200 1579 224.500 178.000
200-500 1867 205.800 153.000
500-1000 2114 189.900 139.800
1000-1500 1683 196.800 148.000
1500-2000 1475 192.600 145.000
>=2000 355 171.700 124.000

902 MHz:

bin n avg_km p50_km
<200 271 198.300 162.000
200-500 366 164.900 138.000
500-1000 433 166.500 131.600
1000-1500 356 166.800 136.500
1500-2000 282 174.900 152.000
>=2000 46 153.500 126.500

1.296 GHz:

bin n avg_km p50_km
<200 443 174.500 145.000
200-500 612 173.100 133.500
500-1000 735 152.500 116.000
1000-1500 585 158.200 131.000
1500-2000 479 152.600 122.000
>=2000 97 143.800 108.000

2.304 GHz:

bin n avg_km p50_km
<200 101 167.000 151.000
200-500 131 182.200 157.000
500-1000 188 140.800 122.000
1000-1500 159 146.700 135.000
1500-2000 123 148.300 135.000
>=2000 17 137.400 140.000

3.4 GHz:

bin n avg_km p50_km
<200 54 143.100 122.000
200-500 60 178.200 141.000
500-1000 74 145.600 108.000
1000-1500 84 149.400 133.000
1500-2000 48 165.100 138.700
>=2000 15 121.800 128.000

5.76 GHz:

bin n avg_km p50_km
<200 37 148.800 108.000
200-500 54 138.400 135.000
500-1000 85 113.300 108.000
1000-1500 74 130.900 127.500
1500-2000 54 121.200 122.000
>=2000 16 124.200 125.000

10 GHz:

bin n avg_km p50_km
<200 10466 212.500 182.600
200-500 14330 205.900 179.500
500-1000 16463 208.700 190.300
1000-1500 8712 212.400 198.500
1500-2000 2985 201.200 179.000
>=2000 1191 228.700 193.500

24 GHz:

bin n avg_km p50_km
<200 731 100.200 92.200
200-500 1079 91.500 87.700
500-1000 1179 94.800 87.700
1000-1500 534 98.500 95.700
1500-2000 196 99.900 99.400
>=2000 75 74.300 31.800

47 GHz:

bin n avg_km p50_km
<200 172 67.100 63.600
200-500 237 62.600 61.300
500-1000 253 61.900 65.400
1000-1500 58 71.000 70.900
1500-2000 29 33.500 23.700
>=2000 8 33.900 32.300

75 GHz:

bin n avg_km p50_km
<200 19 18.600 19.600
200-500 31 44.300 36.700
500-1000 53 58.800 36.700
1000-1500 6 56.100 29.800

122 GHz:

bin n avg_km p50_km
<200 7 4.400 5.000
200-500 27 8.800 8.000
500-1000 18 13.600 7.000
1000-1500 6 78.500 85.500
1500-2000 3 10.000 12.000
>=2000 2 5.000 5.000

Per-band pressure bin distance distribution

Surface pressure tends to proxy synoptic-scale stagnation, so we want to see longer distances under the 1015-1025 mb ridge at every band that ducts.

222 MHz:

bin n avg_km p50_km
<990 2720 227.200 178.000
990-1000 1926 255.100 201.000
1000-1010 1799 233.800 186.000
1010-1020 953 181.400 131.000
>=1020 120 166.100 132.000

432 MHz:

bin n avg_km p50_km
<990 3536 188.800 141.000
990-1000 2278 226.700 178.000
1000-1010 1832 210.900 156.500
1010-1020 1264 174.100 128.000
>=1020 163 159.000 121.000

902 MHz:

bin n avg_km p50_km
<990 590 154.100 127.000
990-1000 510 203.200 157.500
1000-1010 369 189.200 148.000
1010-1020 249 139.200 143.000
>=1020 36 79.700 51.500

1.296 GHz:

bin n avg_km p50_km
<990 1038 155.400 125.000
990-1000 800 183.100 146.000
1000-1010 620 165.400 117.000
1010-1020 444 132.400 114.000
>=1020 49 119.800 101.000

2.304 GHz:

bin n avg_km p50_km
<990 190 146.500 134.000
990-1000 250 155.000 122.000
1000-1010 144 172.600 134.000
1010-1020 121 147.600 152.000
>=1020 14 127.600 137.000

3.4 GHz:

bin n avg_km p50_km
<990 95 154.400 136.000
990-1000 159 159.200 134.000
1000-1010 45 166.000 140.000
1010-1020 27 111.700 98.000
>=1020 9 114.600 131.000

5.76 GHz:

bin n avg_km p50_km
<990 86 106.000 105.500
990-1000 139 133.200 111.000
1000-1010 51 136.100 104.000
1010-1020 34 143.200 152.000
>=1020 10 140.600 139.000

10 GHz:

bin n avg_km p50_km
<990 27142 221.800 213.500
990-1000 13469 181.200 158.600
1000-1010 7236 204.000 175.200
1010-1020 4658 218.700 175.300
>=1020 1645 229.300 207.600

24 GHz:

bin n avg_km p50_km
<990 1485 100.900 96.500
990-1000 1462 87.200 81.000
1000-1010 463 114.400 113.400
1010-1020 258 70.900 72.100
>=1020 126 102.700 89.600

47 GHz:

bin n avg_km p50_km
<990 279 68.500 70.900
990-1000 297 58.000 57.300
1000-1010 63 69.600 68.000
1010-1020 89 60.600 65.400
>=1020 29 43.400 42.000

75 GHz:

bin n avg_km p50_km
<990 55 65.300 57.300
990-1000 32 17.500 10.400
1000-1010 12 71.800 89.800
1010-1020 8 18.300 19.600
>=1020 2 11.700 11.700

122 GHz:

bin n avg_km p50_km
<990 22 12.000 7.000
990-1000 19 27.300 7.000
1000-1010 10 8.400 6.000
1010-1020 10 13.400 8.000
>=1020 2 12.000 12.000

Contact ↔ NARR per-band Pearson correlations (pre-2014 only, matched n=201)

Historical sanity check: if the HRRR-era signs and magnitudes survive on 30+ years of NARR reanalysis, the scoring factors are physical rather than HRRR-artefact. Diverging signs = flag it.

band_mhz n rho_pr rho_dpc rho_pwat rho_sref rho_grad rho_tc rho_hpbl
10000.000 103.000 -0.402 -0.402 -0.402 -0.234 -0.222 -0.402 -0.402

NEXRAD composite reflectivity vs distance (matched n=20525)

Rain-attenuation sanity check — one table per band with ≥50 matched contacts. At rain-sensitive bands (24+ GHz) higher max_dbz should map to shorter contacts; at 10 GHz and below the effect should be barely detectable.

10 GHz:

bin n avg_km p50_km
none (<5) 13803 207.900 193.500
drizzle (5-20) 1270 201.800 200.400
light (20-30) 1696 209.600 187.900
moderate (30-45) 1594 229.500 213.900
heavy (>=45) 675 191.600 146.300

24 GHz:

bin n avg_km p50_km
none (<5) 868 91.500 83.700
drizzle (5-20) 74 108.300 123.200
light (20-30) 151 88.200 70.900
moderate (30-45) 76 109.300 122.400
heavy (>=45) 49 86.600 102.300

47 GHz:

bin n avg_km p50_km
none (<5) 186 52.400 56.000
light (20-30) 30 59.300 66.300
moderate (30-45) 9 75.100 81.600
heavy (>=45) 15 71.400 82.800

hrrr_native_profiles.best_duct_band_ghz vs distance (matched n=56845)

Validates the 1.15× boost in Scorer.score_refractivity/4: contacts where the native duct supports the target band should run longer than those where it does not. One table per band with ≥50 matched contacts.

10 GHz:

bin n avg_km p50_km
none 44655 211.200 192.400
<5 GHz 7073 200.000 169.300
5-10 GHz 439 199.000 174.200
10-24 GHz 146 204.700 242.700
24-47 GHz 5 176.600 133.300
>=47 GHz 23 147.800 131.500

24 GHz:

bin n avg_km p50_km
none 3183.000 94.800 92.200
<5 GHz 473.000 98.600 84.900
5-10 GHz 36.000 97.500 113.700
10-24 GHz 2.000 44.700 44.700
>=47 GHz 6.000 131.500 131.500

47 GHz:

bin n avg_km p50_km
none 552.000 64.300 65.400
<5 GHz 131.000 56.800 61.800
5-10 GHz 6.000 98.100 113.700

75 GHz:

bin n avg_km p50_km
none 77.000 54.200 36.700
<5 GHz 15.000 13.900 14.600

Pearson(degradation_db, distance_km) = 0.318

bin n avg_km p50_km
negative/0 (no fade) 10 134.500 122.500
3 dB noise floor 2 119.500 119.500