ERA5 → EOPF HEALPix Converter#

Converts ERA5 reanalysis surface fields (Gaussian N256/N320) to EOPF-compliant HEALPix zarr (level 7, ~50 km).

Pipeline: download GRIB via CDS (2 MARS requests) → PSFResampler → write zarr → inject STAC → push S3

import logging
from pathlib import Path

from healpix_convert.converters.era5 import ERA5Converter

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")

Configuration#

DATE = "2025-01-01"
TIME = "00:00:00"
LOCAL_DIR = Path(".")
OUTPUT = LOCAL_DIR / f"S00__ADF_ECMWA_{DATE.replace('-', '')}.zarr"
PUSH_S3 = False  # set True to push to S3

converter = ERA5Converter(
    date=DATE,
    time=TIME,
    local_dir=LOCAL_DIR,
)

Step 1 — Prepare (download + PSFResampler)#

result = converter.prepare(output_path=str(OUTPUT))
print(f"Chunks: {result.n_chunks} | Timesteps: {result.n_times}")

Step 2 — Convert (all spatial chunks)#

for i in range(result.n_chunks):
    converter.convert_group(i)
    if (i + 1) % 20 == 0:
        print(f"  {i+1}/{result.n_chunks}")

Step 3 — Consolidate (STAC metadata)#

converter.consolidate()
print(f"Done: {OUTPUT}")

Validation#

import healpy as hp
import matplotlib.pyplot as plt
import xarray as xr

ds = xr.open_zarr(str(OUTPUT), consolidated=True)
print(ds)

var = "t2m"
data = ds[var].isel(time=0).values
hp.mollview(
    hp.reorder(data - 273.15, n2r=True),
    flip="geo",
    nest=False,
    cmap="RdBu_r",
    min=-50,
    max=50,
    unit="°C",
    title=f"ERA5 {var} — HEALPix level 7",
)
plt.show()