5.9 KiB
5.9 KiB
DWD Regen-Vorhersage (Radar-Nowcast) — Scoping-Plan
Status: UMGESETZT auf Staging (v1240, 2026-06-08) — PoC bestanden, Pipeline + Frontend live. Offen: DSM-Aufgabenplaner-Cron (alle 5 Min, Staging + Prod) anlegen; Gerätetest; Prod-Deploy.
Umsetzung (2026-06-08)
- PoC Georeferenzierung BESTANDEN (
tools/dwd-radar/poc/): DE1200 = polar-stereografisch auf WGS84-Ellipsoid (wradlib-Parameter, False Easting/Northing 543196.835/3622588.862 → LL-Ecke (0,0); in GDAL-Konvention y südwärts negativ, Gitter y ∈ [-1200000, 0]). Anker (9°E, 51°N) = Mitte von Pixel (470/600) ✓, Ecken decken sich mit der DE1200-Spec ✓. - Pipeline
tools/dwd-radar/make_radar_tiles.py(Container: GDAL + go-pmtiles): RV-Komposit → je Frame dekodieren → RGBA-Farbskala (transparent < 0,05 mm/5min) → Warp 3857 → MBTiles z7-Basis- Overviews bis z4 → PMTiles. 25 Frames ≈ 14 s (Mac) / ~30 s (DS). Manifest + atomarer Swap
(
run-<id>/), KEEP_RUNS=2.docker-compose.dwd.yml— DSM-Aufgabenplaner ALLE 5 MIN:cd <pfad> && docker compose -f docker-compose.dwd.yml run --rm dwd-radar(⚠️ NIE --remove-orphans).
- Overviews bis z4 → PMTiles. 25 Frames ≈ 14 s (Mac) / ~30 s (DS). Manifest + atomarer Swap
(
- Serving main.py:
/radar/manifest.json(no-store) +/radar/{run}/{file}(Range/206, immutable — Run-Id im Pfad). sw.js:/radar/Pass-through. - Frontend map.js: Radar-Frames heterogen (
{url, time, dwd}) — DWD ersetzt den RainViewer- Nowcast (0–120 min) wenn: Toggle an + GL-Modus + Kartenmitte in DE1200-Bbox + Manifest frisch (< 30 min). Sonst RainViewer-Fallback (auch außerhalb DE / offline / DWD-Ausfall). DWD-Frames alspmtiles://-Raster-Template über das vorhandene Protokoll; Label „+X Min · DWD". - Settings-Toggle „DWD-Regenvorhersage" (
by_dwd_radar, Default AN), settings.js.
(Ursprüngliches Scoping:)
Status: gescoppt + Datenformat verifiziert (2026-06-05). Umsetzung offen.
Ziel: Verlässliche, längere Regen-Vorhersage als animiertes Karten-Overlay (bis +2 h) statt RainViewers
unzuverlässigem 30-Min-Nowcast (der oft leer ist). Self-hosted wie die Basemap — passt zur Tile-Server-Philosophie.
Quelle: DWD RV (Composite RV) — kostenlos, kein API-Key
https://opendata.dwd.de/weather/radar/composite/rv/DE1200_RV<YYMMDDHHMM>.tar.bz2- Alle 5 Min publiziert. Jedes Archiv = ein Vorhersage-Lauf mit 25 Frames
_000…_120(0 bis +120 Min, 5-Min-Schritte), je ~2,5 MB unkomprimiert (~1 MB als .tar.bz2). - Format (verifiziert): RADOLAN-Binär. 194-Byte-ASCII-Header bis
ETX (0x03), dann 1200×1100 uint16 little-endian (= 2.640.000 Byte). Header-Felder:PR E-02(0,01 mm),INT 5(5-Min-Summe),GP1200x1100,VV<lead>(Lead-Time). Wert =raw & 0x0FFF× 0,01 mm/5min;raw & 0x2000= kein Daten. → Decode trivial, kein wradlib nötig (PoC: 1,32 Mio Zellen geparst, Regen korrekt erkannt). - Gitter/Projektion: DE1200 (1 km), polar-stereografisch, fest georeferenziert (Eckkoordinaten dokumentiert;
wradlib
get_radolan_gridODER GDAL mit dem bekannten RADOLAN-PROJ-String). - Abdeckung: Deutschland + Randbereiche (reicht etwas nach AT/CH/Nachbarn, aber DE-zentriert). Voll-AT/CH bräuchte ACG/MeteoSwiss → out of scope.
Pipeline (Server-seitig, Cron alle 5 Min — analog zum OSM-POI-Job)
- Fetch neueste
DE1200_RV<time>.tar.bz2(Verzeichnis-Listing → letzte Datei). - Entpacken → 25 RADOLAN-Grids.
- Decode je Grid → 2D-Niederschlags-Array (eigener ~15-Z.-Parser, PoC-bewiesen).
- Kolorieren → RGBA (transparent bei 0/kein-Regen; Radar-Farbskala wie das aktuelle Overlay).
- Reprojektion DE1200 → EPSG:3857 + Kacheln z0–9 (Radar ist grob 1 km → höher zoomen bringt nichts). Tooling: GDAL (gdalwarp + gdal2tiles) oder rasterio/rio-tiler.
- Output: 25 Frame-Tilesets — je eine kleine PMTiles pro Lead-Time (
rv_000.pmtiles…rv_120.pmtiles) ODER XYZ-PNG. Nur neuesten Lauf behalten (atomarer Swap wie dach.pmtiles). Plusrv_manifest.json(Lauf-Zeit, Lead-Times, Tile-URL-Muster). - Ausliefern von der DS (wie
/tiles).
Frontend (bestehende Radar-Timeline erweitern, map.js)
- Manifest laden → DWD-Vorhersage-Frames (0…+120 Min) rechts von „jetzt" in die Timeline einhängen
(die Forecast-Markierung
is-forecast+ Scrub/Play gibt es schon). - Vergangenheit: weiter RainViewer (einfach) ODER DWD RADOLAN-RY (5-Min-Analyse) für all-DWD-Konsistenz.
- Quelle pro Frame: Vergangenheit = RainViewer-Tiles, Vorhersage = DWD-PMTiles (byt-/raster-Source).
Aufwand & offene Entscheidungen
- Decode: trivial (verifiziert). Projektion: der einzige Knackpunkt — DE1200-Georeferenzierung korrekt nach 3857 (wradlib nimmt's ab, oder bekannter PROJ-String + Eckkoordinaten). PoC nötig: 1 Frame → Tiles → über MapLibre rendern und gegen RainViewer/echten Regen gegenchecken (Passgenauigkeit).
- Tiling alle 5 Min × 25 Frames: z0–9 für DE ist schnell (Sekunden–~1 Min auf der DS). Last beachten (läuft neben Immich & Co.); ggf. nur jeden 2. Lead-Time tilen (10-Min-Schritte) zum Sparen.
- Speicher: Radar-Tiles sind dünn/transparent → wenige MB pro Lauf.
- Cron alle 5 Min: neuer Container/Job (analog
docker-compose.osm.yml); ⚠️--remove-orphans-Falle. - Entscheidungen: (a) Vergangenheit RainViewer vs. DWD-RY; (b) PMTiles-pro-Frame vs. XYZ; (c) Farbskala; (d) Zoom-Range (z0–9) + Lead-Schrittweite (5 vs 10 Min); (e) Container-Stack (GDAL/Python) auf der DS.
- Abhängigkeit: Docker auf der DS.
Nächste Schritte
- PoC: 1 RV-Archiv → 1 Frame decode → kolorieren → reprojizieren → 1 PMTiles → headless über MapLibre rendern. Kernfrage: stimmt die Georeferenzierung? (Wenn ja, ist der Rest Fleißarbeit.)
- Pipeline-Skript (fetch→decode→tile→deploy) + Cron-Job + Manifest.
- Frontend: Manifest in die Timeline einhängen (Vorhersage-Frames rechts von „jetzt").
Siehe docs/TILE_SERVER_HANDOVER.md (Tile-Infra), Memory project_tile_server_maintenance.