CAMS EAC4 → EOPF HEALPix Converter#

Converts CAMS EAC4 aerosol reanalysis (regular 0.75°) to EOPF-compliant HEALPix zarr (level 6, ~100 km).

Pipeline: download NetCDF via ADS REST API → resample to HEALPix → write zarr → inject STAC

Resampling (method=, default "psf"): PSFResampler tuned for the regular grid (threshold=0.01 → 0 NaN, lam=5.0 → no Gibbs ringing / 0 negative AOD), with a final clip(0, None). Pass method="nn" for the nearest-neighbour binning alternative (exact, faster). Both give 0 NaN / 0 negative and correlate > 0.98.

import logging
from pathlib import Path

from healpix_convert.converters.cams import CAMSConverter

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

Configuration#

DATE = "2025-01-01"
TIME = "00:00"
LOCAL_DIR = Path(".")
OUTPUT = LOCAL_DIR / f"S00__ADF_CAMSA_{DATE.replace('-','')}.zarr"

converter = CAMSConverter(
    date=DATE,
    time=TIME,
    local_dir=LOCAL_DIR,
    method="psf",  # default; use "nn" for nearest-neighbour binning
)

Step 1 — Prepare (download)#

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#

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)

data = ds["aod550"].isel(time=0).values
hp.mollview(
    hp.reorder(data, n2r=True),
    flip="geo",
    nest=False,
    cmap="viridis",
    min=0,
    max=1.5,
    unit="AOD",
    title="CAMS AOD550 — HEALPix level 6",
)
plt.show()