feat(p1): city flood stages and zones from CMU Water Center's 2024 flood map
CI / Format & lint (push) Successful in 49s
CI / Test suite (push) Successful in 59s
Docs / Validate documentation (push) Successful in 27s
Security / Dependency vulnerabilities (push) Successful in 1m5s
Security / Static analysis (push) Successful in 17s
Security / License report (push) Successful in 45s
Rust / fmt, clippy, test, build (push) Successful in 3m42s

CMU Water Center's Chiang Mai flood hazard map (CMFlood) replaces the older
municipal map. It is built on the October 2024 flood and has the Ping leave
its banks above P.1 4.20 m, with five stages: 4.30, 4.50, 4.70, 5.00 and
5.30 m (the 2024 record). The old map's seven stages (3.70-4.60 m) said the
city floods from 3.70 m; CMU calls that map out of date.

- P1_FLOOD_STAGES: the five CMU stages, discharge on RID's 2024 rating.
  /forecast's P.1 `stages` now has five entries (same format). Thresholds
  are unchanged: 4.20 m danger is the bank top, 3.70 m warning half a metre
  below (as on CMU's gauge page). flood_config.json and the Rust parity
  fixtures regenerated (only the stages changed).
- flood-zones-p1.geojson: CMU's KML (L1..L5) as five disjoint zones, zone k
  floods first at stage k; scripts/build_flood_zones.py rebuilds it.
- Dashboard: CMU's colours and credit (map attribution); the stage grid follows
  the number of stages; zone lookup for markers honours holes. The city
  verdict uses statusOf's classes: flooding (over the banks) from 4.20 m,
  high water from 3.70 m. Zones show by themselves when the river is over its
  banks or stage 1 is >= 50 % likely. Alert, replay and verdict texts no
  longer call 3.70 m city flooding (EN + TH).
- Docs: DATA_SOURCES 5.1 (CMFlood: the map, flood marks, poles, city gauges),
  FLOOD_FORECASTING, DASHBOARD_REDESIGN, NOTIFICATIONS, README credits.
This commit is contained in:
grabowski committed 2026-10-26 14:19:52 +07:00
1 parent 180d95c6bd
commit 701bb87d34
13 files changed
+301 -101

No files matched your search

+3 -3
View File
@@ -52,7 +52,7 @@ One screen, no page scroll on a desktop:
| Top bar | brand · **Chiang Mai verdict** (P.1 level + 24 h forecast, always visible, click selects P.1) · gauges reporting · highest 24 h flood chance · data age · EN/ไทย · light/dark · Get alerts |
| Left | two lists: **RID gauges** (status bar, code, name, margin to the warning level, 72 h sparkline, level and 6 h change; sort by river order, closest to the warning level, rising) and **Basin stations** (ThaiWater/HII: % of bank height, river and agency; sort fullest first or by name); filter; legend |
| Centre | map on a self-hosted vector basemap (labels in the page language): Ping mainstem and tributaries, gauges coloured by status with code + level labels, layers Basin stations (diamonds), Rain 24 h and Flood zones, the team's markers from zoom 12, one legend |
| Right | selected RID gauge: level, 6 h change, discharge, warning/danger level with margins, capacity; level scale with now and 24 h peak; history (3 d / 7 d / 30 d / 90 d / 1 y / all or dates: level, discharge, the 24 h peaks as issued, warning/danger bands, hover values; up to 7 d it ends in the current forecast); forecast table (peak, chance of warning/danger at 6/12/24 h, model, issue time, disclaimer); for P.1 the seven inundation stages, the zones toggle and "How accurate is the forecast?"; data links. A basin station shows level (m MSL), % of bank height with ThaiWater's class, distance to and height of the bank top, gauge reading, agency (latest reading only: no history is kept for them) |
| Right | selected RID gauge: level, 6 h change, discharge, warning/danger level with margins, capacity; level scale with now and 24 h peak; history (3 d / 7 d / 30 d / 90 d / 1 y / all or dates: level, discharge, the 24 h peaks as issued, warning/danger bands, hover values; up to 7 d it ends in the current forecast); forecast table (peak, chance of warning/danger at 6/12/24 h, model, issue time, disclaimer); for P.1 the five city flood stages, the zones toggle and "How accurate is the forecast?"; data links. A basin station shows level (m MSL), % of bank height with ThaiWater's class, distance to and height of the bank top, gauge reading, agency (latest reading only: no history is kept for them) |
| Status bar | data credits, "2.7M readings since 2018" (opens the data statistics), API, source code |
**Narrower screens:**
@@ -104,11 +104,11 @@ One screen, no page scroll on a desktop:
| Danger | level ≥ `threshold_danger` |
| No data | no reading for 24 h |
- **City verdict:** the old dashboard's rule — flooding from P.1 ≥ 3.70 m; "likely" at danger ≥ 50 % or warning ≥ 70 %; watch at warning ≥ 20 % or level ≥ 3.20 m.
- **City verdict:** the classes of `statusOf` for P.1 — flooding (the Ping over its banks) from 4.20 m, high water from 3.70 m; "flooding likely" at danger ≥ 50 %, "high water likely" at warning ≥ 70 %; watch at warning ≥ 20 % or level ≥ 3.20 m. (Until 2026-10-25 it said flooding from 3.70 m, after the older municipal map.)
- **Data age:** "feed stale" after 3 h, except during RID's overnight pause (21:00 to 09:00 with an evening reading). The pause shows as "overnight pause", the same rule as the notifier's `FEED_NIGHT_UNTIL_HOUR`.
- **Discharge:** comes with RID's report. When the newest hour is a level-only reading, the panel shows the last RID discharge with its time ("at 14:00").
- **Rain layer:** off by default unless any station has heavy rain (> 35 mm / 24 h); an explicit choice is remembered.
- **Flood zones:** shown automatically while P.1 is at or above a stage, unless hidden by the user.
- **Flood zones:** `src/static/flood-zones-p1.geojson`, CMU Water Center's flood hazard map of the October 2024 flood (built by `scripts/build_flood_zones.py` from CMU's KML): five disjoint zones, zone k floods first when P.1 reaches stage k (4.30, 4.50, 4.70, 5.00, 5.30 m), in CMU's colours from deep red to yellow, credited in the map attribution. Shown automatically while P.1 is over its banks (danger level) or stage 1 is at least 50 % likely within 24 h, unless hidden by the user. A point's zone (team markers) honours the holes: dry islands inside a zone are outside it.
- **Basin stations:** ThaiWater's classes for the level as a share of the bank height (critically low ≤ 10 %, low ≤ 30 %, normal ≤ 70 %, high ≤ 100 %, over the bank). On the map and in the list over the bank is danger, high is watch, the rest normal; no data after 24 h. Gauges RID already lists are shown once, as RID gauges. The layer is off until the list is opened or the button pressed.
- **History:** above 2,500 readings (30 d and longer for most gauges) the chart shows the daily mean with the daily low–high band, so a flood peak is not averaged away; gaps longer than 3.5 h (2.5 days when daily) break the line rather than bridging RID's nightly pause. Short ranges reload with every refresh, long ones at most hourly. "All" asks for `limit=100000`: `/measurements/history` returns the oldest rows first and stops at its 50,000 default, which made the old dashboard's "All time" for P.1 end in October 2024.
- **Issued forecasts:** the history's violet line is the model's 24 h peak for every hour (`/api/forecast/history`, `source = model` only: a heuristic row is the level itself and drew a dip into the line). The nightly gaps were RID's overnight batch; the collector now forecasts those hours when they arrive (docs/FLOOD_FORECASTING.md, Serving).
+30
View File
@@ -235,6 +235,34 @@ Oct 2024 flood). Mae Kuang Udom Thara is the second upstream reservoir.
| `https://hydro-1.net` | RID Upper-Northern Hydrology Center — hourly/daily tables, hydrology yearbooks (rating curves) for P-series stations; scrape/download |
| `https://water.rid.go.th/flood/flood/daily.pdf` | RID daily flood bulletin (PDF only) |
### 5.1 CMU Water Center — CMFlood (Chiang Mai city) (verified 2026-10-25)
`https://watercenter.cmu.ac.th/chiangmai/cmflood/warning/*`, the Chiang Mai urban
flood warning site of Chiang Mai University's water center (with RID, ONWR, DDPM
and the province). A Next.js app; its data paths are in the page chunks
(`/_next/static/chunks/app/...`). No licence is stated; we credit CMU.
- **Flood hazard map, 2024 flood** — `/data/KML5Layer/L1.kml` … `L5.kml`: the
flooded extent at P.1 = 4.30 / 4.50 / 4.70 / 5.00 / 5.30 m (2.5 / 3.0 / 22 / 57 /
156 km², cumulative). CMU: the Ping overflows its banks above P.1 4.20 m, and the
older municipal map (2011 flood) no longer fits the city's defences. **In use:**
`P1_FLOOD_STAGES` and `src/static/flood-zones-p1.geojson`
(`uv run scripts/build_flood_zones.py`).
- **Flood marks 2024** — `/data/New_floodMark_2025_fixed_like_pole.geojson` (4.9 MB):
4,869 points in Chiang Mai and Lamphun with the October 2024 depth above the road
in cm (P.1 = 5.30 m), the marker's place and type.
- **Flood poles** — `/data/PoleCNX2025_v2.geojson`: 219 poles with ground level and
maximum flood level (m MSL) and the depth.
- **City-reach gauges** (station page): P.67, P.103, P.1, P.104 (RID, `ST.16`
every 15 min), FloodBoy FBP.2/FBP.3 (CMU climate data centre) and DDPM CMI01–03
(camera gauges, ~5 min, public CCTV snapshots), with gauge zero, bank levels
and chainage. CMU reads them from its own Supabase project with a public browser
key (tables `disaster_level`, `flagship_hydro`, `water_levels`, `hydro_levels`;
timestamps are Bangkok time labelled `+00:00`); history starts 2026-08 (FBP
2025-09). Not ingested: too short to train on, and polling CMU's database is
using their infrastructure — prefer the original sources or ask CMU.
- **P.1 forecast** (`floodforecast`): login only.
---
## 6. Integration status & recommended order
@@ -250,6 +278,8 @@ Oct 2024 flood). Mae Kuang Udom Thara is the second upstream reservoir.
| Satellite QPE (GSMaP/IMERG) | ❌ | Backfill training rainfall (GEE) |
| Open-Meteo rain | ✅ Hourly by ping-collector → `openmeteo_rain` (5 catchment points, past 5 days + 48 h forecast); the 2021+ archive trains the hgb-v3 rain features | — |
| HII API key (dams, forecasts) | ❌ | Contact HII for sanctioned access |
| CMU CMFlood flood map (2024) | ✅ Static (2026-10-25): P.1 stages and the city's flood zones | Rebuild with `scripts/build_flood_zones.py` if CMU revises the map |
| CMU CMFlood marks, poles, city gauges | ❌ | See 5.1 |
**Collector configuration** (ping-collector): HII, the dams and Open-Meteo are
fetched once per clock hour, also while RID is being retried; one-shot via
+15 -9
View File
@@ -465,15 +465,19 @@ validated.
**Thresholds are per-station as of 2026-08-10.** `THRESHOLDS` now carries
calibrated (warning, danger) pairs for all 16 stations, derived from the DB's
`discharge_percent` (RID % of channel capacity): warning = median level at
75–85% capacity, danger = median level at 95–105%. P.1 instead uses the official
Chiang Mai inundation map (`P1_FLOOD_STAGES`): warning 3.70 m (city flooding
begins, stage 1) and danger 4.20 m (stage 5). The prior single default of
75–85% capacity, danger = median level at 95–105%. P.1 is keyed to its banks:
danger 4.20 m, where the Ping overflows them (CMU Water Center's flood map of the
2024 flood; the lower bank is 304.65 m MSL = 4.15 m on the gauge), and warning
3.70 m, half a metre below. (Until 2026-10-25 the docs called 3.70 m "city flooding
begins", after the older municipal map; the values did not change.) The prior single default of
(3.0, 4.5) m made P.103 badly over-alert (its bank-full level is ~6.75 m) and
P.67 under-alert (overflow at ~2.9 m, 1.6 m below the old danger line).
**A retrain is required after any threshold change** — classifier labels depend
on them; until then, model rows report the thresholds baked into their bundle.
P.1 additionally reports `stages`: exceedance probability for each of the seven
official inundation stages (3.70–4.60 m), computed from the regression head and
P.1 additionally reports `stages`: exceedance probability for each of the five
city flood stages (`P1_FLOOD_STAGES`, 4.30–5.30 m, from CMU Water Center's flood
hazard map of the October 2024 flood; the seven stages of the older municipal map,
3.70–4.60 m, were replaced on 2026-10-25), computed from the regression head and
its calibration sigma, so they need no retrain and no per-stage classifiers.
### 2026-08-13: Mae Ngat dam features — a documented negative result
@@ -661,14 +665,16 @@ and `scripts/install.sh` does that on every install.
The dashboard (`src/static/dashboard.html`) loads `/forecast` with the gauges; if
it fails or is empty, the page works without forecasts. Where the model shows:
- **Top bar.** Chiang Mai's verdict from P.1: flooding at ≥ 3.70 m; "likely" at a
24 h danger chance ≥ 50 % or warning chance ≥ 70 %; "watch" at a warning chance
≥ 20 % or a level ≥ 3.20 m. Next to it, the highest 24 h warning chance of any gauge.
- **Top bar.** Chiang Mai's verdict from P.1, in the classes of the gauge status:
flooding (over the banks) at ≥ 4.20 m; high water at ≥ 3.70 m; "flooding likely" at
a 24 h danger chance ≥ 50 %, "high water likely" at a warning chance ≥ 70 %;
"watch" at a warning chance ≥ 20 % or a level ≥ 3.20 m. Next to it, the highest
24 h warning chance of any gauge.
- **Gauge list and map.** A gauge is "watch" from a 24 h warning chance of 25 %.
- **Station panel.** Per horizon (6/12/24 h) the predicted peak and the warning and
danger chances, the model version and when it was trained, or "Simple estimate" when
the row came from the heuristic fallback. For P.1 the chance of reaching each of the
seven inundation stages. The history chart overlays the 24 h peaks as they were
five city flood stages. The history chart overlays the 24 h peaks as they were
issued (`/api/forecast/history`), and "How accurate is the forecast?" loads
`/api/forecast/skill`.
- **Replay.** "Replay the October 2024 flood" plays `src/static/flood-2024-all.json`:
+2 -1
View File
@@ -26,7 +26,8 @@ seventy-two. In a quiet season a subscriber hears nothing.
Station slugs are the code lowercased without the dot: `p1`, `p103`, `p67`.
Thresholds are the ones in `src/ml/features.py` (`THRESHOLDS`): P.1 3.70 /
4.20 m, P.103 5.95 / 6.75 m, and so on.
4.20 m (half a metre below the banks / over the banks; the city floods in stages
from 4.30 m), P.103 5.95 / 6.75 m, and so on.
The outlook topic is opt-in for a reason: it is model output, and the message
says so. Observed-crossing topics only ever report a gauge reading.