Why
The meteofrance model slot is today served only by Open-Meteo's meteofrance_seamless, which exposes no condensate and no vertical velocity for Météo-France. Worse, seamless silently blends: AROME 0.025° inside the AROME footprint, ARPEGE outside, with nothing marking the seam (verified — at Paris, seamless T850 = AROME 21.2 °C while ARPEGE reads 21.8 °C).
AROME is a convection-permitting model (2.5 km / 1.3 km) whose physics is Meso-NH with ICE3 five-species microphysics; only its ALADIN-NH dynamical core descends from the ARPEGE/IFS family. So on the fields that matter for icing and convection it is genuinely independent of the ECMWF IFS we already ingest.
What this buys us is geographic, and bounded. Measured against the ICON-D2 domain:
| route |
D2 coverage |
AROME coverage |
| London → Cannes |
61/61 |
61/61 |
| London → Paris |
61/61 |
61/61 |
| London → Brest |
53/61 |
61/61 |
| London → Dublin |
37/61 |
61/61 |
| Cannes → Barcelona |
11/61 |
61/61 |
46 % of AROME's footprint lies outside ICON-D2 — Ireland, Brittany and western France, Iberia, the western Med. Core corridors are already D2-covered, so AROME is gap-filling plus a second, independent convection-permitting opinion where the two overlap. It is not a prerequisite for the icing win; that comes from the near-free ICON-D2 species work.
ARPEGE was evaluated and deliberately excluded: it shares the IFS codebase with ECMWF (co-developed since 1987), adds nothing convective (no reflectivity, no lightning; its CAPE_INS we already have via Open-Meteo), and is the least independent model we could add alongside the ECMWF we already ingest.
Source — verified live 2026-07-30
Public OVH mirror, no API key required:
https://meteofrance-pnt.s3.rbx.io.cloud.ovh.net/pnt/{RUN}/arome/0025/{PKG}/arome__0025__{PKG}__{RANGE}__{RUN}.grib2
RUN format 2026-07-30T12:00:00Z; RANGE ∈ 00H06H, 07H12H, 13H18H, 19H24H, 25H30H, 31H36H, 37H42H, 43H48H, 49H51H
- 8 runs/day (00,03,06,09,12,15,18,21 Z), horizon 51 h, publish ≈ +3 h (12Z first group landed 15:13 Z)
Accept-Ranges: bytes confirmed — HTTP 206 works mid-file, so per-message byte-range extraction is available if volume ever demands it (demonstrated: a single 88 KB message fetched by offset and decoded standalone)
- 1.3 km stream lives at
.../arome/001/{PKG}/arome__001__{PKG}__{HH}H__{RUN}.grib2, hourly
- Run/resource discovery: the data.gouv.fr dataset API
paquets-arome-resolution-0-025deg enumerates every resource URL
⚠️ Do not use object.data.gouv.fr/meteofrance-pnt — that is the URL in Open-Meteo's source and it is stale, newest run 2026-05-11.
⚠️ Do not use the public-api.meteofrance.fr package endpoint: it requires a key and does not support range requests.
Packages
| pkg |
contents |
size / 6 h group |
IP2 |
clwc, ciwc, crwc, cswc, graupel (cat1/num201), cc — 24 levels 100–1000 hPa, hourly |
146 MB |
IP4 |
tke (24 levels) + 3-D reflectivity (cat16/num192, 16 levels 200–925 hPa) |
68 MB |
001/SP2 |
column-max reflectivity (cat16/num193), CAPE_INS, tgrp, lcc/mcc/hcc, tirf — 1.3 km hourly |
~1.0 MB for the reflectivity message |
Pressure levels: 100,125,150,175,200,225,250,275,300,350,400,450,500,550,600,650,700,750,800,850,900,925,950,1000.
Measured per-message: clwc 0.181 MB, ciwc 0.146 MB, cc 0.126 MB, crwc 0.122 MB.
shortNames
clwc, ciwc, cc are already in _VAR_MAP (src/weatherbrief/fetch/grib/decode.py:32-42) from the ECMWF IFS path — they map straight through. crwc/cswc are standard eccodes names. Graupel and both reflectivity fields are Météo-France local parameters that eccodes reports as unknown; select them by (discipline, parameterCategory, parameterNumber) — the same technique already used for HRRR's CIMIXR (see the unknown note in the HRRR var map in decode.py).
Identification is corroborated by physics: ICE3 carries exactly five prognostic condensate species (cloud droplets, rain, ice, snow, graupel), and IP2 contains exactly clwc+ciwc+crwc+cswc+one unknown — hence cat1/num201 = graupel.
Domain gate — mandatory prerequisite
AROME's array is 717×1121 regular lat/lon over 37.5–55.4 N / −12–16 E, but only 82.8 % of cells are finite. The valid region is a bowed quadrilateral that narrows southward: west edge −11.5° at 53 N → −8.4° at 39 N, and at 55.38 N only −0.5…4.5. It is not an axis-aligned box, and not a clean Lambert conformal rectangle either (fitting one leaves 61 km of edge scatter).
Required:
- Generate a data-derived per-latitude
[west, east] row table from a CONSTANT or SP1 GRIB, checked in as data, with a regeneration script so it can be refreshed if MF changes the domain.
- Implement
route_in_arome_domain(route_points) -> bool, mirroring route_in_icon_eu_domain() (src/weatherbrief/fetch/grib/icon_eu_fetch.py:448) — all-or-nothing, false if any route point is outside.
Note: the same predicate is needed by the separate narrow-only Open-Meteo model-gating work (limiting the meteofrance slot to routes fully inside AROME rather than merely touching France). Build it once, in a place both can import.
Implementation sketch
src/weatherbrief/fetch/grib/arome_fetch.py, mirroring icon_eu_fetch.py: a frozen config dataclass (cycles, publish delay, horizon, packages, levels), run finder that HEAD-probes back through cycles, package URL builder, flight-window → package-group mapping, the domain predicate, and cache-key helpers.
- Decode: extend
_VAR_MAP with crwc → rain_water_kg_kg, cswc → snow_water_kg_kg; add an MF-local parameter map keyed on (0,1,201) → graupel, (0,16,192) → 3-D reflectivity, (0,16,193) → column-max reflectivity.
- Orchestrator: add
_prepare_arome / _prefetch_arome_data / _decode_and_merge_arome alongside the ICON trio in src/weatherbrief/fetch/grib/__init__.py (anchors: _prepare_icon_eu :3836, _prefetch_icon_eu_data :3962, _decode_and_merge_icon_eu :4281), keyed to ModelSource.METEOFRANCE (models/analysis.py:449), and record grib_sources["meteofrance"] = "arome:mf".
- Freshness: add
SOURCE_REGISTRY["arome:mf"] in src/weatherbrief/fetch/freshness/registry.py, following the icon_d2:dwd entry at :307 — 8 cycles, ~3 h publish delay, 51 h horizon.
- Skip paths: reuse the existing
grib_skip_reasons mechanism (the "out_of_domain" reason string already exists — see _prepare_icon_eu's docstring). Skip when the route is not fully inside the domain, or when the flight window exceeds the 51 h horizon; degrade silently to Open-Meteo.
Scope
In: IP2 condensate + cc; the domain gate and row table; freshness registration; merging clwc/ciwc/cc into the enrichment path so meteofrance carries real condensate; window/domain skip handling.
Deferred to follow-ups (no consumer exists yet — do not build speculatively):
Dependency
#530 adds rain_water_kg_kg / snow_water_kg_kg / graupel_water_kg_kg to PressureLevelData and their consumers. Land that first and this issue just feeds them. If this lands first, add the fields here.
Acceptance criteria
Risks
- Volume. IP2 alone is 146 MB per 6 h group — roughly 584 MB per run to cover 0–24 h, at 8 runs/day. GRIB precache is currently disabled in production (
WB_GRIB_PRECACHE_ENABLED=false, after an OOM killed a user briefing). Do not enable AROME prefetch on the droplet without a memory plan; the home-compute offload path is the natural host for this ingestion.
- Reflectivity units. MF's parameter description labels
RFLCTVT as "Derived radar reflectivity backscatter from rain" with unit m6 m-3, but measured values span 0–62 (peak 62.2 at 1.3 km, 57 dBZ at 650 hPa in the 3-D field) which reads as dBZ. Confirm at decode before any threshold is set on it.
- Domain drift. The row table is derived from data; if MF changes the AROME domain the table silently goes stale. The regeneration script and a periodic assertion (finite-fraction ≈ 82.8 %) guard this.
Why
The
meteofrancemodel slot is today served only by Open-Meteo'smeteofrance_seamless, which exposes no condensate and no vertical velocity for Météo-France. Worse,seamlesssilently blends: AROME 0.025° inside the AROME footprint, ARPEGE outside, with nothing marking the seam (verified — at Paris, seamless T850 = AROME 21.2 °C while ARPEGE reads 21.8 °C).AROME is a convection-permitting model (2.5 km / 1.3 km) whose physics is Meso-NH with ICE3 five-species microphysics; only its ALADIN-NH dynamical core descends from the ARPEGE/IFS family. So on the fields that matter for icing and convection it is genuinely independent of the ECMWF IFS we already ingest.
What this buys us is geographic, and bounded. Measured against the ICON-D2 domain:
46 % of AROME's footprint lies outside ICON-D2 — Ireland, Brittany and western France, Iberia, the western Med. Core corridors are already D2-covered, so AROME is gap-filling plus a second, independent convection-permitting opinion where the two overlap. It is not a prerequisite for the icing win; that comes from the near-free ICON-D2 species work.
ARPEGE was evaluated and deliberately excluded: it shares the IFS codebase with ECMWF (co-developed since 1987), adds nothing convective (no reflectivity, no lightning; its
CAPE_INSwe already have via Open-Meteo), and is the least independent model we could add alongside the ECMWF we already ingest.Source — verified live 2026-07-30
Public OVH mirror, no API key required:
RUNformat2026-07-30T12:00:00Z;RANGE∈00H06H, 07H12H, 13H18H, 19H24H, 25H30H, 31H36H, 37H42H, 43H48H, 49H51HAccept-Ranges: bytesconfirmed — HTTP 206 works mid-file, so per-message byte-range extraction is available if volume ever demands it (demonstrated: a single 88 KB message fetched by offset and decoded standalone).../arome/001/{PKG}/arome__001__{PKG}__{HH}H__{RUN}.grib2, hourlypaquets-arome-resolution-0-025degenumerates every resource URLobject.data.gouv.fr/meteofrance-pnt— that is the URL in Open-Meteo's source and it is stale, newest run 2026-05-11.public-api.meteofrance.frpackage endpoint: it requires a key and does not support range requests.Packages
IP2clwc,ciwc,crwc,cswc, graupel (cat1/num201),cc— 24 levels 100–1000 hPa, hourlyIP4tke(24 levels) + 3-D reflectivity (cat16/num192, 16 levels 200–925 hPa)001/SP2cat16/num193),CAPE_INS,tgrp,lcc/mcc/hcc,tirf— 1.3 km hourlyPressure levels:
100,125,150,175,200,225,250,275,300,350,400,450,500,550,600,650,700,750,800,850,900,925,950,1000.Measured per-message:
clwc0.181 MB,ciwc0.146 MB,cc0.126 MB,crwc0.122 MB.shortNames
clwc,ciwc,ccare already in_VAR_MAP(src/weatherbrief/fetch/grib/decode.py:32-42) from the ECMWF IFS path — they map straight through.crwc/cswcare standard eccodes names. Graupel and both reflectivity fields are Météo-France local parameters that eccodes reports asunknown; select them by(discipline, parameterCategory, parameterNumber)— the same technique already used for HRRR'sCIMIXR(see theunknownnote in the HRRR var map indecode.py).Identification is corroborated by physics: ICE3 carries exactly five prognostic condensate species (cloud droplets, rain, ice, snow, graupel), and IP2 contains exactly
clwc+ciwc+crwc+cswc+one unknown — hencecat1/num201= graupel.Domain gate — mandatory prerequisite
AROME's array is 717×1121 regular lat/lon over 37.5–55.4 N / −12–16 E, but only 82.8 % of cells are finite. The valid region is a bowed quadrilateral that narrows southward: west edge −11.5° at 53 N → −8.4° at 39 N, and at 55.38 N only −0.5…4.5. It is not an axis-aligned box, and not a clean Lambert conformal rectangle either (fitting one leaves 61 km of edge scatter).
Required:
[west, east]row table from a CONSTANT or SP1 GRIB, checked in as data, with a regeneration script so it can be refreshed if MF changes the domain.route_in_arome_domain(route_points) -> bool, mirroringroute_in_icon_eu_domain()(src/weatherbrief/fetch/grib/icon_eu_fetch.py:448) — all-or-nothing, false if any route point is outside.Note: the same predicate is needed by the separate narrow-only Open-Meteo model-gating work (limiting the
meteofranceslot to routes fully inside AROME rather than merely touching France). Build it once, in a place both can import.Implementation sketch
src/weatherbrief/fetch/grib/arome_fetch.py, mirroringicon_eu_fetch.py: a frozen config dataclass (cycles, publish delay, horizon, packages, levels), run finder that HEAD-probes back through cycles, package URL builder, flight-window → package-group mapping, the domain predicate, and cache-key helpers._VAR_MAPwithcrwc→rain_water_kg_kg,cswc→snow_water_kg_kg; add an MF-local parameter map keyed on(0,1,201)→ graupel,(0,16,192)→ 3-D reflectivity,(0,16,193)→ column-max reflectivity._prepare_arome/_prefetch_arome_data/_decode_and_merge_aromealongside the ICON trio insrc/weatherbrief/fetch/grib/__init__.py(anchors:_prepare_icon_eu:3836,_prefetch_icon_eu_data:3962,_decode_and_merge_icon_eu:4281), keyed toModelSource.METEOFRANCE(models/analysis.py:449), and recordgrib_sources["meteofrance"] = "arome:mf".SOURCE_REGISTRY["arome:mf"]insrc/weatherbrief/fetch/freshness/registry.py, following theicon_d2:dwdentry at :307 — 8 cycles, ~3 h publish delay, 51 h horizon.grib_skip_reasonsmechanism (the"out_of_domain"reason string already exists — see_prepare_icon_eu's docstring). Skip when the route is not fully inside the domain, or when the flight window exceeds the 51 h horizon; degrade silently to Open-Meteo.Scope
In: IP2 condensate +
cc; the domain gate and row table; freshness registration; mergingclwc/ciwc/ccinto the enrichment path someteofrancecarries real condensate; window/domain skip handling.Deferred to follow-ups (no consumer exists yet — do not build speculatively):
IP4TKE and 3-D reflectivity ingestion.crwc/cswc/graupel — that logic is model-agnostic and belongs to ICON-D2/EU: fetch qr/qs/qg + tke (and EU lpi_con_max/cape_con), and use the new species for precip phase & icing #530; AROME simply becomes a second producer of the same fields.Dependency
#530 adds
rain_water_kg_kg/snow_water_kg_kg/graupel_water_kg_kgtoPressureLevelDataand their consumers. Land that first and this issue just feeds them. If this lands first, add the fields here.Acceptance criteria
meteofrancewith non-nullcloud_liquid_water_kg_kg/ice_mixing_ratio_kg_kgat cruise levels.designs/weather-engine-specs.mdupdated with the new source, bucket paths and variable table (it already documents GFS/ICON-EU/ECMWF this way).Risks
WB_GRIB_PRECACHE_ENABLED=false, after an OOM killed a user briefing). Do not enable AROME prefetch on the droplet without a memory plan; the home-compute offload path is the natural host for this ingestion.RFLCTVTas "Derived radar reflectivity backscatter from rain" with unitm6 m-3, but measured values span 0–62 (peak 62.2 at 1.3 km, 57 dBZ at 650 hPa in the 3-D field) which reads as dBZ. Confirm at decode before any threshold is set on it.