Source code for TeamOverbyeWeather.sources.hrrr

"""HRRR forecast and history client — thin wrapper over :meth:`WeatherClient.download`."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from .era5 import _spatial

if TYPE_CHECKING:
    from ..client import WeatherClient


[docs] class HRRRClient: """Access HRRR historical and forecast datasets via :attr:`WeatherClient.hrrr`. HRRR history comes in four flavours; pass *type* to pick one: ================== ============== ================================== type date keys contents ================== ============== ================================== ``current`` ``YYYY-MM-DD`` this year, 15-minute steps ``archive`` ``YYYY-MM`` past years, 15-minute steps ``hourly_current`` ``YYYY-MM-DD`` this year, hourly steps ``hourly_archive`` ``YYYY-MM`` past years, hourly steps ================== ============== ================================== """ def __init__(self, client: "WeatherClient") -> None: self._client = client # ------------------------------------------------------------------ # Listing # ------------------------------------------------------------------
[docs] def list_months(self, type: str = "archive") -> list[str]: """List available ``YYYY-MM`` archive months, newest first. Args: type: ``"archive"`` (15-min) or ``"hourly_archive"``. """ return self._client.list("hrrr", type)
[docs] def list_days(self, type: str = "current") -> list[str]: """List available ``YYYY-MM-DD`` days, newest first. Args: type: ``"current"`` (15-min) or ``"hourly_current"``. """ return self._client.list("hrrr", type)
[docs] def list_forecast_cycles(self) -> list[str]: """List available forecast cycles like ``["2026-07-22T12Z"]``, newest first.""" return self._client.list("hrrr", "forecast")
# ------------------------------------------------------------------ # Download # ------------------------------------------------------------------
[docs] def download_history( self, months: list[str] | None = None, dest: str = ".", *, days: list[str] | None = None, type: str | None = None, **kwargs, ) -> list[Path]: """Download HRRR history files, one per date key. Args: months: ``YYYY-MM`` keys (archive). dest: Destination directory. days: ``YYYY-MM-DD`` keys (current year) — use instead of *months*. type: Explicit sub-type; inferred from months/days when omitted. **kwargs: Passed to :meth:`WeatherClient.download`. Raises: ValueError: If both or neither of *months* and *days* are given. """ dates, inferred = _history_dates(months, days) return self._client.download("hrrr", dates, type or inferred, dest=dest, **kwargs)
[docs] def download_forecast(self, cycles: list[str], dest: str = ".", **kwargs) -> list[Path]: """Download HRRR forecast files, one ZIP per cycle.""" return self._client.download("hrrr", cycles, "forecast", dest=dest, **kwargs)
[docs] def download_region( self, *, months: list[str] | None = None, days: list[str] | None = None, cycles: list[str] | None = None, type: str | None = None, region_ids: list[str] | None = None, region_layer: str | None = None, bbox: tuple | None = None, dest: str = ".", **kwargs, ) -> list[Path]: """Download HRRR data cropped to a region or bbox. CONUS-scale archive requests are cropped locally, since the server refuses them to protect its memory budget. Args: months: ``YYYY-MM`` archive keys. days: ``YYYY-MM-DD`` current-year keys. cycles: Forecast cycle keys. type: Explicit sub-type; inferred from the date argument when omitted. region_ids: State postal codes or ISO zone ids. region_layer: ``"states"`` or ``"iso"``. bbox: ``(lat_max, lon_min, lat_min, lon_max)``. dest: Destination directory. **kwargs: Passed to :meth:`WeatherClient.download` (``time_start``, ...). Raises: ValueError: If not exactly one of months/days/cycles is given. """ spatial = _spatial(region_ids, region_layer, bbox) if cycles is not None: if months is not None or days is not None: raise ValueError("Provide exactly one of months, days, or cycles") return self._client.download("hrrr", cycles, type or "forecast", dest=dest, **spatial, **kwargs) dates, inferred = _history_dates(months, days) return self._client.download("hrrr", dates, type or inferred, dest=dest, **spatial, **kwargs)
[docs] def download_latest_forecast(self, dest: str = ".", **kwargs) -> Path: """Download the most recent HRRR forecast cycle. Raises: ValueError: If no forecast cycles are available. """ cycles = self.list_forecast_cycles() if not cycles: raise ValueError("No HRRR forecast cycles are currently available.") return self.download_forecast([cycles[0]], dest=dest, **kwargs)[0]
def _history_dates(months, days) -> tuple[list[str], str]: """Pick the date list and infer the matching history sub-type.""" if (months is None) == (days is None): raise ValueError("Provide exactly one of months (YYYY-MM) or days (YYYY-MM-DD)") return (list(months), "archive") if months is not None else (list(days), "current")