Grids
Free GRIB2 files for the cases we have re-run. NOAA’s file names, no key, no sign-up.
What these files are. FrankenNAM output, not NOAA’s, in NOAA’s file names. See Validation for how close they are to the archived NAM.
Cases
Notable events are re-run and added here; there is no daily feed. Each index lists every file’s size and SHA-256. The archived NAM for the same cycles is in s3://noaa-nam-pds under the same file names, so you can compare the two.
| Cycle | Event | Files | Total size |
|---|---|---|---|
| 2026-11-01 00Z | Autumn, CONUS-wide | Index | 1.7 GB |
| 2026-01-23 12Z | CAD ice storm, Georgia and the Carolinas | Index | 1.6 GB |
| 2025-01-05 12Z | Snowcrete, Washington DC, snow to sleet | Index | 1.6 GB |
| 2025-01-21 00Z | Gulf Coast snow | Index | 1.6 GB |
| 2024-11-19 12Z | Pacific Northwest bomb cyclone and atmospheric river | Index | 1.7 GB |
Paths and names
grids/nam.YYYYMMDD/nam.tCCz.awphysFF.tm00.grib2 grids/nam.YYYYMMDD/nam.tCCz.awphysFF.tm00.grib2.idx
Grid 218 awphys, f00 to f84 every 3 h: one GRIB2 and one .idx per hour, 454 records at most (446 at f00), as in the operational file. The names match NOAA’s so that existing scripts need only a new base URL. Byte-range reads from the .idx work as they do on NOMADS. Files can be cached for a day.
Swapping it into your tools
Only the base URL changes. The base is https://nam.theconvergencezone.com/grids.
curl: one file, or one field by byte range
BASE=https://nam.theconvergencezone.com/grids/nam.20261101
F=nam.t00z.awphys24.tm00.grib2
# the whole file and its inventory
curl -s -O "$BASE/$F" -O "$BASE/$F.idx"
# only the 2 m temperature message: offsets come from the .idx
R=$(curl -s "$BASE/$F.idx" | awk -F: -v pat=':TMP:2 m above ground:' \
'$0 ~ pat {s=$2; if ((getline) > 0) print s "-" ($2-1); else print s "-"; exit}')
curl -s -r "$R" "$BASE/$F" -o t2m.grib2
wgrib2
wgrib2 "$F" -match ':(TMP|DPT):2 m above ground:' -csv t2m_td2m.csv wgrib2 "$F" -s | head
Python
import urllib.request, eccodes as ec
base = "https://nam.theconvergencezone.com/grids/nam.20261101/nam.t00z.awphys24.tm00.grib2"
rows = [l.split(":") for l in urllib.request.urlopen(base + ".idx").read().decode().splitlines()]
i = next(k for k, r in enumerate(rows) if r[3] == "TMP" and r[4] == "2 m above ground")
end = int(rows[i + 1][1]) - 1
req = urllib.request.Request(base, headers={"Range": f"bytes={rows[i][1]}-{end}"})
g = ec.codes_new_from_message(urllib.request.urlopen(req).read())
Herbie
Herbie’s NAM template with the base swapped (tested with herbie-data 2026.10.0):
import herbie.models
from herbie import Herbie
class frankennam:
def template(self):
herbie.models.nam.template(self) # NAM products and file names
self.DESCRIPTION = "FrankenNAM 12 km NAM recast"
self.SOURCES = {"frankennam": "https://nam.theconvergencezone.com/grids/"
f"nam.{self.date:%Y%m%d}/nam.t{self.date:%H}z.{self.product}{self.fxx:02d}.tm00.grib2"}
herbie.models.frankennam = frankennam
H = Herbie("2026-11-01 00:00", model="frankennam", product="awphys", fxx=24)
ds = H.xarray(":TMP:2 m above ground")
? how the .idx works
n:offset:d=YYYYMMDDHH:VAR:level:step:. A message runs from its offset to the byte before the next line’s offset.More
- Validation: how close these files are to the archived NAM.
- Costs: what a run costs, and how to make your own.
- Terms: short, for free data.
