78 lines
5.9 KiB
Markdown
78 lines
5.9 KiB
Markdown
# 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).
|
||
- **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
|
||
als `pmtiles://`-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_grid` ODER 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)
|
||
1. **Fetch** neueste `DE1200_RV<time>.tar.bz2` (Verzeichnis-Listing → letzte Datei).
|
||
2. **Entpacken** → 25 RADOLAN-Grids.
|
||
3. **Decode** je Grid → 2D-Niederschlags-Array (eigener ~15-Z.-Parser, PoC-bewiesen).
|
||
4. **Kolorieren** → RGBA (transparent bei 0/kein-Regen; Radar-Farbskala wie das aktuelle Overlay).
|
||
5. **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.
|
||
6. **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). Plus **`rv_manifest.json`**
|
||
(Lauf-Zeit, Lead-Times, Tile-URL-Muster).
|
||
7. **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
|
||
1. **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.)
|
||
2. Pipeline-Skript (fetch→decode→tile→deploy) + Cron-Job + Manifest.
|
||
3. 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`.
|