Computational Epidemiology Est. 2011 · 28 countries
← All writing

Correcting the grid, one neighborhood at a time

A statistical model that corrects a 9-kilometer reanalysis grid toward one neighborhood at a time, validated zone by zone, including forecast days now, not only history.

A previous post on this API's cost showed a real Mexico City colonia, 1.1 square kilometers, sitting inside a single 28-kilometer ERA5 grid cell, and the API flagging the estimate as resolution_adequate: false rather than pretending the cell's one value described the colonia. That disclosed the limitation without fixing it. This post is the fix: a statistical model that corrects the grid's air temperature toward each polygon's own neighborhood, validated per climate zone, with the failures disclosed alongside the successes.

The base grid was already there. ERA5-Land runs at roughly 9 kilometers, already finer than the 28-kilometer ERA5 the earlier post described, and every project already used it. What's new is that the API now predicts how far a given neighborhood departs from its grid cell's value and shifts the value accordingly. A park-heavy block and a concrete-heavy block that share one 9-kilometer cell get one identical grid temperature today. The correction is what separates them.

The differentiator here is not the correction alone. Elevation, canopy height, land cover fractions, built-up fraction, land-surface temperature, population density, each of these is individually a real burden to source, process, and harmonize to a common polygon. Most of the hard part of this work was doing that integration, once, so a user isn't handed seven raw rasters and left to build a correction themselves. The model is the applied, validated layer on top of that integration, not a replacement for it. The resolution, stated plainly: the correction targets roughly 100 to 300 meters where the fine covariates exist, degrading toward about 1 kilometer where only coarse covariates do. Not block-level. Not a fixed number anywhere.

What the correction actually is

A quantile regression forest predicts each polygon's daily temperature anomaly relative to its own ERA5-Land grid cell, one delta for the daytime maximum and a second for the nighttime minimum, from covariates the API already stores for every polygon: warm-season land-surface temperature anomaly, tree canopy height, impervious and tree fractions from WorldCover, built-up fraction from GHSL, elevation relative to the grid cell, population density, humidity, wind, latitude, day of year, and Köppen climate zone.

The model corrects temperature only. Heat index, UTCI, and WBGT are re-derived from the corrected temperature through the same physics functions the base pipeline already uses for the raw grid value. The composite indices are never modeled directly.

Real data always wins: a four-step order of precedence

A value can come from one of four places, in a strict order: the raw grid estimate, last resort; the model's corrected estimate; that same correction refined against nearby real weather stations; or, where a station sits inside the polygon itself, that station's own observed reading, which overrides the model outright. A later value in this order can replace an earlier one and never the reverse, so a real observation is never quietly downgraded back to a modeled estimate. Every polygon-day carries a data_source stamp naming which of the four produced it, so a corrected value is never presented as if it were a measurement.

The real tier is worldwide METAR, airport hourly weather reports, free, no key required. Where a reporting airport falls inside a polygon, its observed daily max and min override the model for that polygon-day. Strict point-in-polygon containment means a station just outside a polygon's boundary leaves that polygon on the modeled tier; that's a disclosed estimate, deliberately not an interpolation across the boundary.

The third tier is the one that didn't exist when the correction first shipped: a distance-weighted blend of the model's own delta against real nearby stations, closer stations carrying more weight, saturating toward the station term as more of them contribute. It sits between the model correction and a full station override, real ground data pulling the estimate closer without requiring a station to sit exactly inside the polygon. Boston and Cambridge is the project where this shows up today, 24,231 recorded polygon-days in all: 934 carry a blended correction, 22,319 more are model-corrected outright, 972 remain on the raw grid, and a real station override inside a polygon accounts for the rest. One real row, Census Tract 1001 in Suffolk County, on July 21, 2026:

{
  "data_source": "era5_land_station_blended",
  "base_source": "era5_land",
  "applied": true,
  "model_version": "ds-2026.07-rf4",
  "tmax": {
    "delta_c": -0.63,
    "ci95_c": 3.38
  },
  "tmin": {
    "delta_c": null,
    "ci95_c": null
  },
  "blend_n_stations": 8,
  "blend_nearest_km": 10.1,
  "blend_station_weight": 0.953,
  "blend_station_ids": [
    "K1B9",
    "KBED",
    "KBOS",
    "KBVY",
    "KGHG",
    "KLWM",
    "KOWD",
    "KTAN"
  ]
}

Eight real stations, the nearest ten kilometers out, weighted at 95 percent toward the station term for this particular delta. The tmin half of that same row is null, not zero, because Boston-Cambridge sits in a Köppen zone mix, mostly Cfa with some Dfa and Dfb, and the nighttime-minimum gate does not pass for all of it. A failing target returns a null delta and falls back to the grid value for that target specifically, never a guessed correction.

122 grid · 467 corrected · 2 station
Tier 1 era5_land_grid · raw grid value (122) Tier 2 era5_land_downscaled · model correction (467) Tier 2.5 era5_land_station_blended · station blend (0) Tier 3 metar_station · in-polygon station (2)
The four-tier precedence order as real geography: all 591 Boston-Cambridge census tracts, each colored by the data_source actually stored for that tract-day. No single day holds all four tiers at once, and that is the ladder working: when the station blend (Tier 2.5) cleared its gate, it replaced the model tier (Tier 2) on the identical 467 tracts, because a higher tier may overwrite a lower one and never the reverse. The 122 raw-grid tracts and the two station-override tracts — the ones with Logan and Hanscom inside their boundaries — are unchanged across both days.

Where the correction earns its keep, and where it stops on purpose

The honesty mechanism here is a leave-region-out cross-validation, held out by whole regions rather than random rows, scored per Köppen climate zone. On the historical ERA5 band, daytime-maximum correction passes in all 19 zones tested. Nighttime-minimum passes in 15 of 19 and fails in four: Am, As, and Cwa, tropical monsoon and humid subtropical zones, and BWh, hot desert. Where a target fails for a zone, the pipeline does not ship a guessed correction. It falls back to the raw grid value for that target and records that it did.

Phoenix is a real, in-project example of exactly this. Seven of its seventeen counties, La Paz, Yuma, Maricopa, Clark, Pinal, Imperial, and Graham, sit in BWh. Daytime highs in those counties are corrected like everywhere else in the project. Nighttime lows are not; BWh fails the nighttime gate, so those counties' overnight minimum serves the raw grid value, by design, not by omission.

Köppen zone Daytime max Nighttime min
Am Tropical monsoon
As Tropical savanna, dry summer
Aw Tropical savanna, dry winter
BSh Hot semi-arid
BSk Cold semi-arid
BWh Hot desert
BWk Cold desert
Cfa Humid subtropical
Cfb Oceanic
Cfc Subpolar oceanic
Csa Hot-summer Mediterranean
Csb Warm-summer Mediterranean
Cwa Humid subtropical, dry winter
Cwb Subtropical highland, dry winter
Dfa Hot-summer humid continental
Dfb Warm-summer humid continental
Dfc Subarctic
Dsb Warm-summer continental, dry summer
Dwa Hot-summer continental, dry winter
Beats the raw grid (held-out cross-validation) Gate not passed — serves the raw grid value

19 of 19 zones pass on daytime max; 15 of 19 pass on nighttime min. The four nighttime failures — Am, As, BWh, Cwa — are tropical-monsoon, humid-subtropical-dry-winter, and hot-desert zones, where those polygons' overnight minimum serves the raw grid, disclosed as such, while daytime max in the same zones is corrected. Historical (ERA5-Land) band, model ds-2026.07-rf4.

What changed this month is which parts of the calendar this validation covers. Through most of this build, a genuine correction could only ever come from the ERA5 band, which runs roughly six days behind real time. That meant the days people actually check, today and the coming week, were permanently uncorrected by architecture, not by an oversight anyone had gotten around to fixing. I judged that the wrong priority: people check current and forecast risk far more than they check last week's. So the near-term band, the one to five days before the ERA5 archive catches up, and the seven-day forecast horizon each now carry their own independently validated gate, per Köppen zone, per target, per lead day. Near-term validates 10 of the zones tested on daytime max and 5 on nighttime min, every one of those passes carried by genuine per-polygon spatial signal, not a flat adjustment. On tomorrow's forecast, 11 zones pass on daytime max and 9 on nighttime min; by seven days out, daytime max narrows to 5 passing zones and nighttime min holds at 8.

That narrowing has two distinct sources, and the model page discloses them separately. At one day out, 7 of the 11 passing daytime-max zones beat the grid through genuine per-polygon spatial signal, the model actually reading the covariates. By seven days out, only one zone, Am, still does; the other four passes that remain rest on a flat per-Köppen-zone bias adjustment, a validated correction of a different kind. One answers "does this neighborhood run differently from its grid cell"; the other answers "does this zone run differently from what the raw forecast assumes." Both are real, and conflating them would hide which question each zone's correction is actually answering.

What the correction cannot see

Land-surface temperature is skin temperature, not air temperature, and it enters the model as a seasonal structural feature, never a day-to-day predictor. It tells the model which parts of a grid cell run persistently hotter across a season. It says nothing about any single day's weather.

Humidity, wind, and solar radiation are not downscaled. Only air temperature is. A corrected WBGT or UTCI improves through its temperature term while still inheriting grid-scale wind and solar values, worth saying explicitly since a reader could otherwise assume every input moved together.

The uncertainty interval is a split-conformal calibration, per Köppen zone, on held-out stations. Conformal calibration assumes exchangeability, an assumption spatial autocorrelation strains; calibrating per zone narrows that problem but does not close it, a documented, still-open limitation.

The closest real-world precedent, comparing random-forest and kriging approaches for sparse-station air temperature in a tropical setting, found tree ensembles competitive but not uniformly better. I'd rather cite that plainly than claim a clean win this build hasn't earned.

The synthesis that's actually new

The age-structure data here isn't new. Every project already carries WorldPop per-polygon fractions, residents under 5 and residents 65 and older, the two age groups that carry the sharpest heat-mortality risk. What's new as of this rollout is that the exposure side of that pairing now sits at the same resolution as the vulnerability side. An elderly-dense census tract and its own corrected neighborhood temperature can be read together, instead of a per-polygon vulnerability profile sitting on top of one temperature shared across an entire district.

Keep the claim bounded to what it actually is: a data-availability change that makes a cross-reference possible for the first time, not a validated health finding. Nothing here demonstrates a mortality or morbidity outcome.

Age-vulnerable fraction (under-5 + 65+) →Daytime max, °C →
One census tract, 2026-07-21 Trend line: r = -0.29, 587 tracts

Every Boston-Cambridge census tract with both a WorldPop age-structure row and a 2026-07-21 daytime-max value (587 of 591 tracts) — every one of them carries a model-corrected or station-blended value that day, not the raw grid. This is a cross-reference between two independently sourced layers now sitting at the same resolution — not a claim that either causes the other.

How this works

The model is a quantile regression forest predicting a temperature anomaly, trained with leave-region-out cross-validation (folds held out by whole country or admin region, never a random split, since random splits leak through spatially correlated neighboring station-days), split-conformal intervals calibrated per Köppen zone, and an area-of-applicability dissimilarity index flagging polygons whose covariates sit outside the training distribution rather than silently extrapolating past it. The current version is ds-2026.07-rf4, stamped on every corrected row it produces.

Whether a polygon can ever be corrected at all is a separate, static fact, reported per polygon as a downscaling entry under polygon_coverage: does this polygon's static covariate context exist, complete enough for the model to run. That's a structural question, answered once and rarely changing. Whether a specific polygon-day actually got corrected is the dynamic question this whole post has been answering zone by zone, band by band.

The full per-zone results, every band's gate including the ones I've only summarized here, and a global map of where real weather stations exist to support a station-tier correction, are on the model performance page, the place this post's numbers were drawn from directly.

Where the rollout actually stands today

Nine active projects are public today, and across all of them, 66,219 polygon-days have ever been recorded, 86.5 percent of them served above the raw grid tier. Delhi is fully corrected, every one of its 6,244 recorded polygon-days carrying a model correction, none still on the raw grid. Manhattan and Brooklyn, the largest of the nine at 1,114 census tracts, sits at 99.1 percent above grid. Mexico City's 1,182 colonias run lower, 64.0 percent, the trade-off of being the earliest and largest of the group, with more of its history predating this month's forecast and near-term extension. Boston-Cambridge, described above, is the only one with a live station-blend so far, for the structural reason that a blend needs real stations near enough to contribute, and most of these projects are drawn at a scale, neighborhoods and census tracts, where that's rare; Phoenix's county-scale polygons are the outlier, large enough that a station sitting inside one is common rather than rare, which is also why Phoenix carries the most direct station-override rows, 30 of the fleet's 49.

Raw grid (Tier 1)Model-corrected (Tier 2)Station-blended (Tier 2.5)Real station (Tier 3)

All-time polygon-days per tier, 2026-07-23, across the 9 public projects. 66,219 polygon-days recorded fleet-wide, 86.5% of them served above the raw grid tier. Boston-Cambridge is the only project with a live station blend today; Phoenix's county-scale polygons carry 30 of the fleet's 49 direct station-override rows.

The remaining share on each project reflects ordinary publication latency: Copernicus takes roughly six days to publish a complete ERA5 day, a polygon's static covariate context has to be complete before any correction can run at all, and a project's own onboarding date determines how much of its history predates this month's near-term and forecast extension. Every one of those closes on its own as each project's daily update runs.

no correction: serves the raw grid value station override: observed, no model delta −2.7°C0+2.7°C correction applied to the day's max, relative to the raw grid
Before and after, on the day's maximum: each corrected tract is colored by how far its stored daily-max temperature sits from the raw grid value it replaced (downscale_delta_tmax_c). July 19 is the model correction from covariates alone, +0.2 to +2.6°C above the grid; July 20 is the station-blended correction, 0 to −1.7°C below it — a different day's weather, and a different tier doing the correcting. Hatched tracts serve the raw grid unchanged; the two station-override tracts report the airport observation itself.
One ERA5-Land grid cell (~9 km), one raw value
26.4°C
2026-07-21 raw grid daytime max, shared by both tracts below

Impervious-heavy block

Census Tract 1201.04 — Suffolk

Tree cover
42%
Built / impervious
55%
Mean canopy height
10.7 m
-0.66°C model delta → corrected 25.7°C
era5_land_station_blended

Canopy-heavy block

Census Tract 1201.05 — Suffolk

Tree cover
78%
Built / impervious
18%
Mean canopy height
14.2 m
-0.86°C model delta → corrected 25.5°C
era5_land_station_blended

Both tracts split from the same parent Census Tract 1201 (Suffolk County, MA) — adjoining by construction, both centroid-sampled to the same ~9km ERA5-Land grid cell. Same raw grid value in, genuinely different corrections out — -0.66°C for the impervious-heavy tract against -0.86°C for the canopy-heavy one, model ds-2026.07-rf4. Both tracts carry the era5_land_station_blended tag, so each delta is the covariate-driven model correction plus this tract's own station-blend adjustment, not covariates in isolation.

Why this is the interesting part

The interesting work from here is wherever a coarse grid was previously the only option and now isn't: a block that used to inherit its whole city's temperature and now gets its own; a forecast day that used to be an uncorrected guess and now carries the same validation discipline as history. Some of that work will pass its gate cleanly. Some of it, like Phoenix's desert counties overnight, correctly won't, and disclosing that is as much the point as the correction itself.

If you're using this API for a project and want to know exactly what's validated where yours sits, or you're a researcher with a use case this could serve, email the CrisisReady team directly. This work is built through CrisisReady at the Harvard Data Science Initiative and the Harvard Salata Institute for Climate and Sustainability.