← Reproduction studies

Can a published climate normal be recomputed from the data it derives from?

Recomputing NOAA's 1991–2020 U.S. Climate Normals from the GHCN-Daily observations they are built on, across 12 stations, as a Facetwork FFL workflow. September 2026.

1. Purpose of the analysis

A climate normal is the reference against which "hotter than average" is measured — in agriculture, energy demand forecasting, insurance pricing and building codes. NOAA publishes the normals and the daily observations they derive from, so unlike most published results this one can be checked rather than trusted.

The question is not "are the published normals correct". It is narrower and more useful: can an independent party, starting from the same archived observations, arrive at the same numbers? Where the answer is no, the gap measures how much of the published product depends on decisions that are documented in prose but not reproducible from the archive.

2. What the original work does

NOAA NCEI's U.S. Climate Normals are not an average of the daily archive. Their published Normals Calculation Methodology (2020) describes a substantially longer pipeline, and the two steps that matter here are both corrections applied before any averaging:

StepWhat it doesNCEI's own words
Time-of-observation adjustment Corrects for when the observer read the thermometer. A station read at 5 pm double-counts hot afternoons in TMAX; one read at 7 am double-counts cold mornings in TMIN. "a time of observation (TOB) adjustment that strives to make it as if the observations at a particular station had been taken at local midnight"
Homogenisation Detects and corrects breaks from station moves, instrument changes and other shifts in practice, by pairwise comparison with neighbours (Menne & Williams 2009). "GHCN-Daily … is not homogenized like the monthly temperature dataset … The standardization procedures account for both documented and undocumented station moves and other changes in observing practices."
Gap filling Regression against nearby stations, for monthly temperature and precipitation, where suitable neighbours exist. flagged R in the output
Rounding Banker's rounding, computed in metric units at machine precision and rounded only at output. one decimal place in °F

NCEI even give a worked example of the homogenisation adjustment, at exactly the magnitude this study measures:

"if the 31 daily minimum temperature values from January 2000 average to 45.5 F, but the monthly homogenized mean minimum temperature value for January 2000 is 44.5 F, the 31 daily minimum temperature values are each reduced by 1.0 °F"

What we do differently — deliberately

NOAA NCEIThis workflow
InputGHCN-Daily plus the homogenised monthly seriesGHCN-Daily alone
TOB adjustmentapplied, per stationnone
Homogenisationapplied, per stationnone
Gap fillingwhere neighbours allownone
Averagingover the corrected seriesarithmetic mean of raw dailies

So the difference we measure is not an error on either side — it is the size of NOAA's corrections. That reframes the whole study: it is not "can the normals be reproduced?" but "how much of the published normal comes from the raw record, and how much from the adjustments applied to it?" Those adjustments are station-specific by construction, which is precisely what the twelve-station spread shows.

Two things we assumed and the documentation corrects. The comp_flag value S does not mean 30 complete years — under the 2020 WMO guidelines it means at least 24 years (80%). And TAVG is not defined as (TMAX+TMIN)/2: NCEI note the average temperature normal "may not be identical, but within rounding error, of the sum of the corresponding maximum and minimum temperature normals". Our TAVG column uses the conventional midpoint, so a small part of its residual is definitional. Full field layout: the by-station readme.

3. What our FFL workflow found

Each station is fetched, recomputed (mean of daily values per calendar month, tenths °C → °F), and compared against the published normals. 12 stations, 61 tasks, distributed across a four-host fleet. 432 values in total (12 months × TMAX/TMIN/TAVG × 12 stations).

Reproduction quality is a spectrum, not a pass/fail. An earlier version of this page reported "four stations do not reproduce at all". That was an artifact of the threshold, not a property of the data — see §6. Sorted by how closely each station reproduces:
Stationmedian error °Fmax error °F TMAX biasTMIN bias
Los Angeles CA0.0400.300nonenone
Charlotte NC0.0900.200-0.146none
Cincinnati OH0.1150.290-0.233+0.110
Miami FL0.1250.340+0.232none
Minneapolis MN0.2050.540none-0.410
New York NY0.2350.540+0.242-0.511
Atlanta GA0.2700.460-0.395none
Denver CO0.3350.770none-0.237
Houston TX0.3400.520-0.278-0.385
Las Vegas NV0.3401.020+0.161-0.859
Seattle WA0.6850.960-0.899-0.472
Chicago IL0.8751.540-0.291-1.452

"Bias" is the mean signed residual (ours − NOAA) where an exact sign test finds the residuals systematically one-sided (p < 0.01 over 12 months); none means consistent with noise. The sign test is threshold-independent, so unlike the error magnitudes it does not move when the tolerance changes.

Los Angeles reproduces to 0.040 °F median; Chicago is off by 0.875. That is a twentyfold spread across stations processed from the same archive by the same code. Overall:

All 432 values
median absolute error0.230 °F
90th percentile0.820 °F
maximum1.540 °F (Chicago TMIN, January)
within 0.25 °F53.2%
within 0.50 °F81.7%
within 1.00 °F97.0%
The single-station result was misleading, and the fan-out is what showed it. New York alone gives TMAX high in all 12 months (+0.242) and TMIN low in all 12 (−0.511) — a clean, consistent offset. The explanation that suggests itself is a unit round-trip: US first-order stations record whole degrees F, GHCN-Daily archives tenths of a degree C, and the conversion does not commute.

Twelve stations refute that, and NOAA's own documentation supplies the right answer. TMAX bias runs −0.899 (Seattle) to +0.242 (New York) — it flips sign, which an archive-wide rounding artifact cannot do. What does vary by station, by construction, is the time-of-observation adjustment and the homogenisation correction described in §2: TOB depends on the hour each station's observer reads the thermometer, and homogenisation depends on that station's particular history of moves and instrument changes. A station whose observer read in the afternoon needs a different correction, in a different direction, from one who read at dawn.

So the residuals are not noise and not an artifact — they are a measurement of NOAA's per-station corrections, recovered by subtracting the raw archive from the published product. Los Angeles reproduces to 0.04 °F because its corrections are near zero; Chicago is off by 0.875 because its are not.

With n = 1 the wrong explanation was not merely possible, it was compelling.

4. How our workflow compares to the published work

NOAAThis workflow
QuestionWhat is the climate normal?Can it be recomputed from the archive?
InputFull station history + homogenisationThe published daily archive alone
MethodDocumented estimation, QC, infillingArithmetic mean per calendar month
OutputA reference productA measured gap, per station

The algorithmic point: a tolerance cannot see a bias

At New York every one of 36 values sits within a generous tolerance and every one falls on the same side per column — TMAX high 12/12, TMIN low 12/12.

verdict : agree at level `values`,  differing: 0
TMAX residuals SYSTEMATIC: 12+/0- of 12, mean +0.2425  (p=0.00049)
TMIN residuals SYSTEMATIC: 0+/12- of 12, mean -0.5108  (p=0.00049)

Agrees and differs at once. "36 small random errors" and "36 errors in the same direction" are completely different claims about a reproduction, and only the second says the method differs. A tolerance is a per-value predicate; it cannot express that. So the comparison runs an exact sign test over the signed residuals — Binomial(n, ½) under the null, no distributional assumption — and reports the structure beside the verdict. Being threshold-free, it is the part of this study that does not move when the tolerance does.

The test is per column, never pooled. The first implementation pooled, and TMAX running high cancelled TMIN running low into a balanced sign split reporting "no bias" — while both columns were systematically wrong in opposite directions. The check destroyed the signal it existed to find.

What the verdict levels mean

The comparison returns the highest rung reached on a ladder, so the level names what did match and thereby locates the first thing that did not:

levelmeansthe failure is
existsreadable, fields disagreewrong file, schema change
schemafields agree, record sets do notrecords added, dropped, or out of scope
cardinalitycounts agree, which records do notsame number, different members
keysthe same records exist; their values differthe numbers — a method difference
valuesvalues agree under declared normalisationsonly serialisation differs
bytesidentical filesnothing

keys is the informative rung and the easiest to misread. It says both sides looked at exactly the same population and computed different answers — nothing lost in transfer, no filter diverged, no schema drifted. That is a finding about method. A verdict of cardinality or lower usually means something broke before the science started.

The key columns define what "the same record" means, which is a substantive claim rather than configuration. Here the key is (month): twelve records, all twelve present on both sides, so every disagreement is necessarily at keys — the months are the same, the temperatures are not. In the companion GIAB study the key is (CHROM, POS, REF, ALT); without it records would match by position in the file, and one inserted row would misalign everything after it.

5. Reproducing this

fw ffl run --primary examples/repro-normals/noaa_normals_repro.ffl \
           --library facetwork/ffl/file.ffl \
           --workflow repro.normals.ReproduceManyStations

The recomputation is an FFL script block bound to fw.file.FileOps — no handler and no domain package. The ~18 MB daily file is read inside the script rather than passed through a step payload, which would exceed the 16 MB document limit. foreach … limit 4 bounds how many stations are in flight so the run does not pull twelve large files from NOAA at once.

6. Limitations, and a correction

This page previously reported "four stations do not reproduce at all". That was wrong — an artifact of comparing with a relative tolerance. Fahrenheit is an interval scale: its zero is arbitrary, so "within 2% of the value" has no physical meaning. Chicago's recomputed TAVG is off by a near-constant −0.9 °F all year, and 2% of the reading is 0.50 °F in January but 1.55 °F in July:

January  NOAA 25.2  2% = 0.50  → FAIL
July     NOAA 77.5  2% = 1.55  → pass

Same error, opposite verdict, purely seasonal. The comparison gained an abs_tolerance for interval scales and the study was re-run. The station-level bias findings are unchanged — they come from the sign test, which has no threshold — but the pass/fail split is gone, replaced by the error distribution above, which was always the more honest presentation.
Generated by Facetwork workflow repro.normals.ReproduceManyStations · view FFL · source repo