{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# CAMS EAC4 → EOPF HEALPix Converter\n", "\n", "Converts CAMS EAC4 aerosol reanalysis (regular 0.75°) to EOPF-compliant HEALPix zarr (level 6, ~100 km).\n", "\n", "**Pipeline**: download NetCDF via ADS REST API → resample to HEALPix → write zarr → inject STAC\n", "\n", "**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." ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [], "source": [ "import logging\n", "from pathlib import Path\n", "\n", "from healpix_convert.converters.cams import CAMSConverter\n", "\n", "logging.basicConfig(level=logging.INFO, format=\"%(asctime)s %(levelname)s %(message)s\")" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "## Configuration" ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": {}, "outputs": [], "source": [ "DATE = \"2025-01-01\"\n", "TIME = \"00:00\"\n", "LOCAL_DIR = Path(\".\")\n", "OUTPUT = LOCAL_DIR / f\"S00__ADF_CAMSA_{DATE.replace('-','')}.zarr\"\n", "\n", "converter = CAMSConverter(\n", " date=DATE,\n", " time=TIME,\n", " local_dir=LOCAL_DIR,\n", " method=\"psf\", # default; use \"nn\" for nearest-neighbour binning\n", ")" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "## Step 1 — Prepare (download)" ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "result = converter.prepare(output_path=str(OUTPUT))\n", "print(f\"Chunks: {result.n_chunks} | Timesteps: {result.n_times}\")" ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "## Step 2 — Convert (all spatial chunks)" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "for i in range(result.n_chunks):\n", " converter.convert_group(i)\n", " if (i + 1) % 20 == 0:\n", " print(f\" {i+1}/{result.n_chunks}\")" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "## Step 3 — Consolidate" ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "converter.consolidate()\n", "print(f\"Done: {OUTPUT}\")" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "## Validation" ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [], "source": [ "import healpy as hp\n", "import matplotlib.pyplot as plt\n", "import xarray as xr\n", "\n", "ds = xr.open_zarr(str(OUTPUT), consolidated=True)\n", "print(ds)\n", "\n", "data = ds[\"aod550\"].isel(time=0).values\n", "hp.mollview(\n", " hp.reorder(data, n2r=True),\n", " flip=\"geo\",\n", " nest=False,\n", " cmap=\"viridis\",\n", " min=0,\n", " max=1.5,\n", " unit=\"AOD\",\n", " title=\"CAMS AOD550 — HEALPix level 6\",\n", ")\n", "plt.show()" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 5 }