Eleven Winters
Data and methods

How every number is made

Everything here is public data and open code. One command rebuilds every table, figure, this website and the paper.

Sources

Four public datasets

SourceWhat we useCoverage
CPCB continuous monitors, via the OpenAQ archiveHourly PM2.5, PM10, NO₂, SO₂, CO at 100 sites in 39 citiesFeb 2016 to Sep 2026, with an archive gap from late 2022 to early 2025
US Embassy and consulate monitors, via OpenAQHourly PM2.5 from reference instruments in New Delhi, Mumbai, Kolkata, Hyderabad and Chennai2016 to 2026, nearly continuous
NASA FIRMS active firesVIIRS S-NPP and MODIS detections, with overpass time and fire radiative power2016 to 2025
ERA5 reanalysis, via Open-MeteoHourly temperature, humidity, wind, rain, pressure, cloud, sunlight and boundary-layer height for each city2016 to Sep 2026

State boundaries for assigning fires to Punjab and Haryana: geoBoundaries (CC BY 2.5 IN).

The open archive has a two-year hole in India's official network

Heat map of data availability by city and month. CPCB network data are missing from late 2022 to early 2025 in the open archive.

Share of hours with a valid PM2.5 reading, by city and month. CPCB-network data are missing from the OpenAQ archive from late 2022 to early 2025; the US mission monitors run almost without a break.Source: CPCB and US Department of State monitors via the OpenAQ archive.
Cleaning

Quality control

Readings from duplicate archive entries of the same physical monitor are merged into one site. Timestamps in the archive mark the end of each hour; we label hours by their start. Of 2,841,635 site-hours of PM2.5, 4.6% were removed:

  • Invalid: zero, negative, or at the instrument ceiling (74,646 hours).
  • Stuck sensor: the same value six or more hours running (18,291).
  • Stall before failure: a high reading repeated just before the record goes blank, which is how the monitors tend to fail on Diwali nights (1,305).
  • Isolated spike: one hour far above both neighbours (477). Multi-hour events such as Diwali are kept.
  • Impossible ratio: PM2.5 above PM10 in the same hour (34,823).

Flag counts per site are in results/qc_report.csv.

Weather

Taking the weather out

For each site we fit a gradient-boosted tree model (LightGBM) of log PM2.5 on weather and calendar terms. To normalise, we predict each day 200 times with the weather columns replaced by draws from the site's whole record, keeping the date fixed (Grange et al., 2018). The average is the PM2.5 expected under typical weather.

Model skill, from five-fold cross-validation with whole calendar years held out: median R² of 0.52 on log PM2.5 across 103 sites (interquartile range 0.28 to 0.68).

The Diwali baseline

For events we use an hourly model that also knows about farm fires, through a wind-aware fire index: VIIRS detections in Punjab and Haryana weighted by how directly upwind of Delhi they are and by distance (300 km e-folding), with lags of up to three days. Diwali windows (three days either side) are never used for training, and every hour is predicted by a model that did not see that week. Diwali-night excess is observed minus baseline, averaged from 6 pm to 3 am. Ordinary nights between October and mid-December are scored the same way to show what normal variation looks like.

Fire coupling

For each season we regress Delhi's daily weather-adjusted log PM2.5 (US Embassy) on the fire index, averaged over the lags with the strongest response, using heteroscedasticity- and autocorrelation-consistent standard errors.

Reproduce

Run it yourself

git clone https://github.com/krishnav1412/eleven-winters
cd eleven-winters
python -m venv .venv && .venv/Scripts/activate
pip install -e ".[dev]"
cp .env.example .env        # add a free OpenAQ key
ew download                 # stations, archive, fires, weather
ew all                      # cleaning, models, figures, site

Raw data go to the folder named in EW_DATA_DIR, outside the repository. Tests: pytest.

Cite

Citation

Agarwal, K. (2026). Eleven Winters: separating weather, farm fires and fireworks
in India's PM2.5, 2016–2026. https://github.com/krishnav1412/eleven-winters