Query AROME-PI and PIAF forecasts
AromePISource and PiafSource retrieve geographically targeted surface
forecasts through Météo-France's authenticated WCS APIs. Install the GRIB
backend from PyPI:
Subscribe to each API in the Météo-France portal.
| Source | Native grid | Output interval | Initializations | Maximum lead |
|---|---|---|---|---|
| AROME-PI | 0.025° or 0.01° | 15 minutes | Every hour | 6 hours |
| PIAF | 0.01° | 5 minutes | Every 5 minutes | 195 minutes |
These are forecasts, not reanalyses. The APIs expose about five days of runs. The date of initialization is preserved alongside the forecast lead. A run's initialization time is not its publication time.
Credentials and fixed runs
Keep credentials outside the repository. The following example reads an API
key from a private local file; its contents are sent only in the apikey
header, never in URLs or cache keys. Paths are application configuration,
not hardcoded by the library.
For example, create separate files for the API keys authorized for AROME-PI and PIAF. In Bash on Linux, this prompts without echoing either key or putting its value into shell history:
install -d -m 700 "$HOME/.config/barograph"
(
umask 077
for api in arome-pi piaf; do
key_file="$HOME/.config/barograph/$api.token"
touch "$key_file"
chmod 600 "$key_file"
read -r -s -p "API key for $api: " barograph_key
printf '\n'
printf '%s\n' "$barograph_key" > "$key_file"
unset barograph_key
done
)
The files are ~/.config/barograph/arome-pi.token and
~/.config/barograph/piaf.token, readable only by their owner. Keep them out of
Git and do not paste their values into examples or issue reports. The library
does not automatically search these paths or load a .env file: pass a token
or a callable that reads your chosen file, as below. Public Open-Meteo archives
and the native public AROME GRIB source do not require these API keys.
from pathlib import Path
import numpy as np
from baro.met import AromePISource, SurfaceEnricher
key_file = Path("~/.config/barograph/arome-pi.token").expanduser()
run = np.datetime64("now", "h") - np.timedelta64(1, "h")
with AromePISource(
run=run,
token=lambda: key_file.read_text().strip(),
resolution="0.025",
) as source:
result = SurfaceEnricher(source, cache_dir="~/.cache/barograph/met").enrich(
time=[run + np.timedelta64(30, "m")],
lat=[48.8566],
lon=[2.3522],
)
result["wind_speed"], result["wind_direction"]
result["gusts"], result["precipitation"], result["t2m"]
result.run, result.lead, result.flags
Choose a published run for reproducible results; the example's preceding-hour
run is a convenience, not a guarantee of publication. API keys use
auth="apikey" by default. For an OAuth access token use auth="bearer".
A callable token supplier can handle renewal outside the library. HTTP 401/403
raises an explicit authentication error, rather than returning missing weather.
Fields and resolution
On the 0.025° AROME-PI grid, the default fields are u10, v10, t2m,
precipitation, and gusts. The 0.01° grid defaults to t2m, precipitation,
and gusts: mean wind components are not published on that finer grid.
rain (liquid precipitation) is optional on either grid. All fields are
validated against the returned GRIB parameter, level, units, run, and interval.
Use fields={"temperature": "t2m"} to request only temperature, or any other
mapping of output names to the canonical fields. Wind speed and meteorological
wind-from direction are derived after interpolating u10/v10. If you alias
these components, set SurfaceEnricher(..., wind_components=("east", "north"))
to the chosen output names.
PIAF provides deterministic precipitation amounts:
from baro.met import PiafSource
key_file = Path("~/.config/barograph/piaf.token").expanduser()
valid_time = np.datetime64("now", "s") + np.timedelta64(15, "m")
with PiafSource.latest(
valid_time, token=lambda: key_file.read_text().strip()
) as source:
result = SurfaceEnricher(source, cache_dir="~/.cache/barograph/met").enrich(
[valid_time], [48.8566], [2.3522]
)
result["precipitation"] # mm over the enclosing native five-minute interval
result.interval_start["precipitation"], result.interval_end["precipitation"]
The PIAF WCS coverage name contains TOTAL_PRECIPITATION_RATE, but its GRIB
product is an accumulated amount in kg/m², equivalent to mm. It must not be
multiplied by the interval duration as though it were a rate. The reader
rejects incompatible statistical products rather than guessing their meaning.
Time semantics and run selection
Instantaneous fields are interpolated between adjacent native times in the
same run. Precipitation retains the full amount over (start, end]; gusts
retain the maximum over that interval. At a fractional query time, these
period fields describe the enclosing interval, including its future portion.
They are not interpolated or prorated. At an exact boundary, the preceding
interval is returned. No period exists at lead zero.
latest(valid_time, ...) chooses the newest catalogued run with the necessary
field endpoints and heights. source.observed_at records when that selection
was made. This checks metadata observed now, not which forecast could have
been downloaded at a historical cutoff. A missing download never silently
switches the selected run. published_runs(refresh=True) refreshes the catalog.
The public APIs' short retention is distinct from an archive service: saving requested responses in the cache does not create a complete historical archive. Météo-France's PIAF documentation also mentions a three-year rolling archive via BDAP, whose access is separate and is not implemented here.
Download scope and caching
The reader requests one parameter, level, run, valid time and geographic box per field. Bounds are snapped to the native grid centres required for bilinear interpolation (at least 2×2). Exact timestamps avoid the unused next endpoint; fractional timestamps fetch the left endpoint only for instantaneous fields. Native interval products are preferred. A cumulative precipitation response requires only its preceding same-run counter, which is differenced explicitly.
tile_deg=0.25 groups nearby query points without merging an entire connected
trajectory into a large box. It controls request grouping, not model
resolution. Smaller values can reduce empty area while increasing request
count. This differs from Open-Meteo's storage tiles: WCS supplies a server-side
geographic subset, so an isolated site needs only its interpolation neighbours.
Validated GRIB responses use the shared RangeCache. Repeating identical
queries with the same source and cache causes zero network transfers. A new
source discovers the current catalog and field metadata again; these can be
larger than the requested weather data. Cached field responses are reusable
across source instances, processes and token renewal. Overlapping but different
geographic subsets have different cache keys.
The cache is not an offline archive: a newly created source still needs the
run's catalog entry and metadata, so expired runs cannot be reopened through
these APIs merely because their GRIB responses remain on disk.