{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "71143187",
   "metadata": {
    "id": "71143187"
   },
   "source": "# 🌊 TR-Flood Engine v1.0 — Türkiye Kuantum-Destekli Taşkın Simülasyon Motoru\n**BVK Technology · İTÜ ARI Teknokent · Eylül 2026**\n **Q-Flood / MQFSE** motorunun **Türkiye ülke paketi**. Aynı mimari (veri → arazi → hidroloji → 2B taşma → kuantum → Monte Carlo → etki → rapor), yalnızca **Türkiye'ye özel kamu ve açık veri kaynaklarıyla** uçtan uca çalışır.\n\n| Katman | Türkiye kaynağı | Erişim |\n|---|---|---|\n| Gözlem / uyarı | **MGM** `servis.mgm.gov.tr` — anlık AWOS, son 7 gün 24 s yağış (~1.700 istasyon), **MeteoUyarı** sel uyarıları, 5 gün tahmin | anahtarsız (Origin başlığı) |\n| Yağış (geçmiş/tahmin) | **Open-Meteo** ERA5/ERA5-Land arşivi, çok-modelli tahmin (ICON/GFS/ECMWF) | anahtarsız |\n| Yağış kontrol | **CHIRPS v2.0** 0,05° günlük · İBB İSKİ günlük yağış | anahtarsız |\n| Nehir debisi | **GloFAS v4** (Open-Meteo Flood API) · Copernicus EWDS (GloFAS/EFAS-geçmiş) · Google Flood Forecasting API | anahtarsız / jeton / bekleme listesi |\n| Yükseklik | **Copernicus GLO-30 DEM** (AWS) → dolgu, D8, birikim, dere ağı, **HAND** | anahtarsız |\n| Arazi örtüsü | **ESA WorldCover 10 m** (2021) → CN, Manning n, sızma | anahtarsız |\n| Nüfus | **WorldPop TUR 2025** 100 m (R2024B) | anahtarsız |\n| İdari sınır | **geoBoundaries TUR ADM1/ADM2** (ODbL) | anahtarsız |\n| Toprak | **ISRIC SoilGrids** → hidrolojik toprak grubu | anahtarsız |\n| Doğrulama | **CEMS Küresel Taşkın İzleme (GFM)** Sentinel-1 taşkın yayılımı (2015→) | anahtarsız |\n| Kuantum | PennyLane VQC (simülatör) · IBM Quantum · Origin Wukong · D-Wave (QUBO) | hesap/jeton |\n\n**Modlar:** `historical` (referans olay yeniden üretimi) · `forecast` (5 gün) · `nowcast` (son 72 s + 24 s).\n**Kapsam:** referans olay · 81 il · 25 havza · tüm Türkiye (tarama katmanı) · serbest bbox.\n\n**Referans olay çifti :** 🏞️ *Kastamonu Bozkurt – Ezine Çayı, 10–12 Ağustos 2021* (nehir/ani taşkın, 451,7 mm/3 gün) ↔ 🏙️ *İstanbul Başakşehir–Küçükçekmece, 5 Eylül 2023* (kentsel-plüvyal, 125 mm/3 saat).\n\n> ⚠️ Bu motor bir **tarama/erken uyarı** aracıdır; HEC-RAS 2D / LISFLOOD-FP sınıfı hidrodinamik modelin ve DSİ gözlem verisiyle kalibrasyonun yerini tutmaz. Hasar ve sigorta rakamları kalibre edilmeden karar amaçlı kullanılmamalıdır.\n"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c9f5da5c",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "c9f5da5c",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695577177,
     "user_tz": -180,
     "elapsed": 69465,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "2ca11821-4cd8-4eba-db32-9cca21928159"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Kurulum tamam · rasterio 1.5.1 · pennylane 0.45.1\n"
     ]
    }
   ],
   "source": "#@title 1 · Kurulum (≈1–2 dk) { display-mode: \"form\" }\n#@markdown Gerekli paketler kurulur. Colab'da rasterio, pennylane, python-docx ve isteğe bağlı istemciler.\nimport subprocess, sys, importlib\ndef _pip(*pkgs):\n    subprocess.run([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", *pkgs], check=False)\nneed = []\nfor mod, pkg in [(\"rasterio\",\"rasterio\"), (\"pennylane\",\"pennylane\"), (\"docx\",\"python-docx\"), (\"openpyxl\",\"openpyxl\"), (\"folium\",\"folium\")]:\n    try: importlib.import_module(mod)\n    except Exception: need.append(pkg)\nif need: _pip(*need)\noptional = \"cdsapi google-genai qiskit-ibm-runtime pennylane-qiskit\"  #@param {type:\"string\"}\ninstall_optional = True  #@param {type:\"boolean\"}\nif install_optional and optional.strip(): _pip(*optional.split())\nimport rasterio, pennylane, docx\nprint(\"Kurulum tamam · rasterio\", rasterio.__version__, \"· pennylane\", pennylane.__version__)\n"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e40bceee",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "e40bceee",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695583725,
     "user_tz": -180,
     "elapsed": 177,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "56083a96-2d33-4fe6-881c-4495b63879d8"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Writing trflood_engine.py\n"
     ]
    }
   ],
   "source": "%%writefile trflood_engine.py\n# -*- coding: utf-8 -*-\n\"\"\"\nTR-Flood Engine v1.0  —  Türkiye Kuantum-Destekli Taşkın Simülasyon Motoru\nBVK Technology · İTÜ ARI Teknokent · 2026\n\nMalezya Q-Flood Engine (MQFSE) mimarisinin Türkiye ülke paketi.\nYalnızca Türkiye'ye özel kamu ve açık veri kaynakları kullanılır:\n\n  MGM servis.mgm.gov.tr (gözlem, 7 gün yağış, MeteoUyarı, tahmin)\n  Open-Meteo (ERA5 arşivi, tahmin, GloFAS nehir debisi)          CHIRPS v2/v3 (UCSB)\n  Copernicus GLO-30 DEM + 30 m HAND (AWS açık veri)               ESA WorldCover 10 m\n  WorldPop TR 2025 (100 m)                                        geoBoundaries il/ilçe (ODbL)\n  HydroRIVERS / HydroBASINS                                       SoilGrids (ISRIC)\n  CEMS Küresel Taşkın İzleme (Sentinel-1 taşkın yayılımı)         İBB Açık Veri (İSKİ yağış)\n  İsteğe bağlı (ücretsiz kayıt): Copernicus CDS (ERA5-Land, GloFAS, EFAS), NASA IMERG,\n  Google Flood Forecasting API, OpenTopography.\n\nKatmanlar:  sources → terrain → hydrology → inundation → quantum → montecarlo → impact → report\nModlar:     historical | forecast | nowcast        Kapsam: il | havza | turkiye\n\"\"\"\nfrom __future__ import annotations\n\nimport gzip\nimport io\nimport json\nimport logging\nimport math\nimport os\nimport shutil\nimport time\nimport zipfile\nfrom dataclasses import dataclass, field, asdict\nfrom datetime import date, datetime, timedelta\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Tuple\n\nimport numpy as np\nimport pandas as pd\nimport requests\n\nENGINE_VERSION = \"1.0.0\"\nENGINE_NAME = \"TR-Flood Engine\"\n\nlog = logging.getLogger(\"trflood\")\nif not log.handlers:\n    _h = logging.StreamHandler()\n    _h.setFormatter(logging.Formatter(\"%(asctime)s %(levelname)s %(message)s\", \"%H:%M:%S\"))\n    log.addHandler(_h)\nlog.setLevel(logging.INFO)\n\nCACHE_DIR = Path(os.environ.get(\"TRFLOOD_CACHE\", \"trflood_cache\"))\nCACHE_DIR.mkdir(parents=True, exist_ok=True)\n\n_SESSION = requests.Session()\n_SESSION.headers.update({\"User-Agent\": f\"{ENGINE_NAME}/{ENGINE_VERSION} (BVK Technology)\"})\n\n\n# ---------------------------------------------------------------------------\n# Yardımcılar\n# ---------------------------------------------------------------------------\ndef http_get(url: str, params: dict | None = None, headers: dict | None = None,\n             timeout: int = 60, retries: int = 3, stream: bool = False) -> requests.Response:\n    \"\"\"Yeniden denemeli GET. Son hata yeniden fırlatılır.\"\"\"\n    last = None\n    for i in range(retries):\n        try:\n            r = _SESSION.get(url, params=params, headers=headers, timeout=timeout, stream=stream)\n            if r.status_code == 200:\n                return r\n            last = RuntimeError(f\"HTTP {r.status_code} {url}\" + (f\" — {r.text[:120]}\" if r.status_code == 429 else \"\"))\n            if r.status_code in (400, 401, 403, 404, 429):\n                break\n        except Exception as e:  # noqa: BLE001\n            last = e\n        time.sleep(1.5 * (i + 1))\n    raise last  # type: ignore[misc]\n\n\ndef http_json(url: str, **kw) -> Any:\n    return http_get(url, **kw).json()\n\n\ndef cached_download(url: str, filename: str | None = None, headers: dict | None = None) -> Path:\n    \"\"\"URL'yi önbelleğe indirir, yolu döndürür.\"\"\"\n    filename = filename or url.split(\"?\")[0].rstrip(\"/\").split(\"/\")[-1]\n    p = CACHE_DIR / filename\n    if p.exists() and p.stat().st_size > 0:\n        return p\n    r = http_get(url, headers=headers, stream=True, timeout=600)\n    tmp = p.with_suffix(p.suffix + \".part\")\n    with open(tmp, \"wb\") as f:\n        for chunk in r.iter_content(1 << 20):\n            f.write(chunk)\n    tmp.rename(p)\n    return p\n\n\nclass Provenance:\n    \"\"\"Her veri katmanının nereden geldiğini (gerçek kaynak / yedek / sentetik) kaydeder.\"\"\"\n\n    def __init__(self):\n        self.rows: List[dict] = []\n\n    def add(self, layer: str, source: str, status: str, detail: str = \"\", url: str = \"\"):\n        self.rows.append(dict(katman=layer, kaynak=source, durum=status, detay=detail, url=url,\n                              zaman=datetime.utcnow().isoformat(timespec=\"seconds\") + \"Z\"))\n        lvl = logging.INFO if status == \"ok\" else logging.WARNING\n        log.log(lvl, f\"[{layer}] {source}: {status} {detail}\")\n\n    def frame(self) -> pd.DataFrame:\n        return pd.DataFrame(self.rows)\n\n\ndef slugify(s: str) -> str:\n    tr = str.maketrans(\"çğıöşüÇĞİÖŞÜ \", \"cgiosuCGIOSU_\")\n    return \"\".join(ch for ch in s.translate(tr) if ch.isalnum() or ch in \"_-\").lower()\n\n\ndef bbox_from_center(lat: float, lon: float, half_deg: float) -> Tuple[float, float, float, float]:\n    \"\"\"(south, west, north, east)\"\"\"\n    return (lat - half_deg, lon - half_deg, lat + half_deg, lon + half_deg)\n\n\ndef bbox_area_km2(b: Tuple[float, float, float, float]) -> float:\n    s, w, n, e = b\n    return abs(n - s) * 111.0 * abs(e - w) * 111.0 * math.cos(math.radians((n + s) / 2))\n\n\n# ---------------------------------------------------------------------------\n# Kayıt defterleri: 81 il, 25 havza, referans taşkın olayları\n# ---------------------------------------------------------------------------\n# plaka: (il adı, enlem, boylam) — il merkezi yaklaşık koordinatı. Kesin sınırlar\n# çalışma zamanında geoBoundaries (ODbL) ADM1 poligonlarından alınır.\nPROVINCES: Dict[int, Tuple[str, float, float]] = {\n    1: (\"Adana\", 37.00, 35.32), 2: (\"Adıyaman\", 37.76, 38.28), 3: (\"Afyonkarahisar\", 38.76, 30.54),\n    4: (\"Ağrı\", 39.72, 43.05), 5: (\"Amasya\", 40.65, 35.83), 6: (\"Ankara\", 39.93, 32.86),\n    7: (\"Antalya\", 36.90, 30.70), 8: (\"Artvin\", 41.18, 41.82), 9: (\"Aydın\", 37.85, 27.85),\n    10: (\"Balıkesir\", 39.65, 27.89), 11: (\"Bilecik\", 40.14, 29.98), 12: (\"Bingöl\", 38.88, 40.50),\n    13: (\"Bitlis\", 38.40, 42.11), 14: (\"Bolu\", 40.74, 31.61), 15: (\"Burdur\", 37.72, 30.29),\n    16: (\"Bursa\", 40.19, 29.06), 17: (\"Çanakkale\", 40.15, 26.41), 18: (\"Çankırı\", 40.60, 33.62),\n    19: (\"Çorum\", 40.55, 34.95), 20: (\"Denizli\", 37.78, 29.09), 21: (\"Diyarbakır\", 37.91, 40.24),\n    22: (\"Edirne\", 41.68, 26.56), 23: (\"Elazığ\", 38.68, 39.22), 24: (\"Erzincan\", 39.75, 39.49),\n    25: (\"Erzurum\", 39.90, 41.27), 26: (\"Eskişehir\", 39.78, 30.52), 27: (\"Gaziantep\", 37.07, 37.38),\n    28: (\"Giresun\", 40.91, 38.39), 29: (\"Gümüşhane\", 40.46, 39.48), 30: (\"Hakkari\", 37.58, 43.74),\n    31: (\"Hatay\", 36.20, 36.16), 32: (\"Isparta\", 37.76, 30.55), 33: (\"Mersin\", 36.81, 34.64),\n    34: (\"İstanbul\", 41.01, 28.98), 35: (\"İzmir\", 38.42, 27.14), 36: (\"Kars\", 40.60, 43.10),\n    37: (\"Kastamonu\", 41.38, 33.78), 38: (\"Kayseri\", 38.72, 35.49), 39: (\"Kırklareli\", 41.73, 27.22),\n    40: (\"Kırşehir\", 39.15, 34.16), 41: (\"Kocaeli\", 40.77, 29.92), 42: (\"Konya\", 37.87, 32.49),\n    43: (\"Kütahya\", 39.42, 29.98), 44: (\"Malatya\", 38.35, 38.31), 45: (\"Manisa\", 38.61, 27.43),\n    46: (\"Kahramanmaraş\", 37.58, 36.93), 47: (\"Mardin\", 37.31, 40.74), 48: (\"Muğla\", 37.22, 28.36),\n    49: (\"Muş\", 38.73, 41.49), 50: (\"Nevşehir\", 38.62, 34.71), 51: (\"Niğde\", 37.97, 34.68),\n    52: (\"Ordu\", 40.98, 37.88), 53: (\"Rize\", 41.02, 40.52), 54: (\"Sakarya\", 40.77, 30.40),\n    55: (\"Samsun\", 41.29, 36.33), 56: (\"Siirt\", 37.93, 41.94), 57: (\"Sinop\", 42.03, 35.15),\n    58: (\"Sivas\", 39.75, 37.02), 59: (\"Tekirdağ\", 40.98, 27.51), 60: (\"Tokat\", 40.31, 36.55),\n    61: (\"Trabzon\", 41.00, 39.72), 62: (\"Tunceli\", 39.11, 39.55), 63: (\"Şanlıurfa\", 37.17, 38.79),\n    64: (\"Uşak\", 38.68, 29.41), 65: (\"Van\", 38.49, 43.38), 66: (\"Yozgat\", 39.82, 34.81),\n    67: (\"Zonguldak\", 41.45, 31.79), 68: (\"Aksaray\", 38.37, 34.03), 69: (\"Bayburt\", 40.26, 40.23),\n    70: (\"Karaman\", 37.18, 33.22), 71: (\"Kırıkkale\", 39.85, 33.51), 72: (\"Batman\", 37.88, 41.13),\n    73: (\"Şırnak\", 37.52, 42.46), 74: (\"Bartın\", 41.64, 32.34), 75: (\"Ardahan\", 41.11, 42.70),\n    76: (\"Iğdır\", 39.92, 44.04), 77: (\"Yalova\", 40.65, 29.27), 78: (\"Karabük\", 41.20, 32.63),\n    79: (\"Kilis\", 36.72, 37.12), 80: (\"Osmaniye\", 37.07, 36.25), 81: (\"Düzce\", 40.84, 31.16),\n}\nPROVINCE_BY_NAME: Dict[str, int] = {slugify(v[0]): k for k, v in PROVINCES.items()}\n\n# SYGM 25 havza — yaklaşık kapsayan kutu (south, west, north, east). Kesin sınır için\n# HydroBASINS (lev05/06) ile kesiştirme çalışma zamanında yapılabilir.\nBASINS: Dict[str, Tuple[float, float, float, float]] = {\n    \"Meriç-Ergene\": (40.55, 26.05, 42.10, 28.05), \"Marmara\": (40.00, 26.20, 41.60, 30.50),\n    \"Susurluk\": (39.10, 27.30, 40.60, 29.60), \"Kuzey Ege\": (38.90, 26.10, 40.10, 27.90),\n    \"Gediz\": (38.20, 26.60, 39.30, 29.20), \"Küçük Menderes\": (37.90, 26.80, 38.50, 28.30),\n    \"Büyük Menderes\": (37.30, 27.20, 38.60, 30.30), \"Batı Akdeniz\": (36.20, 27.90, 37.60, 30.10),\n    \"Antalya\": (36.30, 29.80, 37.90, 32.20), \"Burdur\": (37.30, 29.80, 38.00, 30.60),\n    \"Akarçay\": (38.40, 30.20, 39.10, 31.40), \"Sakarya\": (38.90, 29.70, 41.20, 33.00),\n    \"Batı Karadeniz\": (40.60, 31.00, 42.10, 35.20), \"Yeşilırmak\": (39.60, 34.70, 41.40, 38.20),\n    \"Kızılırmak\": (38.40, 32.50, 41.80, 38.30), \"Konya Kapalı\": (36.90, 31.60, 39.30, 34.90),\n    \"Doğu Akdeniz\": (36.00, 32.10, 37.60, 35.00), \"Seyhan\": (36.60, 34.80, 39.20, 36.60),\n    \"Asi\": (35.85, 35.80, 36.90, 36.70), \"Ceyhan\": (36.50, 35.50, 38.50, 37.60),\n    \"Fırat-Dicle\": (36.60, 36.30, 40.40, 44.80), \"Doğu Karadeniz\": (40.30, 36.80, 41.60, 41.60),\n    \"Çoruh\": (40.20, 39.80, 41.60, 42.10), \"Aras\": (39.20, 41.50, 41.40, 44.80),\n    \"Van Gölü\": (38.00, 42.20, 39.30, 44.30),\n}\n\n# Referans taşkın olayları — MGM Yıllık İklim Değerlendirmesi raporları, İstanbul Valiliği,\n# NHESS 2022, Su Kaynakları Dergisi, AFAD/TRT/Milliyet haberleri (Eylül 2026 araştırması).\nEVENTS: Dict[str, dict] = {\n    \"bozkurt_2021\": dict(\n        ad=\"Kastamonu Bozkurt – Ezine Çayı Taşkını\", il=\"Kastamonu\", ilce=\"Bozkurt\",\n        havza=\"Batı Karadeniz\", tip=\"riverine_flash\", baslangic=\"2021-08-10\", bitis=\"2021-08-12\",\n        lat=41.875, lon=33.975, half_deg=0.15,\n        yagis_mm=451.7, yagis_sure_saat=72, tepe_saat_utc=\"2021-08-11T11:00\", yagis_kaynak=\"MGM 2021 Yıllık İklim Raporu (Bozkurt/Mamatlar, 3 gün)\",\n        kayip=\"71 can kaybı Kastamonu + 10 Sinop (MGM); 82 (NHESS 2022)\",\n        gfm_kontrol=True, notlar=\"Sentinel-1A 11 Ağu / S1B 12 Ağu 2021 sahneleri CDSE'de; CEMS GFM taşkın yayılımı arşivde\"),\n    \"istanbul_2023\": dict(\n        ad=\"İstanbul Başakşehir–Küçükçekmece Kentsel Taşkını\", il=\"İstanbul\", ilce=\"Başakşehir\",\n        havza=\"Marmara\", tip=\"urban_pluvial\", baslangic=\"2023-09-05\", bitis=\"2023-09-05\",\n        lat=41.055, lon=28.780, half_deg=0.09,\n        yagis_mm=125.0, yagis_sure_saat=3, tepe_saat_utc=\"2023-09-05T17:00\", yagis_kaynak=\"İstanbul Valiliği basın açıklaması 2023/72 (18:30–21:30 yerel)\",\n        kayip=\"2 can kaybı, 12 yaralı, 1.754 konut/iş yeri (Valilik)\",\n        gfm_kontrol=False, notlar=\"Arnavutköy 128 mm, yerel 150 mm'ye kadar\"),\n    \"sanliurfa_2023\": dict(\n        ad=\"Şanlıurfa–Adıyaman Taşkını\", il=\"Şanlıurfa\", ilce=\"Haliliye\",\n        havza=\"Fırat-Dicle\", tip=\"flash_mixed\", baslangic=\"2023-03-14\", bitis=\"2023-03-15\",\n        lat=37.16, lon=38.80, half_deg=0.15,\n        yagis_mm=119.0, yagis_sure_saat=24, yagis_kaynak=\"MGM 2023 Yıllık İklim Raporu (günlük rekor, önceki 90,5 mm)\",\n        kayip=\"21 can kaybı (17 Şanlıurfa / 4 Adıyaman)\", gfm_kontrol=True, notlar=\"Deprem sonrası konteyner kentler etkilendi\"),\n    \"giresun_dereli_2020\": dict(\n        ad=\"Giresun Dereli Taşkını\", il=\"Giresun\", ilce=\"Dereli\", havza=\"Doğu Karadeniz\",\n        tip=\"riverine_flash\", baslangic=\"2020-08-22\", bitis=\"2020-08-22\", lat=40.74, lon=38.45, half_deg=0.15,\n        yagis_mm=137.6, yagis_sure_saat=24, yagis_kaynak=\"Su Kaynakları Dergisi (Yağlıdere Sınırköy, 133,1 mm/8 saat)\",\n        kayip=\"11 can kaybı + 4 kayıp\", gfm_kontrol=True, notlar=\"~12 saatlik konvektif yağış, 48 yıl tekerrür\"),\n    \"rize_2021\": dict(\n        ad=\"Rize Güneysu–Çayeli Taşkını\", il=\"Rize\", ilce=\"Güneysu\", havza=\"Doğu Karadeniz\",\n        tip=\"riverine_flash\", baslangic=\"2021-07-14\", bitis=\"2021-07-15\", lat=40.98, lon=40.60, half_deg=0.15,\n        yagis_mm=213.0, yagis_sure_saat=24, yagis_kaynak=\"TRT Haber (Güneysu 213 kg/m²)\",\n        kayip=\"6 can kaybı, 2 kayıp, 87 konut\", gfm_kontrol=True, notlar=\"\"),\n    \"rize_2025\": dict(\n        ad=\"Rize Ardeşen–İkizdere Taşkını\", il=\"Rize\", ilce=\"Ardeşen\", havza=\"Doğu Karadeniz\",\n        tip=\"riverine_flash\", baslangic=\"2025-09-20\", bitis=\"2025-09-21\", lat=41.05, lon=40.95, half_deg=0.18,\n        yagis_mm=161.8, yagis_sure_saat=24, yagis_kaynak=\"AFAD (İkizdere Çağrankaya)\", kayip=\"Can kaybı yok, 2 köprü yıkıldı\",\n        gfm_kontrol=True, notlar=\"MGM turuncu uyarı\"),\n    \"izmir_2021\": dict(\n        ad=\"İzmir Kemalpaşa–Bornova Taşkını\", il=\"İzmir\", ilce=\"Bornova\", havza=\"Gediz\",\n        tip=\"urban_pluvial\", baslangic=\"2021-02-02\", bitis=\"2021-02-02\", lat=38.44, lon=27.22, half_deg=0.12,\n        yagis_mm=None, yagis_sure_saat=12, yagis_kaynak=\"Doğrulanamadı — Open-Meteo/ERA5'ten türetilir\",\n        kayip=\"2 can kaybı\", gfm_kontrol=False, notlar=\"Kıyı kabarması ile birleşik\"),\n    \"izmir_2026\": dict(\n        ad=\"İzmir Buca–Konak Kentsel Taşkını\", il=\"İzmir\", ilce=\"Buca\", havza=\"Küçük Menderes\",\n        tip=\"urban_pluvial\", baslangic=\"2026-01-29\", bitis=\"2026-01-29\", lat=38.39, lon=27.17, half_deg=0.10,\n        yagis_mm=80.0, yagis_sure_saat=6, yagis_kaynak=\"İlkses (Buca 80 kg/m², Konak 63)\", kayip=\"963 su baskını ihbarı\",\n        gfm_kontrol=False, notlar=\"\"),\n    \"antalya_manavgat_2024\": dict(\n        ad=\"Antalya Manavgat Taşkını\", il=\"Antalya\", ilce=\"Manavgat\", havza=\"Antalya\",\n        tip=\"flash_mixed\", baslangic=\"2024-12-21\", bitis=\"2024-12-21\", lat=36.79, lon=31.44, half_deg=0.15,\n        yagis_mm=106.6, yagis_sure_saat=2, yagis_kaynak=\"Milliyet (2 saatte 106,6 kg/m²)\", kayip=\"2 yaralı, 236 kurtarma\",\n        gfm_kontrol=True, notlar=\"\"),\n    \"ankara_mamak_2018\": dict(\n        ad=\"Ankara Mamak Kentsel Taşkını\", il=\"Ankara\", ilce=\"Mamak\", havza=\"Sakarya\",\n        tip=\"urban_pluvial\", baslangic=\"2018-05-05\", bitis=\"2018-05-06\", lat=39.92, lon=32.92, half_deg=0.08,\n        yagis_mm=16.0, yagis_sure_saat=0.33, yagis_kaynak=\"Sabah (20 dakikada 16 kg/m²)\", kayip=\"6 yaralı, 100–150 araç\",\n        gfm_kontrol=False, notlar=\"\"),\n    \"hatay_samandag_2026\": dict(\n        ad=\"Hatay Samandağ Taşkını\", il=\"Hatay\", ilce=\"Samandağ\", havza=\"Asi\",\n        tip=\"riverine_flash\", baslangic=\"2026-05-21\", bitis=\"2026-05-23\", lat=36.09, lon=35.98, half_deg=0.14,\n        yagis_mm=None, yagis_sure_saat=48, yagis_kaynak=\"Doğrulanamadı — Open-Meteo/ERA5'ten türetilir\",\n        kayip=\"4 can kaybı, 1 kayıp, 1.600+ ihbar\", gfm_kontrol=True, notlar=\"\"),\n    \"rize_2026\": dict(\n        ad=\"Rize İyidere–Pazar Taşkını\", il=\"Rize\", ilce=\"İyidere\", havza=\"Doğu Karadeniz\",\n        tip=\"riverine_flash\", baslangic=\"2026-09-19\", bitis=\"2026-09-19\", lat=41.02, lon=40.35, half_deg=0.15,\n        yagis_mm=200.0, yagis_sure_saat=24, yagis_kaynak=\"Star/Yeni Şafak (200 kg/m²'ye kadar)\", kayip=\"1,04–1,42 milyar TL hasar\",\n        gfm_kontrol=True, notlar=\"\"),\n}\n\nDEFAULT_POC_PAIR = (\"bozkurt_2021\", \"istanbul_2023\")\n\n\n# ---------------------------------------------------------------------------\n# Çalıştırma yapılandırması\n# ---------------------------------------------------------------------------\n@dataclass\nclass RunConfig:\n    # Kapsam ve mod\n    mode: str = \"historical\"            # historical | forecast | nowcast\n    scope: str = \"event\"                # event | il | havza | turkiye | bbox\n    event_key: str = \"bozkurt_2021\"     # scope=event ise\n    il: str = \"Kastamonu\"               # scope=il ise\n    havza: str = \"Batı Karadeniz\"       # scope=havza ise\n    bbox: Optional[Tuple[float, float, float, float]] = None  # (S, W, N, E) scope=bbox\n    half_deg: float = 0.15              # il/tur. modunda merkez etrafı yarı genişlik\n    start: Optional[str] = None         # historical: olay başlangıcı; None ise olaydan\n    end: Optional[str] = None\n    forecast_days: int = 5\n    nowcast_hours: int = 12\n    run_frequency: str = \"daily\"        # hourly | daily | weekly (zamanlayıcı notu + pencere)\n    flood_type: str = \"auto\"            # auto | riverine | pluvial | both\n\n    # Çözünürlük / hesap bütçesi\n    grid_max: int = 300                 # DEM ızgarası en fazla NxN (yeniden örneklenir)\n    pluvial_grid_max: int = 300\n    mc_runs: int = 24\n    mc_grid_max: int = 120\n\n    # Kuantum\n    quantum_backend: str = \"default.qubit\"   # default.qubit | lightning.qubit | ibm | origin | none\n    n_qubits: int = 6\n    qml_epochs: int = 60\n    qml_layers: int = 3\n    qubo_solver: str = \"anneal\"              # anneal | dwave | none\n\n    # LLM anlatı\n    llm_provider: str = \"template\"           # template | gemini\n    gemini_model: str = \"gemini-2.5-flash\"\n\n    # Çıktı\n    out_dir: str = \"trflood_out\"\n    report_lang: str = \"tr\"                  # tr | en | both\n    seed: int = 42\n\n    # Etki parametreleri (kalibrasyon gerekli)\n    residential_max_damage_try_m2: float = 9000.0     # 2026 TL/m² (yaklaşık; Huizinga 2017 ölçek)\n    commercial_max_damage_try_m2: float = 14000.0\n    insurance_penetration: float = 0.12               # özel taşkın poliçesi tahmini oranı (DASK taşkını kapsamaz)\n    persons_per_building: float = 3.2\n    sewer_capacity_mm_h: float = 10.0\n    exposure_depth_m: float = 0.3                      # nüfus/yapı maruziyeti için derinlik eşiği                  # yapılaşmış hücrelerde yağmur suyu şebekesi kapasitesi (kalibrasyon gerekli)\n\n    def resolve(self) -> \"RunConfig\":\n        \"\"\"Kapsamdan bbox ve tarih penceresini türetir (yerinde günceller).\"\"\"\n        if self.scope == \"event\":\n            ev = EVENTS[self.event_key]\n            self.il = ev[\"il\"]\n            self.havza = ev[\"havza\"]\n            self.bbox = self.bbox or bbox_from_center(ev[\"lat\"], ev[\"lon\"], ev[\"half_deg\"])\n            if self.mode == \"historical\":\n                self.start = self.start or ev[\"baslangic\"]\n                self.end = self.end or ev[\"bitis\"]\n            if self.flood_type == \"auto\":\n                self.flood_type = \"pluvial\" if ev[\"tip\"] == \"urban_pluvial\" else (\"both\" if ev[\"tip\"] == \"flash_mixed\" else \"riverine\")\n        elif self.scope == \"il\":\n            code = PROVINCE_BY_NAME[slugify(self.il)]\n            _, lat, lon = PROVINCES[code]\n            self.bbox = self.bbox or bbox_from_center(lat, lon, self.half_deg)\n        elif self.scope == \"havza\":\n            self.bbox = self.bbox or BASINS[self.havza]\n        elif self.scope == \"turkiye\":\n            self.bbox = self.bbox or (35.8, 25.6, 42.2, 44.9)\n        elif self.scope == \"bbox\":\n            assert self.bbox is not None, \"scope=bbox için bbox verin\"\n        if self.flood_type == \"auto\":\n            self.flood_type = \"both\"\n        today = date.today()\n        if self.mode == \"forecast\":\n            self.start = today.isoformat()\n            self.end = (today + timedelta(days=self.forecast_days)).isoformat()\n        elif self.mode == \"nowcast\":\n            self.start = (today - timedelta(days=3)).isoformat()\n            self.end = (today + timedelta(days=1)).isoformat()\n        elif self.mode == \"historical\" and not self.start:\n            self.start = (today - timedelta(days=10)).isoformat()\n            self.end = (today - timedelta(days=7)).isoformat()\n        return self\n\n    @property\n    def center(self) -> Tuple[float, float]:\n        s, w, n, e = self.bbox  # type: ignore[misc]\n        return ((s + n) / 2, (w + e) / 2)\n\n    def to_json(self) -> str:\n        return json.dumps(asdict(self), ensure_ascii=False, indent=2, default=str)\n\n# ===========================================================================\n# 1. VERİ BAĞLAYICILARI (Türkiye kamu + açık veri)\n# ===========================================================================\nMGM_ORIGIN = {\"Origin\": \"https://www.mgm.gov.tr\", \"Referer\": \"https://www.mgm.gov.tr/\"}\n\n\nclass MGMClient:\n    \"\"\"servis.mgm.gov.tr — mgm.gov.tr ön yüzünün kullandığı JSON uçları (resmî değil, anahtarsız).\n    Zorunlu: Origin başlığı. Yağış toplamları yalnızca son 7 gün için sunulur.\"\"\"\n    BASE = \"https://servis.mgm.gov.tr/web\"\n\n    def _get(self, path: str, **params):\n        return http_json(f\"{self.BASE}/{path}\", params=params or None, headers=MGM_ORIGIN, timeout=40)\n\n    def iller(self) -> pd.DataFrame:\n        return pd.DataFrame(self._get(\"merkezler/iller\"))\n\n    def ilceler(self, il: str) -> pd.DataFrame:\n        return pd.DataFrame(self._get(\"merkezler/ililcesi\", il=il))\n\n    def merkez_lokasyon(self, lat: float, lon: float) -> dict:\n        return self._get(\"merkezler/lokasyon\", enlem=lat, boylam=lon)\n\n    def sondurum(self, merkez_id: int) -> dict:\n        j = self._get(\"sondurumlar\", merkezid=merkez_id)\n        return j[0] if j else {}\n\n    def toplam_yagis(self, tarih: str) -> pd.DataFrame:\n        \"\"\"~1.700 AWOS istasyonu için 24 saatlik (06Z–06Z) yağış toplamı; son 7 gün.\"\"\"\n        df = pd.DataFrame(self._get(\"sondurumlar/toplamyagis\", tarih=tarih))\n        if not df.empty:\n            df = df.rename(columns={\"deger\": \"yagis_mm\", \"enlem\": \"lat\", \"boylam\": \"lon\"})\n        return df\n\n    def toplam_yagis_bbox(self, tarih: str, bbox) -> pd.DataFrame:\n        df = self.toplam_yagis(tarih)\n        s, w, n, e = bbox\n        if df.empty:\n            return df\n        return df[(df.lat >= s) & (df.lat <= n) & (df.lon >= w) & (df.lon <= e)].copy()\n\n    def meteoalarm(self, gun: str = \"today\") -> List[dict]:\n        return self._get(f\"meteoalarm/{gun}\")\n\n    def alarmlar(self) -> List[dict]:\n        return self._get(\"alarmlar\")\n\n    def tahmin_saatlik(self, ist_no: int) -> pd.DataFrame:\n        j = self._get(\"tahminler/saatlik\", istno=ist_no)\n        return pd.DataFrame(j[0][\"tahmin\"]) if j else pd.DataFrame()\n\n    def tahmin_gunluk(self, ist_no: int) -> dict:\n        j = self._get(\"tahminler/gunluk\", istno=ist_no)\n        return j[0] if j else {}\n\n    def uyari_seviyesi(self, merkez_ids: List[int]) -> Tuple[str, str]:\n        \"\"\"Verilen ilçe merkezId'leri için bugünkü MeteoUyarı seviyesi (red>orange>yellow>none) ve metin.\"\"\"\n        try:\n            alarms = self.meteoalarm(\"today\")\n        except Exception as e:  # noqa: BLE001\n            log.warning(f\"MeteoUyarı alınamadı: {e}\")\n            return \"unknown\", \"\"\n        best, text = \"none\", \"\"\n        order = {\"none\": 0, \"yellow\": 1, \"orange\": 2, \"red\": 3}\n        for a in alarms:\n            towns = a.get(\"towns\", {})\n            for lvl in (\"red\", \"orange\", \"yellow\"):\n                if set(towns.get(lvl, [])) & set(merkez_ids) and order[lvl] > order[best]:\n                    best, text = lvl, (a.get(\"text\", {}) or {}).get(lvl, \"\")\n        return best, text\n\n\nclass OpenMeteoClient:\n    \"\"\"Open-Meteo: ERA5/ERA5-Land arşivi, çok modelli tahmin ve GloFAS v4 nehir debisi. Anahtarsız,\n    ticari olmayan kullanımda 10.000 çağrı/gün.\"\"\"\n    ARCHIVE = \"https://archive-api.open-meteo.com/v1/archive\"\n    FORECAST = \"https://api.open-meteo.com/v1/forecast\"\n    FLOOD = \"https://flood-api.open-meteo.com/v1/flood\"\n\n    def archive_hourly(self, lat, lon, start, end,\n                       variables=(\"precipitation\", \"temperature_2m\", \"soil_moisture_0_to_7cm\")) -> pd.DataFrame:\n        j = http_json(self.ARCHIVE, params=dict(latitude=lat, longitude=lon, start_date=start, end_date=end,\n                                                hourly=\",\".join(variables), timezone=\"UTC\"))\n        df = pd.DataFrame(j[\"hourly\"])\n        df[\"time\"] = pd.to_datetime(df[\"time\"], utc=True)\n        return df.set_index(\"time\")\n\n    def archive_daily(self, lat, lon, start, end) -> pd.DataFrame:\n        j = http_json(self.ARCHIVE, params=dict(latitude=lat, longitude=lon, start_date=start, end_date=end,\n                                                daily=\"precipitation_sum,temperature_2m_mean,et0_fao_evapotranspiration\",\n                                                timezone=\"UTC\"))\n        df = pd.DataFrame(j[\"daily\"])\n        df[\"time\"] = pd.to_datetime(df[\"time\"], utc=True)\n        return df.set_index(\"time\")\n\n    def forecast_hourly(self, lat, lon, days=5, past_days=2, models=\"best_match\") -> pd.DataFrame:\n        j = http_json(self.FORECAST, params=dict(latitude=lat, longitude=lon, forecast_days=days, past_days=past_days,\n                                                 hourly=\"precipitation,precipitation_probability,temperature_2m,soil_moisture_0_to_1cm\",\n                                                 models=models, timezone=\"UTC\"))\n        df = pd.DataFrame(j[\"hourly\"])\n        df[\"time\"] = pd.to_datetime(df[\"time\"], utc=True)\n        return df.set_index(\"time\")\n\n    def flood_daily(self, lat, lon, start=None, end=None, past_days=None, forecast_days=None,\n                    ensemble=False, model=\"seamless_v4\") -> pd.DataFrame:\n        p = dict(latitude=lat, longitude=lon, models=model,\n                 daily=\"river_discharge,river_discharge_mean,river_discharge_max,river_discharge_min\")\n        if start:\n            p.update(start_date=start, end_date=end)\n        if past_days is not None:\n            p[\"past_days\"] = past_days\n        if forecast_days is not None:\n            p[\"forecast_days\"] = forecast_days\n        if ensemble:\n            p[\"ensemble\"] = \"true\"\n        j = http_json(self.FLOOD, params=p)\n        df = pd.DataFrame(j[\"daily\"])\n        df[\"time\"] = pd.to_datetime(df[\"time\"], utc=True)\n        return df.set_index(\"time\")\n\n\nclass CHIRPSClient:\n    \"\"\"CHIRPS v2.0 günlük 0,05° GeoTIFF (UCSB CHC). Son ~1 ay 'prelim', öncesi 'final'.\"\"\"\n    FINAL = \"https://data.chc.ucsb.edu/products/CHIRPS-2.0/global_daily/tifs/p05/{y}/chirps-v2.0.{y}.{m:02d}.{d:02d}.tif.gz\"\n    PRELIM = \"https://data.chc.ucsb.edu/products/CHIRPS-2.0/prelim/global_daily/tifs/p05/{y}/chirps-v2.0.{y}.{m:02d}.{d:02d}.tif\"\n\n    def daily_mean_mm(self, bbox, d: date) -> Optional[float]:\n        import rasterio\n        from rasterio.windows import from_bounds\n        s, w, n, e = bbox\n        for tpl, gz in ((self.FINAL, True), (self.PRELIM, False)):\n            url = tpl.format(y=d.year, m=d.month, d=d.day)\n            try:\n                p = cached_download(url)\n                if gz:\n                    out = p.with_suffix(\"\")\n                    if not out.exists():\n                        with gzip.open(p, \"rb\") as fi, open(out, \"wb\") as fo:\n                            shutil.copyfileobj(fi, fo)\n                    p = out\n                with rasterio.open(p) as src:\n                    win = from_bounds(w, s, e, n, src.transform)\n                    arr = src.read(1, window=win).astype(float)\n                    arr[arr < 0] = np.nan\n                    return float(np.nanmean(arr))\n            except Exception:  # noqa: BLE001\n                continue\n        return None\n\n\nclass CopernicusDEM:\n    \"\"\"Copernicus GLO-30 DEM (1\", ~30 m) ve türev 30 m HAND — AWS açık veri, anahtarsız, COG.\n    Okuma /vsicurl/ pencereleri ile yapılır; yalnızca gereken kısım indirilir.\"\"\"\n    DEM = \"https://copernicus-dem-30m.s3.amazonaws.com/Copernicus_DSM_COG_10_{lat}_00_{lon}_00_DEM/Copernicus_DSM_COG_10_{lat}_00_{lon}_00_DEM.tif\"\n    HAND = \"https://glo-30-hand.s3.amazonaws.com/v1/2021/Copernicus_DSM_COG_10_{lat}_00_{lon}_00_HAND.tif\"\n\n    @staticmethod\n    def _tiles(bbox):\n        s, w, n, e = bbox\n        out = []\n        for la in range(math.floor(s), math.ceil(n)):\n            for lo in range(math.floor(w), math.ceil(e)):\n                out.append((f\"{'N' if la >= 0 else 'S'}{abs(la):02d}\", f\"{'E' if lo >= 0 else 'W'}{abs(lo):03d}\"))\n        return out\n\n    def read(self, bbox, kind=\"DEM\", max_px=1200) -> Tuple[np.ndarray, Any]:\n        \"\"\"Returns (array, affine transform) in EPSG:4326, mosaicked & clipped to bbox.\"\"\"\n        import rasterio\n        from rasterio.merge import merge\n        s, w, n, e = bbox\n        tpl = self.DEM if kind == \"DEM\" else self.HAND\n        srcs = []\n        for la, lo in self._tiles(bbox):\n            url = tpl.format(lat=la, lon=lo)\n            try:\n                srcs.append(rasterio.open(f\"/vsicurl/{url}\"))\n            except Exception as ex:  # noqa: BLE001\n                log.warning(f\"{kind} karo açılamadı {la}{lo}: {ex}\")\n        if not srcs:\n            raise RuntimeError(f\"{kind} karosu yok\")\n        res = srcs[0].res[0]\n        # bbox'u en fazla max_px piksele sığdırmak için çözünürlük kabalaştır\n        need = max((e - w) / res, (n - s) / res)\n        factor = max(1.0, need / max_px)\n        arr, transform = merge(srcs, bounds=(w, s, e, n), res=(res * factor, res * factor), nodata=-32767.0)\n        for sd in srcs:\n            sd.close()\n        arr = arr[0].astype(\"float32\")\n        arr[arr <= -32767.0] = np.nan\n        return arr, transform\n\n\nclass WorldCoverClient:\n    \"\"\"ESA WorldCover 10 m (2021, v200) — 3°×3° COG karoları, AWS, CC BY 4.0.\"\"\"\n    URL = \"https://esa-worldcover.s3.eu-central-1.amazonaws.com/v200/2021/map/ESA_WorldCover_10m_2021_v200_{lat}{lon}_Map.tif\"\n    CLASSES = {10: \"Ağaç örtüsü\", 20: \"Çalılık\", 30: \"Otlak\", 40: \"Tarım\", 50: \"Yapılaşmış\",\n               60: \"Çıplak/seyrek\", 70: \"Kar/buz\", 80: \"Su\", 90: \"Sulak alan\", 95: \"Mangrov\", 100: \"Yosun/liken\"}\n\n    def read_to_grid(self, bbox, shape) -> np.ndarray:\n        import rasterio\n        from rasterio.merge import merge\n        from rasterio.enums import Resampling\n        s, w, n, e = bbox\n        srcs = []\n        for la in range(math.floor(s / 3) * 3, math.ceil(n / 3) * 3, 3):\n            for lo in range(math.floor(w / 3) * 3, math.ceil(e / 3) * 3, 3):\n                url = self.URL.format(lat=f\"{'N' if la >= 0 else 'S'}{abs(la):02d}\", lon=f\"{'E' if lo >= 0 else 'W'}{abs(lo):03d}\")\n                try:\n                    srcs.append(rasterio.open(f\"/vsicurl/{url}\"))\n                except Exception as ex:  # noqa: BLE001\n                    log.warning(f\"WorldCover karo yok {la},{lo}: {ex}\")\n        if not srcs:\n            raise RuntimeError(\"WorldCover karosu yok\")\n        res_y = (n - s) / shape[0]\n        res_x = (e - w) / shape[1]\n        arr, _ = merge(srcs, bounds=(w, s, e, n), res=(res_x, res_y), nodata=0, resampling=Resampling.mode)\n        for sd in srcs:\n            sd.close()\n        out = arr[0].astype(\"uint8\")\n        return _fit_shape(out, shape)\n\n\nclass WorldPopClient:\n    \"\"\"WorldPop Türkiye 2025, 100 m, kısıtlı (constrained) — R2024B v1. Piksel = kişi sayısı.\"\"\"\n    URL = \"https://data.worldpop.org/GIS/Population/Global_2015_2030/R2024B/2025/TUR/v1/100m/constrained/tur_pop_2025_CN_100m_R2024B_v1.tif\"\n    FALLBACK = \"https://data.worldpop.org/GIS/Population/Global_2000_2020_Constrained/2020/BSGM/TUR/tur_ppp_2020_constrained.tif\"\n\n    def read_to_grid(self, bbox, shape) -> np.ndarray:\n        import rasterio\n        from rasterio.windows import from_bounds\n        s, w, n, e = bbox\n        for url in (self.URL, self.FALLBACK):\n            # WorldPop sunucusu HTTP Range desteklemez → dosya (73 MB) bir kez indirilip önbellekten okunur\n            for path in (f\"/vsicurl/{url}\", None):\n                try:\n                    p = path or str(cached_download(url))\n                    with rasterio.open(p) as src:\n                        win = from_bounds(w, s, e, n, src.transform)\n                        pop = src.read(1, window=win).astype(\"float64\")\n                        nd = src.nodata\n                        if nd is not None:\n                            pop[pop == nd] = 0\n                        pop[pop < 0] = 0\n                        return _resum_to_grid(pop, shape)\n                except Exception as ex:  # noqa: BLE001\n                    log.warning(f\"WorldPop okunamadı ({'vsicurl' if path else 'indirme'}) {url.split('/')[-1]}: {str(ex)[:80]}\")\n        raise RuntimeError(\"WorldPop okunamadı\")\n\n\nclass GeoBoundariesClient:\n    \"\"\"geoBoundaries gbOpen TUR ADM1 (il) / ADM2 (ilçe) — ODbL, GitHub raw GeoJSON.\"\"\"\n    API = \"https://www.geoboundaries.org/api/current/gbOpen/TUR/{lvl}/\"\n\n    def __init__(self):\n        self._cache: Dict[str, dict] = {}\n\n    def geojson(self, lvl=\"ADM2\") -> dict:\n        if lvl in self._cache:\n            return self._cache[lvl]\n        meta = http_json(self.API.format(lvl=lvl))\n        simp = meta.get(\"simplifiedGeometryGeoJSON\") or meta[\"gjDownloadURL\"]\n        candidates = [simp, simp.replace(\"https://github.com/\", \"https://media.githubusercontent.com/media/\").replace(\"/raw/\", \"/\"),\n                      meta[\"gjDownloadURL\"], f\"https://www.geoboundaries.org/data/geoBoundaries-3_0_0/TUR/{lvl}/geoBoundaries-3_0_0-TUR-{lvl}.geojson\"]\n        gj, last = None, None\n        for url in candidates:\n            try:\n                p = cached_download(url, f\"geoBoundaries_TUR_{lvl}.geojson\")\n                with open(p, encoding=\"utf-8\") as f:\n                    head = f.read(64)\n                if head.startswith(\"version https://git-lfs\"):\n                    p.unlink(); raise RuntimeError(\"LFS işaretçisi\")\n                with open(p, encoding=\"utf-8\") as f:\n                    gj = json.load(f)\n                break\n            except Exception as ex:  # noqa: BLE001\n                last = ex\n        if gj is None:\n            raise RuntimeError(f\"geoBoundaries indirilemedi: {last}\")\n        self._cache[lvl] = gj\n        return gj\n\n    @staticmethod\n    def _bbox_of(geom) -> Tuple[float, float, float, float]:\n        xs, ys = [], []\n        polys = geom[\"coordinates\"] if geom[\"type\"] == \"MultiPolygon\" else [geom[\"coordinates\"]]\n        for poly in polys:\n            for x, y in poly[0]:\n                xs.append(x); ys.append(y)\n        return (min(ys), min(xs), max(ys), max(xs))\n\n    def features_in_bbox(self, bbox, lvl=\"ADM2\") -> List[dict]:\n        s, w, n, e = bbox\n        out = []\n        for ft in self.geojson(lvl)[\"features\"]:\n            fs, fw, fn, fe = self._bbox_of(ft[\"geometry\"])\n            if fn < s or fs > n or fe < w or fw > e:\n                continue\n            out.append(dict(name=ft[\"properties\"].get(\"shapeName\"), bbox=(fs, fw, fn, fe), geometry=ft[\"geometry\"]))\n        return out\n\n    def province_bbox(self, il: str) -> Optional[Tuple[float, float, float, float]]:\n        target = slugify(il)\n        for ft in self.geojson(\"ADM1\")[\"features\"]:\n            if slugify(ft[\"properties\"].get(\"shapeName\", \"\")) == target:\n                return self._bbox_of(ft[\"geometry\"])\n        return None\n\n\ndef rasterize_features(features: List[dict], transform, shape) -> np.ndarray:\n    \"\"\"Poligon listesini ızgaraya (int etiket) çevirir; shapely gerekmez (matplotlib.path).\"\"\"\n    from matplotlib.path import Path as MPath\n    H, W = shape\n    cols, rows = np.meshgrid(np.arange(W) + 0.5, np.arange(H) + 0.5)\n    xs = transform.c + cols * transform.a\n    ys = transform.f + rows * transform.e\n    pts = np.column_stack([xs.ravel(), ys.ravel()])\n    labels = np.zeros(H * W, dtype=np.int32)\n    for i, ft in enumerate(features, start=1):\n        geom = ft[\"geometry\"]\n        polys = geom[\"coordinates\"] if geom[\"type\"] == \"MultiPolygon\" else [geom[\"coordinates\"]]\n        for poly in polys:\n            inside = MPath(np.array(poly[0])).contains_points(pts)\n            for hole in poly[1:]:\n                inside &= ~MPath(np.array(hole)).contains_points(pts)\n            labels[inside & (labels == 0)] = i\n    return labels.reshape(H, W)\n\n\nclass SoilGridsClient:\n    \"\"\"ISRIC SoilGrids v2.0 REST — kil/kum yüzdesinden hidrolojik toprak grubu (A–D).\"\"\"\n    URL = \"https://rest.isric.org/soilgrids/v2.0/properties/query\"\n\n    def hsg(self, lat, lon) -> Tuple[str, dict]:\n        j = http_json(self.URL, params=[(\"lon\", lon), (\"lat\", lat), (\"property\", \"clay\"), (\"property\", \"sand\"),\n                                        (\"depth\", \"0-5cm\"), (\"value\", \"mean\")], timeout=25, retries=1)\n        vals = {}\n        for layer in j[\"properties\"][\"layers\"]:\n            v = layer[\"depths\"][0][\"values\"][\"mean\"]\n            vals[layer[\"name\"]] = (v / 10.0) if v is not None else None  # g/kg → %\n        clay, sand = vals.get(\"clay\") or 20, vals.get(\"sand\") or 40\n        if sand > 70:\n            g = \"A\"\n        elif clay > 40:\n            g = \"D\"\n        elif clay > 27:\n            g = \"C\"\n        else:\n            g = \"B\"\n        return g, vals\n\n\nclass GFMClient:\n    \"\"\"CEMS Küresel Taşkın İzleme (GFM) — Sentinel-1 tabanlı 20 m taşkın yayılımı, EODC STAC (2015→).\n    Geçmiş olay doğrulaması için kullanılır.\"\"\"\n    STAC = \"https://stac.eodc.eu/api/v1/search\"\n\n    def flood_extent_to_grid(self, bbox, start: str, end: str, shape) -> Optional[Tuple[np.ndarray, List[str]]]:\n        import rasterio\n        from rasterio.windows import from_bounds\n        from rasterio.enums import Resampling\n        s, w, n, e = bbox\n        body = {\"collections\": [\"GFM\"], \"bbox\": [w, s, e, n], \"datetime\": f\"{start}T00:00:00Z/{end}T23:59:59Z\", \"limit\": 50}\n        r = _SESSION.post(self.STAC, json=body, timeout=60)\n        r.raise_for_status()\n        items = r.json().get(\"features\", [])\n        if not items:\n            return None\n        acc = np.zeros(shape, dtype=\"float32\")\n        used = []\n        for it in items:\n            href = None\n            for k, a in it.get(\"assets\", {}).items():\n                if \"flood_extent\" in k.lower() or \"ensemble_flood\" in k.lower():\n                    href = a[\"href\"]; break\n            if not href:\n                continue\n            try:\n                with rasterio.open(href if href.startswith(\"/vsicurl/\") else f\"/vsicurl/{href}\") as src:\n                    from rasterio.warp import transform_bounds\n                    b = transform_bounds(\"EPSG:4326\", src.crs, w, s, e, n)\n                    win = from_bounds(*b, src.transform)\n                    arr = src.read(1, window=win, out_shape=shape, resampling=Resampling.max, boundless=True, fill_value=0)\n                    acc = np.maximum(acc, (arr == 1).astype(\"float32\"))\n                    used.append(it[\"id\"])\n            except Exception as ex:  # noqa: BLE001\n                log.warning(f\"GFM okunamadı {it['id']}: {ex}\")\n        return (acc, used) if used else None\n\n\nclass IBBOpenData:\n    \"\"\"İBB Açık Veri Portalı (CKAN) — İSKİ baraj havzalarına düşen günlük yağış (2011→2024).\"\"\"\n    API = \"https://data.ibb.gov.tr/api/3/action/package_show\"\n\n    def iski_daily_rain(self) -> Optional[pd.DataFrame]:\n        try:\n            j = http_json(self.API, params={\"id\": \"istanbul-barajlarina-dusen-gunluk-toplam-yagis-miktari\"})\n            for res in j[\"result\"][\"resources\"]:\n                if res.get(\"format\", \"\").lower() in (\"xlsx\", \"csv\"):\n                    p = cached_download(res[\"url\"], \"iski_gunluk_yagis.\" + res[\"format\"].lower())\n                    return pd.read_excel(p) if p.suffix == \".xlsx\" else pd.read_csv(p)\n        except Exception as ex:  # noqa: BLE001\n            log.warning(f\"İBB açık veri alınamadı: {ex}\")\n        return None\n\n\nclass GoogleFloodClient:\n    \"\"\"Google Flood Forecasting API (bekleme listesi + API anahtarı; GOOGLE_FLOOD_API_KEY ortam değişkeni).\"\"\"\n    BASE = \"https://floodforecasting.googleapis.com/v1\"\n\n    def __init__(self):\n        self.key = os.environ.get(\"GOOGLE_FLOOD_API_KEY\")\n\n    def gauges_in_bbox(self, bbox) -> List[dict]:\n        if not self.key:\n            return []\n        r = _SESSION.post(f\"{self.BASE}/gauges:searchGaugesByArea\", params={\"key\": self.key},\n                          json={\"regionCode\": \"TR\"}, timeout=60)\n        r.raise_for_status()\n        s, w, n, e = bbox\n        out = []\n        for g in r.json().get(\"gauges\", []):\n            loc = g.get(\"location\", {})\n            if s <= loc.get(\"latitude\", -99) <= n and w <= loc.get(\"longitude\", -999) <= e:\n                out.append(g)\n        return out\n\n\nclass CDSClient:\n    \"\"\"Copernicus CDS/EWDS (ücretsiz jeton: ~/.cdsapirc). ERA5-Land saatlik yağış, GloFAS, EFAS-geçmiş.\"\"\"\n\n    def available(self) -> bool:\n        try:\n            import cdsapi  # noqa: F401\n            return Path.home().joinpath(\".cdsapirc\").exists() or bool(os.environ.get(\"CDSAPI_KEY\"))\n        except Exception:  # noqa: BLE001\n            return False\n\n    def era5_land_precip(self, bbox, start: str, end: str) -> Optional[Path]:\n        if not self.available():\n            return None\n        import cdsapi\n        s, w, n, e = bbox\n        d0, d1 = pd.Timestamp(start), pd.Timestamp(end)\n        target = CACHE_DIR / f\"era5land_{start}_{end}.nc\"\n        if target.exists():\n            return target\n        c = cdsapi.Client()\n        c.retrieve(\"reanalysis-era5-land\", {\n            \"variable\": [\"total_precipitation\"], \"year\": sorted({str(y) for y in range(d0.year, d1.year + 1)}),\n            \"month\": sorted({f\"{m:02d}\" for m in pd.date_range(d0, d1).month}),\n            \"day\": sorted({f\"{d:02d}\" for d in pd.date_range(d0, d1).day}),\n            \"time\": [f\"{h:02d}:00\" for h in range(24)], \"area\": [n, w, s, e],\n            \"data_format\": \"netcdf\", \"download_format\": \"unarchived\"}, str(target))\n        return target\n\n\n# ---- ızgara yardımcıları ----------------------------------------------------\ndef _fit_shape(a: np.ndarray, shape) -> np.ndarray:\n    H, W = shape\n    if a.shape == (H, W):\n        return a\n    ri = np.clip((np.arange(H) * a.shape[0] / H).astype(int), 0, a.shape[0] - 1)\n    ci = np.clip((np.arange(W) * a.shape[1] / W).astype(int), 0, a.shape[1] - 1)\n    return a[np.ix_(ri, ci)]\n\n\ndef _resum_to_grid(a: np.ndarray, shape) -> np.ndarray:\n    \"\"\"Sayım rasterını (kişi/piksel) hedef ızgaraya toplayarak yeniden örnekler (toplam korunur).\"\"\"\n    H, W = shape\n    h, w = a.shape\n    ri = np.minimum((np.arange(h) * H / h).astype(int), H - 1)\n    ci = np.minimum((np.arange(w) * W / w).astype(int), W - 1)\n    out = np.zeros((H, W))\n    np.add.at(out, (ri[:, None].repeat(w, 1), ci[None, :].repeat(h, 0)), a)\n    return out\n\n\ndef block_reduce(a: np.ndarray, target_max: int, func=np.nanmean) -> np.ndarray:\n    f = int(math.ceil(max(a.shape) / target_max))\n    if f <= 1:\n        return a\n    H = (a.shape[0] // f) * f\n    W = (a.shape[1] // f) * f\n    b = a[:H, :W].reshape(H // f, f, W // f, f)\n    return func(func(b, axis=3), axis=1)\n\n\n# ---- sentetik yedekler -------------------------------------------------------\ndef synthetic_dem(bbox, n=200, seed=0) -> Tuple[np.ndarray, Any]:\n    \"\"\"Vadi + menderesli akarsu + kentsel düzlük içeren sentetik arazi (bağlantı yoksa).\"\"\"\n    from rasterio.transform import from_bounds\n    rng = np.random.default_rng(seed)\n    s, w, nn, e = bbox\n    y, x = np.mgrid[0:n, 0:n] / n\n    river = 0.5 + 0.12 * np.sin(2 * np.pi * y * 1.5) + 0.04 * np.sin(2 * np.pi * y * 5)\n    dist = np.abs(x - river)\n    z = 120 + 260 * dist ** 0.9 + 60 * (1 - y) + 6 * rng.random((n, n)) + 15 * np.sin(6 * x + 3 * y)\n    z[dist < 0.012] -= 8\n    return z.astype(\"float32\"), from_bounds(w, s, e, nn, n, n)\n\n\ndef synthetic_landcover(dem: np.ndarray, seed=0) -> np.ndarray:\n    rng = np.random.default_rng(seed)\n    z = (dem - np.nanmin(dem)) / (np.nanmax(dem) - np.nanmin(dem) + 1e-9)\n    lc = np.full(dem.shape, 30, dtype=\"uint8\")\n    lc[z < 0.18] = 50\n    lc[(z >= 0.18) & (z < 0.45)] = 40\n    lc[z >= 0.6] = 10\n    lc[rng.random(dem.shape) < 0.03] = 80\n    return lc\n\n\ndef synthetic_population(lc: np.ndarray, seed=0) -> np.ndarray:\n    rng = np.random.default_rng(seed)\n    pop = np.zeros(lc.shape)\n    pop[lc == 50] = rng.gamma(2.0, 25.0, size=int((lc == 50).sum()))\n    pop[lc == 40] = rng.gamma(1.0, 1.5, size=int((lc == 40).sum()))\n    return pop\n\n\ndef scs_type2_hyetograph(total_mm: float, hours: float, dt_h: float = 1.0) -> pd.Series:\n    \"\"\"SCS Tip-II benzeri (merkezi tepe) tasarım hiyetografı; toplam total_mm, süre hours.\"\"\"\n    n = max(1, int(round(hours / dt_h)))\n    t = (np.arange(n) + 0.5) / n\n    sigma = max(0.2, 0.6 / max(hours, 1e-6))  # süre kısaldıkça tepe daha yayvan (3 s: 17/66/17)\n    w = np.exp(-((t - 0.5) ** 2) / (2 * sigma ** 2))\n    w = w / w.sum() * total_mm\n    idx = pd.date_range(\"2000-01-01\", periods=n, freq=f\"{int(dt_h*60)}min\", tz=\"UTC\")\n    return pd.Series(w, index=idx, name=\"precipitation\")\n\n# ===========================================================================\n# 2. ARAZİ ANALİZİ — DEM doldurma, D8 akış yönü, birikim, dere ağı, HAND\n# ===========================================================================\n_D8_OFF = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]\n_D8_DIST = np.array([1, math.sqrt(2), 1, math.sqrt(2), 1, math.sqrt(2), 1, math.sqrt(2)])\n\n\ndef cell_size_m(transform, lat_center: float) -> Tuple[float, float]:\n    \"\"\"(dy_m, dx_m) EPSG:4326 dönüşümünden.\"\"\"\n    dy = abs(transform.e) * 111_320.0\n    dx = abs(transform.a) * 111_320.0 * math.cos(math.radians(lat_center))\n    return dy, dx\n\n\ndef fill_sinks(dem: np.ndarray) -> np.ndarray:\n    \"\"\"Priority-Flood (Barnes ve diğ. 2014) çukur doldurma; NaN'lar çevre ortalaması ile kapatılır.\"\"\"\n    import heapq\n    z = dem.astype(\"float64\").copy()\n    if np.isnan(z).any():\n        m = np.isnan(z)\n        z[m] = np.nanmean(z) if not np.isnan(np.nanmean(z)) else 0.0\n    H, W = z.shape\n    out = np.full_like(z, np.inf)\n    closed = np.zeros_like(z, dtype=bool)\n    heap = []\n    for i in range(H):\n        for j in (0, W - 1):\n            heap.append((z[i, j], i, j)); closed[i, j] = True\n    for j in range(1, W - 1):\n        for i in (0, H - 1):\n            heap.append((z[i, j], i, j)); closed[i, j] = True\n    heapq.heapify(heap)\n    while heap:\n        zc, i, j = heapq.heappop(heap)\n        out[i, j] = zc\n        for di, dj in _D8_OFF:\n            ni, nj = i + di, j + dj\n            if 0 <= ni < H and 0 <= nj < W and not closed[ni, nj]:\n                closed[ni, nj] = True\n                heapq.heappush(heap, (max(z[ni, nj], zc + 1e-4), ni, nj))\n    return out.astype(\"float32\")\n\n\ndef flow_direction_d8(zf: np.ndarray) -> np.ndarray:\n    \"\"\"Her hücre için en dik iniş yönü (0–7), akış yoksa -1.\"\"\"\n    H, W = zf.shape\n    zp = np.pad(zf, 1, mode=\"edge\")\n    best = np.full((H, W), -1, dtype=np.int8)\n    bestdrop = np.zeros((H, W))\n    for k, (di, dj) in enumerate(_D8_OFF):\n        zn = zp[1 + di:1 + di + H, 1 + dj:1 + dj + W]\n        drop = (zf - zn) / _D8_DIST[k]\n        m = drop > bestdrop\n        best[m] = k; bestdrop[m] = drop[m]\n    # kenarlara doğru akış izin ver (sınırda hücre dışına çıkış)\n    return best\n\n\ndef flow_accumulation(zf: np.ndarray, fdir: np.ndarray) -> np.ndarray:\n    H, W = zf.shape\n    acc = np.ones((H, W), dtype=\"float64\")\n    order = np.argsort(zf, axis=None)[::-1]  # yüksekten alçağa\n    ii, jj = np.unravel_index(order, (H, W))\n    for i, j in zip(ii, jj):\n        k = fdir[i, j]\n        if k < 0:\n            continue\n        di, dj = _D8_OFF[k]\n        ni, nj = i + di, j + dj\n        if 0 <= ni < H and 0 <= nj < W:\n            acc[ni, nj] += acc[i, j]\n    return acc\n\n\ndef compute_hand(zf: np.ndarray, fdir: np.ndarray, streams: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:\n    \"\"\"Height Above Nearest Drainage — akış yolundaki ilk dere hücresine göre yükseklik.\n    Döndürür: (hand, drain_idx) — drain_idx her hücrenin boşaldığı dere hücresinin düz indeksi.\"\"\"\n    H, W = zf.shape\n    drain = np.full((H, W), np.nan)\n    drain_idx = np.full((H, W), -1, dtype=np.int64)\n    flat = np.arange(H * W).reshape(H, W)\n    drain[streams] = zf[streams]; drain_idx[streams] = flat[streams]\n    order = np.argsort(zf, axis=None)  # alçaktan yükseğe: mansap önce işlenir\n    ii, jj = np.unravel_index(order, (H, W))\n    for i, j in zip(ii, jj):\n        if not np.isnan(drain[i, j]):\n            continue\n        k = fdir[i, j]\n        if k >= 0:\n            di, dj = _D8_OFF[k]\n            ni, nj = i + di, j + dj\n            if 0 <= ni < H and 0 <= nj < W and not np.isnan(drain[ni, nj]):\n                drain[i, j] = drain[ni, nj]; drain_idx[i, j] = drain_idx[ni, nj]\n                continue\n        drain[i, j] = zf[i, j]; drain_idx[i, j] = flat[i, j]  # kenardan çıkan hücre: kendi kotu (HAND=0 kabul)\n    return np.maximum(zf - drain, 0).astype(\"float32\"), drain_idx\n\n\ndef slope_fraction(zf: np.ndarray, dy_m: float, dx_m: float) -> np.ndarray:\n    gy, gx = np.gradient(zf, dy_m, dx_m)\n    return np.sqrt(gx ** 2 + gy ** 2)\n\n\n@dataclass\nclass Terrain:\n    dem: np.ndarray\n    filled: np.ndarray\n    fdir: np.ndarray\n    acc: np.ndarray\n    streams: np.ndarray\n    hand: np.ndarray\n    slope: np.ndarray\n    transform: Any\n    dy_m: float\n    dx_m: float\n    hand_source: str = \"computed\"\n    drain_idx: Optional[np.ndarray] = None\n    main_path: Optional[np.ndarray] = None      # ana kanal hücreleri (bool)\n    stage_scale: Optional[np.ndarray] = None    # yerel seviye ölçeği (memba alanına göre)\n    valid: Optional[np.ndarray] = None          # kara hücreleri (deniz/göl dışı)\n    props: Optional[dict] = None\n\n    @property\n    def cell_area_km2(self) -> float:\n        return self.dy_m * self.dx_m / 1e6\n\n    def catchment_props(self) -> dict:\n        \"\"\"Çıkış noktası (en büyük birikim), alan, ana kanal uzunluğu/eğimi, Kirpich tc, ana kanal maskesi.\"\"\"\n        if self.props is not None:\n            return self.props\n        H, W = self.filled.shape\n        acc = np.where(self.valid, self.acc, 0) if self.valid is not None else self.acc\n        oi, oj = np.unravel_index(np.argmax(acc), (H, W))\n        area_km2 = float(acc[oi, oj] * self.cell_area_km2)\n        path = np.zeros((H, W), dtype=bool); path[oi, oj] = True\n        i, j, length_m, path_z = oi, oj, 0.0, [self.filled[oi, oj]]\n        for _ in range(H * W):\n            best, bacc = None, 0\n            for k, (di, dj) in enumerate(_D8_OFF):\n                ni, nj = i + di, j + dj\n                if 0 <= ni < H and 0 <= nj < W and not path[ni, nj]:\n                    kk = self.fdir[ni, nj]\n                    if kk >= 0 and (ni + _D8_OFF[kk][0], nj + _D8_OFF[kk][1]) == (i, j) and self.acc[ni, nj] > bacc:\n                        best, bacc = (ni, nj, k), self.acc[ni, nj]\n            if best is None or bacc < 2:\n                break\n            ni, nj, k = best\n            length_m += _D8_DIST[k] * (self.dy_m + self.dx_m) / 2\n            path_z.append(self.filled[ni, nj]); path[ni, nj] = True; i, j = ni, nj\n        drop = max(path_z[-1] - path_z[0], 1.0)\n        s = drop / max(length_m, 100.0)\n        tc_min = 0.0195 * (max(length_m, 100.0) ** 0.77) * (s ** -0.385)  # Kirpich\n        self.main_path = path\n        self.props = dict(outlet_rc=(int(oi), int(oj)), area_km2=area_km2, channel_length_km=float(length_m / 1000),\n                          channel_slope=float(s), tc_hours=float(tc_min / 60), stream_cells=int(self.streams.sum()),\n                          outlet_acc=float(acc[oi, oj]))\n        return self.props\n\n\ndef build_terrain(dem: np.ndarray, transform, lat_center: float, stream_area_km2: float = 1.0,\n                  water_mask: Optional[np.ndarray] = None) -> Terrain:\n    dy, dx = cell_size_m(transform, lat_center)\n    valid = np.isfinite(dem) & (dem > 0.5)\n    if water_mask is not None:\n        valid &= ~water_mask\n    zf = fill_sinks(dem)\n    fdir = flow_direction_d8(zf)\n    acc = flow_accumulation(zf, fdir)\n    thr = max(2.0, stream_area_km2 / (dy * dx / 1e6))\n    streams = (acc >= thr) & valid\n    hand, drain_idx = compute_hand(zf, fdir, streams)\n    T = Terrain(dem=dem, filled=zf, fdir=fdir, acc=acc, streams=streams, hand=hand, slope=slope_fraction(zf, dy, dx),\n                transform=transform, dy_m=dy, dx_m=dx, hand_source=\"computed (GLO-30 DEM, D8)\", drain_idx=drain_idx, valid=valid)\n    props = T.catchment_props()\n    # yerel seviye ölçeği: boşaldığı dere hücresinin memba alanı / çıkış alanı (Q ~ A, h ~ Q^0.4)\n    acc_drain = acc.ravel()[drain_idx.ravel()].reshape(dem.shape)\n    T.stage_scale = np.clip((acc_drain / max(props[\"outlet_acc\"], 1.0)) ** 0.4, 0.12, 1.0).astype(\"float32\")\n    return T\n\n\n# ===========================================================================\n# 3. HİDROLOJİ — SCS-CN, Nash, HBV-light, GR4J, Sacramento (SAC-SMA), doğrusal hazne\n# ===========================================================================\n# WorldCover sınıfı × hidrolojik toprak grubu → SCS eğri numarası (AMC II, TR-55 tabloları)\nCN_TABLE = {\n    10: dict(A=36, B=60, C=73, D=79), 20: dict(A=35, B=56, C=70, D=77), 30: dict(A=49, B=69, C=79, D=84),\n    40: dict(A=67, B=78, C=85, D=89), 50: dict(A=89, B=92, C=94, D=95), 60: dict(A=77, B=86, C=91, D=94),\n    70: dict(A=98, B=98, C=98, D=98), 80: dict(A=100, B=100, C=100, D=100), 90: dict(A=90, B=93, C=95, D=97),\n    95: dict(A=90, B=93, C=95, D=97), 100: dict(A=60, B=75, C=83, D=87),\n}\n# Manning n ve sızma (mm/saat) — plüvyal CA modeli için\nMANNING_BY_LC = {10: 0.12, 20: 0.08, 30: 0.045, 40: 0.05, 50: 0.018, 60: 0.03, 70: 0.03, 80: 0.03, 90: 0.07, 95: 0.07, 100: 0.04}\nINFIL_BY_LC = {10: 18.0, 20: 12.0, 30: 9.0, 40: 7.0, 50: 0.8, 60: 4.0, 70: 0.0, 80: 0.0, 90: 2.0, 95: 2.0, 100: 6.0}\n\n\ndef composite_cn(lc: np.ndarray, hsg: str, amc: str = \"II\") -> Tuple[float, np.ndarray]:\n    cn = np.vectorize(lambda c: CN_TABLE.get(int(c), CN_TABLE[30])[hsg])(lc).astype(\"float32\")\n    if amc == \"I\":\n        cn = 4.2 * cn / (10 - 0.058 * cn)\n    elif amc == \"III\":\n        cn = 23 * cn / (10 + 0.13 * cn)\n    return float(np.clip(cn.mean(), 30, 100)), np.clip(cn, 30, 100)\n\n\ndef scs_excess(rain_mm: np.ndarray, cn: float, ia_ratio: float = 0.2) -> np.ndarray:\n    \"\"\"Kümülatif SCS-CN yöntemi ile artımlı etkin yağış (mm).\"\"\"\n    s = 25400.0 / cn - 254.0\n    ia = ia_ratio * s\n    P = np.cumsum(rain_mm)\n    Pe = np.where(P > ia, (P - ia) ** 2 / (P - ia + s), 0.0)\n    return np.diff(np.concatenate([[0.0], Pe]))\n\n\ndef scs_unit_hydrograph(tp_h: float, dt_h: float) -> np.ndarray:\n    \"\"\"SCS boyutsuz birim hidrografı (t/tp, q/qp tablosu) — 1 mm etkin yağış için m³/s·km².\"\"\"\n    t_ratio = np.array([0, .1, .2, .3, .4, .5, .6, .7, .8, .9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 4.5, 5])\n    q_ratio = np.array([0, .03, .1, .19, .31, .47, .66, .82, .93, .99, 1, .99, .93, .86, .78, .68, .56, .39, .28, .207, .147, .107, .077, .055, .025, .011, .005, 0])\n    qp = 0.208 / tp_h  # m³/s per km² per mm (SCS: qp = 0.208 A Q / tp)\n    t = np.arange(0, 5 * tp_h + dt_h, dt_h)\n    return np.interp(t / tp_h, t_ratio, q_ratio) * qp\n\n\ndef route_uh(excess_mm: np.ndarray, uh: np.ndarray, area_km2: float) -> np.ndarray:\n    return np.convolve(excess_mm, uh)[: len(excess_mm)] * area_km2\n\n\ndef model_scs_uh(rain: pd.Series, area_km2: float, cn: float, tc_h: float, baseflow: float = 0.0) -> pd.Series:\n    dt_h = _dt_hours(rain)\n    ex = scs_excess(rain.values, cn)\n    tp = max(0.6 * tc_h + dt_h / 2, dt_h)\n    q = route_uh(ex, scs_unit_hydrograph(tp, dt_h), area_km2) + baseflow\n    return pd.Series(q, index=rain.index, name=\"SCS-CN + SCS UH\")\n\n\ndef model_nash(rain: pd.Series, area_km2: float, cn: float, n_res: float = 3.0, k_h: float | None = None,\n               tc_h: float = 3.0, baseflow: float = 0.0) -> pd.Series:\n    from scipy.special import gamma as G\n    dt_h = _dt_hours(rain)\n    k = k_h or max(tc_h / n_res, dt_h)\n    t = np.arange(dt_h / 2, 8 * n_res * k, dt_h)\n    iuh = (1 / (k * G(n_res))) * (t / k) ** (n_res - 1) * np.exp(-t / k) * dt_h  # birim: 1/dt\n    uh = iuh / 3.6 / dt_h  # mm·km² → m³/s\n    q = route_uh(scs_excess(rain.values, cn), uh, area_km2) + baseflow\n    return pd.Series(q, index=rain.index, name=\"Nash kaskadı\")\n\n\ndef model_linear_reservoir(rain: pd.Series, area_km2: float, runoff_coef: float = 0.6, k_h: float = 4.0,\n                           baseflow: float = 0.0) -> pd.Series:\n    dt_h = _dt_hours(rain)\n    S, out = 0.0, []\n    for p in rain.values:\n        S += runoff_coef * p\n        q_mm = S * (1 - math.exp(-dt_h / k_h))\n        S -= q_mm\n        out.append(q_mm * area_km2 / 3.6 / dt_h + baseflow)\n    return pd.Series(out, index=rain.index, name=\"Doğrusal hazne\")\n\n\ndef model_hbv_light(rain: pd.Series, pet_mm_h: np.ndarray | float, area_km2: float, temp_c: np.ndarray | float = 15.0,\n                    params: dict | None = None, baseflow: float = 0.0) -> pd.Series:\n    \"\"\"HBV-light (Seibert 2005) — saatlik zaman adımına ölçeklenmiş; kar rutini dahil.\"\"\"\n    p = dict(TT=0.0, CFMAX=3.5, SFCF=0.9, CFR=0.05, CWH=0.1, FC=150.0, LP=0.7, BETA=1.8,\n             PERC=1.5, UZL=25.0, K0=0.4, K1=0.12, K2=0.01, MAXBAS=0.25, SM0=0.6)  # MAXBAS gün; olay ölçeğinde ≈ tc\n    if params:\n        p.update(params)\n    dt_h = _dt_hours(rain)\n    f = dt_h / 24.0  # günlük parametrelerin saatliğe ölçeği\n    P = rain.values\n    n = len(P)\n    T = np.broadcast_to(np.asarray(temp_c, dtype=float), (n,))\n    E = np.broadcast_to(np.asarray(pet_mm_h, dtype=float), (n,))\n    snow = swe = 0.0\n    sm = p[\"SM0\"] * p[\"FC\"]\n    suz = slz = 0.0\n    qs = np.zeros(n)\n    for i in range(n):\n        # kar\n        if T[i] < p[\"TT\"]:\n            snow += P[i] * p[\"SFCF\"]; rain_in = 0.0\n        else:\n            rain_in = P[i]\n        melt = min(snow, p[\"CFMAX\"] * f * max(T[i] - p[\"TT\"], 0))\n        snow -= melt; swe += melt\n        refr = min(swe, p[\"CFR\"] * p[\"CFMAX\"] * f * max(p[\"TT\"] - T[i], 0))\n        snow += refr; swe -= refr\n        excess_snow = max(swe - p[\"CWH\"] * snow, 0); swe -= excess_snow\n        inp = rain_in + excess_snow\n        # toprak\n        recharge = inp * (sm / p[\"FC\"]) ** p[\"BETA\"]\n        sm += inp - recharge\n        et = E[i] * min(sm / (p[\"LP\"] * p[\"FC\"]), 1.0)\n        sm = max(sm - et, 0.0)\n        if sm > p[\"FC\"]:\n            recharge += sm - p[\"FC\"]; sm = p[\"FC\"]\n        # tepki\n        suz += recharge\n        perc = min(suz, p[\"PERC\"] * f); suz -= perc; slz += perc\n        q0 = p[\"K0\"] * f * max(suz - p[\"UZL\"], 0)\n        q1 = p[\"K1\"] * f * suz\n        q2 = p[\"K2\"] * f * slz\n        suz -= q0 + q1; slz -= q2\n        qs[i] = q0 + q1 + q2\n    mb = max(int(round(p[\"MAXBAS\"] / f)), 1)\n    w = np.array([min(k + 1, mb - k) for k in range(mb)], dtype=float); w /= w.sum()\n    q = np.convolve(qs, w)[:n] * area_km2 / 3.6 / dt_h + baseflow\n    return pd.Series(q, index=rain.index, name=\"HBV-light\")\n\n\ndef model_gr4j(rain_daily: pd.Series, pet_daily: pd.Series, area_km2: float,\n               x1=350.0, x2=0.0, x3=90.0, x4=1.7) -> pd.Series:\n    \"\"\"GR4J (Perrin ve diğ. 2003) günlük — akış m³/s.\"\"\"\n    P, E = rain_daily.values, np.broadcast_to(pet_daily.values if hasattr(pet_daily, \"values\") else pet_daily, rain_daily.shape)\n    n = len(P)\n    nUH1, nUH2 = int(math.ceil(x4)), int(math.ceil(2 * x4))\n\n    def SH1(t):\n        return 0 if t <= 0 else (t / x4) ** 2.5 if t < x4 else 1\n\n    def SH2(t):\n        if t <= 0: return 0\n        if t < x4: return 0.5 * (t / x4) ** 2.5\n        if t < 2 * x4: return 1 - 0.5 * (2 - t / x4) ** 2.5\n        return 1\n    UH1 = np.array([SH1(j + 1) - SH1(j) for j in range(nUH1)])\n    UH2 = np.array([SH2(j + 1) - SH2(j) for j in range(nUH2)])\n    S, R = 0.3 * x1, 0.5 * x3\n    q1 = np.zeros(nUH1); q2 = np.zeros(nUH2)\n    out = np.zeros(n)\n    for i in range(n):\n        if P[i] >= E[i]:\n            Pn, En = P[i] - E[i], 0.0\n            ws = np.tanh(Pn / x1)\n            Ps = x1 * (1 - (S / x1) ** 2) * ws / (1 + S / x1 * ws)\n            S += Ps; Es = 0.0\n        else:\n            Pn, En = 0.0, E[i] - P[i]\n            we = np.tanh(En / x1)\n            Es = S * (2 - S / x1) * we / (1 + (1 - S / x1) * we)\n            S -= Es; Ps = 0.0\n        perc = S * (1 - (1 + (4 / 9 * S / x1) ** 4) ** -0.25)\n        S -= perc\n        Pr = perc + (Pn - Ps)\n        q1 = np.roll(q1, -1); q1[-1] = 0; q1 += UH1 * 0.9 * Pr\n        q2 = np.roll(q2, -1); q2[-1] = 0; q2 += UH2 * 0.1 * Pr\n        F = x2 * (R / x3) ** 3.5\n        R = max(R + q1[0] + F, 0)\n        Qr = R * (1 - (1 + (R / x3) ** 4) ** -0.25)\n        R -= Qr\n        Qd = max(q2[0] + F, 0)\n        out[i] = (Qr + Qd) * area_km2 / 86.4\n    return pd.Series(out, index=rain_daily.index, name=\"GR4J\")\n\n\ndef model_sacramento(rain: pd.Series, pet_mm_step: np.ndarray | float, area_km2: float,\n                     params: dict | None = None, baseflow: float = 0.0) -> pd.Series:\n    \"\"\"SAC-SMA (Burnash 1973) — sadeleştirilmiş uygulama (donmuş toprak yok). Adım: rain serisinin adımı.\"\"\"\n    p = dict(UZTWM=60.0, UZFWM=40.0, LZTWM=130.0, LZFPM=80.0, LZFSM=40.0, UZK=0.25, LZPK=0.01, LZSK=0.08,\n             ZPERC=60.0, REXP=1.5, PCTIM=0.02, ADIMP=0.05, PFREE=0.1, RIVA=0.0, SIDE=0.0, UNIT_K=6.0)\n    if params:\n        p.update(params)\n    dt_h = _dt_hours(rain)\n    f = dt_h / 24.0\n    P = rain.values; n = len(P)\n    E = np.broadcast_to(np.asarray(pet_mm_step, dtype=float), (n,))\n    uztwc, uzfwc = 0.5 * p[\"UZTWM\"], 0.2 * p[\"UZFWM\"]\n    lztwc, lzfpc, lzfsc = 0.5 * p[\"LZTWM\"], 0.5 * p[\"LZFPM\"], 0.3 * p[\"LZFSM\"]\n    adimc = uztwc + lztwc\n    tci = np.zeros(n)\n    parea = 1 - p[\"PCTIM\"] - p[\"ADIMP\"]\n    for i in range(n):\n        # ET\n        e1 = E[i] * uztwc / p[\"UZTWM\"]; red = E[i] - e1\n        uztwc -= e1\n        e2 = 0.0\n        if uztwc < 0:\n            e1 += uztwc; uztwc = 0\n            e2 = min(uzfwc, red); uzfwc -= e2; red -= e2\n        if uztwc / p[\"UZTWM\"] < uzfwc / p[\"UZFWM\"]:\n            tot = uztwc + uzfwc; r = tot / (p[\"UZTWM\"] + p[\"UZFWM\"])\n            uztwc, uzfwc = p[\"UZTWM\"] * r, p[\"UZFWM\"] * r\n        e3 = red * lztwc / (p[\"UZTWM\"] + p[\"LZTWM\"]); lztwc = max(lztwc - e3, 0)\n        ratlzt = lztwc / p[\"LZTWM\"]; ratlz = (lztwc + lzfpc + lzfsc) / (p[\"LZTWM\"] + p[\"LZFPM\"] + p[\"LZFSM\"])\n        if ratlzt < ratlz:\n            d = (ratlz - ratlzt) * p[\"LZTWM\"]; lztwc += d; lzfsc -= d\n            if lzfsc < 0:\n                lzfpc += lzfsc; lzfsc = 0\n        e5 = e1 + (red + e2) * (adimc - e1 - uztwc) / (p[\"UZTWM\"] + p[\"LZTWM\"]); adimc = max(adimc - e5, 0)\n        # yağış\n        twx = P[i] + uztwc - p[\"UZTWM\"]\n        if twx < 0:\n            uztwc += P[i]; twx = 0.0\n        else:\n            uztwc = p[\"UZTWM\"]\n        adimc += P[i] - twx\n        roimp = P[i] * p[\"PCTIM\"]\n        # perkolasyon & yüzey akışı\n        sbf = lzfpc * p[\"LZPK\"] * f + lzfsc * p[\"LZSK\"] * f\n        lzfpc -= lzfpc * p[\"LZPK\"] * f; lzfsc -= lzfsc * p[\"LZSK\"] * f\n        ssur = 0.0; sif = 0.0\n        pbase = p[\"LZFPM\"] * p[\"LZPK\"] * f + p[\"LZFSM\"] * p[\"LZSK\"] * f\n        defr = 1 - (lztwc + lzfpc + lzfsc) / (p[\"LZTWM\"] + p[\"LZFPM\"] + p[\"LZFSM\"])\n        perc = pbase * (1 + p[\"ZPERC\"] * defr ** p[\"REXP\"]) * uzfwc / p[\"UZFWM\"]\n        perc = min(perc, uzfwc, (p[\"LZTWM\"] - lztwc) + (p[\"LZFPM\"] - lzfpc) + (p[\"LZFSM\"] - lzfsc))\n        uzfwc -= perc\n        perct = perc * (1 - p[\"PFREE\"]); lztwc += perct\n        if lztwc > p[\"LZTWM\"]:\n            perc_free = perc * p[\"PFREE\"] + (lztwc - p[\"LZTWM\"]); lztwc = p[\"LZTWM\"]\n        else:\n            perc_free = perc * p[\"PFREE\"]\n        hpl = p[\"LZFPM\"] / (p[\"LZFPM\"] + p[\"LZFSM\"])\n        ratlp, ratls = lzfpc / p[\"LZFPM\"], lzfsc / p[\"LZFSM\"]\n        fracp = min(1.0, hpl * 2 * (1 - ratlp) / ((1 - ratlp) + (1 - ratls) + 1e-9))\n        percp, percs = perc_free * fracp, perc_free * (1 - fracp)\n        lzfsc += percs\n        if lzfsc > p[\"LZFSM\"]:\n            percp += lzfsc - p[\"LZFSM\"]; lzfsc = p[\"LZFSM\"]\n        lzfpc = min(lzfpc + percp, p[\"LZFPM\"])\n        # ara akış\n        sif = uzfwc * p[\"UZK\"] * f; uzfwc -= sif\n        # üst bölge serbest su\n        uzfwc += twx\n        if uzfwc > p[\"UZFWM\"]:\n            ssur = uzfwc - p[\"UZFWM\"]; uzfwc = p[\"UZFWM\"]\n        addro = twx * ((adimc - uztwc) / p[\"LZTWM\"]) ** 2 if adimc > uztwc else 0.0\n        adimc = min(adimc + twx - addro, p[\"UZTWM\"] + p[\"LZTWM\"])\n        tci[i] = roimp + addro * p[\"ADIMP\"] + (ssur + sif) * parea + sbf * parea * (1 - p[\"SIDE\"])\n    k = max(p[\"UNIT_K\"], dt_h)\n    t = np.arange(0, 6 * k, dt_h); uh = np.exp(-t / k); uh /= uh.sum()\n    q = np.convolve(tci, uh)[:n] * area_km2 / 3.6 / dt_h + baseflow\n    return pd.Series(q, index=rain.index, name=\"Sacramento SAC-SMA\")\n\n\ndef _dt_hours(s: pd.Series) -> float:\n    if len(s.index) < 2:\n        return 1.0\n    return float((s.index[1] - s.index[0]).total_seconds() / 3600.0)\n\n\n# ---- değerlendirme ölçütleri -------------------------------------------------\ndef nse(obs, sim) -> float:\n    obs, sim = np.asarray(obs, float), np.asarray(sim, float)\n    m = np.isfinite(obs) & np.isfinite(sim)\n    if m.sum() < 2:\n        return float(\"nan\")\n    return float(1 - np.sum((obs[m] - sim[m]) ** 2) / (np.sum((obs[m] - obs[m].mean()) ** 2) + 1e-12))\n\n\ndef kge(obs, sim) -> float:\n    obs, sim = np.asarray(obs, float), np.asarray(sim, float)\n    m = np.isfinite(obs) & np.isfinite(sim)\n    if m.sum() < 2:\n        return float(\"nan\")\n    r = np.corrcoef(obs[m], sim[m])[0, 1] if np.std(sim[m]) > 0 else 0.0\n    a = np.std(sim[m]) / (np.std(obs[m]) + 1e-12)\n    b = np.mean(sim[m]) / (np.mean(obs[m]) + 1e-12)\n    return float(1 - math.sqrt((r - 1) ** 2 + (a - 1) ** 2 + (b - 1) ** 2))\n\n\ndef evaluate_models(sims: Dict[str, pd.Series], reference: Optional[pd.Series]) -> pd.DataFrame:\n    rows = []\n    for name, q in sims.items():\n        row = dict(model=name, peak_m3s=float(q.max()), t_peak=q.idxmax(), volume_hm3=float(q.sum() * _dt_hours(q) * 3600 / 1e6))\n        if reference is not None and len(reference) > 2:\n            qd = q.resample(\"1D\").mean()\n            j = pd.concat([reference.rename(\"ref\"), qd.rename(\"sim\")], axis=1).dropna()\n            if len(j) >= 2:\n                row.update(NSE=nse(j.ref, j.sim), KGE=kge(j.ref, j.sim),\n                           peak_err_pct=float((j.sim.max() - j.ref.max()) / (j.ref.max() + 1e-9) * 100))\n        rows.append(row)\n    df = pd.DataFrame(rows)\n    if \"KGE\" in df:\n        df = df.sort_values(\"KGE\", ascending=False)\n    return df.reset_index(drop=True)\n\n\ndef run_classical_models(rain: pd.Series, area_km2: float, cn: float, tc_h: float, pet_mm_h: float = 0.15,\n                         temp_c: float = 15.0, baseflow: float = 0.0, daily_rain: pd.Series | None = None,\n                         daily_pet: pd.Series | None = None) -> Dict[str, pd.Series]:\n    \"\"\"Tüm klasik modelleri ayrı ayrı çalıştırır (Malezya v6.0 gereksinimi: her model bağımsız).\"\"\"\n    sims = {\n        \"SCS-CN + SCS UH\": model_scs_uh(rain, area_km2, cn, tc_h, baseflow),\n        \"Nash kaskadı\": model_nash(rain, area_km2, cn, tc_h=tc_h, baseflow=baseflow),\n        \"Doğrusal hazne\": model_linear_reservoir(rain, area_km2, runoff_coef=min(0.95, cn / 100), k_h=max(tc_h, 1.0), baseflow=baseflow),\n        \"HBV-light\": model_hbv_light(rain, pet_mm_h, area_km2, temp_c, params=dict(MAXBAS=max(tc_h, 1.0) / 24.0), baseflow=baseflow),\n        \"Sacramento SAC-SMA\": model_sacramento(rain, pet_mm_h, area_km2, baseflow=baseflow),\n    }\n    if daily_rain is not None:\n        pet_d = daily_pet if daily_pet is not None else pd.Series(pet_mm_h * 24, index=daily_rain.index)\n        sims[\"GR4J\"] = model_gr4j(daily_rain, pet_d, area_km2)\n    return sims\n\n# ===========================================================================\n# 4. TAŞMA — HAND tabanlı nehir taşkını ve 2B hücresel otomat plüvyal model\n# ===========================================================================\ndef synthetic_rating_curve(terrain: Terrain, channel_slope: float, manning_n: float = 0.045,\n                           max_stage: float = 15.0, step: float = 0.1) -> pd.DataFrame:\n    \"\"\"HAND'den sentetik anahtar eğrisi (Zheng ve diğ. 2018): yalnızca ana kanala boşalan koridor hücreleri\n    kullanılır; kesit alanı ve hidrolik yarıçap seviyeye bağlanır, Q = A R^(2/3) S^(1/2) / n (erişim ortalaması).\"\"\"\n    cell_area = terrain.dy_m * terrain.dx_m\n    cell_len = (terrain.dy_m + terrain.dx_m) / 2\n    props = terrain.catchment_props()\n    main = terrain.main_path if terrain.main_path is not None else terrain.streams\n    L = max(props[\"channel_length_km\"] * 1000.0, cell_len)\n    corridor = np.isin(terrain.drain_idx, np.flatnonzero(main)) if terrain.drain_idx is not None else np.ones_like(terrain.hand, bool)\n    if terrain.valid is not None:\n        corridor &= terrain.valid\n    hand = np.where(corridor, terrain.hand, np.inf)\n    rows = []\n    for h in np.arange(step, max_stage + step, step):\n        wet = hand < h\n        depth = (h - hand[wet])\n        A = depth.sum() * cell_area / L\n        B = wet.sum() * cell_area / L  # ıslak üst genişlik yaklaşımı\n        R = A / (B + 2 * h + 1e-6)\n        Q = A * R ** (2 / 3) * math.sqrt(max(channel_slope, 1e-4)) / manning_n\n        rows.append(dict(stage_m=h, Q_m3s=Q, area_m2=A, top_width_m=B, wet_cells=int(wet.sum())))\n    return pd.DataFrame(rows)\n\n\ndef stage_from_discharge(rating: pd.DataFrame, Q: float) -> float:\n    return float(np.interp(Q, rating.Q_m3s.values, rating.stage_m.values))\n\n\ndef hand_inundation(terrain: Terrain, stage_m: float) -> np.ndarray:\n    \"\"\"Derinlik = yerel seviye − HAND; yerel seviye, hücrenin boşaldığı dere kolunun memba alanına göre ölçeklenir\n    (ana kanalda tam seviye, küçük yan kollarda daha düşük).\"\"\"\n    scale = terrain.stage_scale if terrain.stage_scale is not None else 1.0\n    d = stage_m * scale - terrain.hand\n    d[d < 0] = 0\n    if terrain.valid is not None:\n        d[~terrain.valid] = 0\n    return d.astype(\"float32\")\n\n\ndef pluvial_ca(zf: np.ndarray, rain_mm_h: pd.Series, lc: np.ndarray, dy_m: float, dx_m: float,\n               drain_hours: float = 2.0, dt_max: float = 30.0, max_minutes: float = 30.0,\n               manning_scale: float = 1.0, infil_scale: float = 1.0, record_every_min: float = 15.0,\n               sink: Optional[np.ndarray] = None, sewer_mm_h: float = 0.0) -> dict:\n    \"\"\"Ağırlıklı hücresel otomat (Ghimire ve diğ. 2013 / CADDIES tarzı) yüzeysel akış modeli.\n    Yağış fazlası her hücreye eklenir; su, Manning hızıyla 8 komşuya baş farkına göre dağılır.\n    sink: deniz/göl hücreleri (su emilir, derinlik birikmez).\"\"\"\n    t0 = time.time()\n    H_, W_ = zf.shape\n    if sink is None:\n        sink = (lc == 80) | (zf <= 0.5)\n    n_map = np.vectorize(lambda c: MANNING_BY_LC.get(int(c), 0.05))(lc) * manning_scale\n    infil = np.vectorize(lambda c: INFIL_BY_LC.get(int(c), 6.0))(lc) * infil_scale\n    infil = (infil + np.where(lc == 50, sewer_mm_h, 0.0)) / 3600.0 / 1000.0  # m/s (sızma + şebeke kapasitesi)\n    zpad = np.pad(zf, 1, mode=\"edge\") - 0.0\n    zpad[0, :] -= 5; zpad[-1, :] -= 5; zpad[:, 0] -= 5; zpad[:, -1] -= 5  # sınırlar: çıkış\n    h = np.zeros((H_ + 2, W_ + 2))\n    hmax = np.zeros((H_, W_))\n    dt_h = _dt_hours(rain_mm_h)\n    rain = rain_mm_h.values / 1000.0 / (dt_h * 3600.0)  # m/s\n    T_total = (len(rain) * dt_h + drain_hours) * 3600.0\n    dist = np.array([(dy_m + dx_m) / 2 if k % 2 == 0 else math.hypot(dy_m, dx_m) for k in range(8)])\n    dist[0] = dist[4] = dy_m; dist[2] = dist[6] = dx_m\n    t, steps, snapshots = 0.0, 0, []\n    next_snap = record_every_min * 60\n    while t < T_total:\n        if time.time() - t0 > max_minutes * 60:\n            log.warning(\"pluvial_ca: süre bütçesi doldu, erken bitirildi\"); break\n        idx = min(int(t // (dt_h * 3600.0)), len(rain) - 1) if t < len(rain) * dt_h * 3600.0 else None\n        core = h[1:-1, 1:-1]\n        wl = zpad + h\n        outflow = np.zeros((8, H_, W_))\n        vmax = 0.0\n        for k, (di, dj) in enumerate(_D8_OFF):\n            wn = wl[1 + di:1 + di + H_, 1 + dj:1 + dj + W_]\n            dh = wl[1:-1, 1:-1] - wn\n            pos = dh > 1e-4\n            if not pos.any():\n                continue\n            hc = core[pos]\n            v = (1.0 / n_map[pos]) * np.maximum(hc, 1e-4) ** (2 / 3) * np.sqrt(dh[pos] / dist[k])\n            v = np.minimum(v, 6.0)\n            vmax = max(vmax, float(v.max()) if v.size else 0.0)\n            flux = np.zeros_like(dh); flux[pos] = v * hc / dist[k]  # m/s (derinlik/s)\n            outflow[k] = flux\n        dt = min(dt_max, 0.6 * dist.min() / (vmax + 1e-3))\n        dt = max(dt, 0.5)\n        tot = outflow.sum(axis=0) * dt\n        cap = 0.5 * core\n        scale = np.where(tot > cap, cap / (tot + 1e-12), 1.0)\n        outflow *= scale * dt\n        newh = h.copy()\n        newh[1:-1, 1:-1] -= outflow.sum(axis=0)\n        for k, (di, dj) in enumerate(_D8_OFF):\n            newh[1 + di:1 + di + H_, 1 + dj:1 + dj + W_] += outflow[k]\n        # yağış ve sızma\n        core_new = newh[1:-1, 1:-1]\n        if idx is not None:\n            core_new += rain[idx] * dt\n        core_new -= np.minimum(core_new, infil * dt)\n        core_new[sink] = 0.0\n        newh[1:-1, 1:-1] = core_new\n        newh[0, :] = 0; newh[-1, :] = 0; newh[:, 0] = 0; newh[:, -1] = 0  # sınırdan çıkan su kaybolur\n        h = newh\n        hmax = np.maximum(hmax, h[1:-1, 1:-1])\n        t += dt; steps += 1\n        if t >= next_snap:\n            snapshots.append((t / 3600.0, h[1:-1, 1:-1].copy())); next_snap += record_every_min * 60\n    return dict(max_depth=hmax.astype(\"float32\"), final_depth=h[1:-1, 1:-1].astype(\"float32\"), steps=steps,\n                sim_hours=t / 3600.0, runtime_s=time.time() - t0, snapshots=snapshots)\n\n\n# ===========================================================================\n# 5. KUANTUM KATMANI — VQC tabanlı QML tahmin, QUBO/QAOA kaynak tahsisi\n# ===========================================================================\ndef build_forecast_dataset(daily_rain: pd.Series, daily_q: pd.Series, lags: int = 7, horizon: int = 1) -> Tuple[pd.DataFrame, pd.Series]:\n    df = pd.concat([daily_rain.rename(\"P\"), daily_q.rename(\"Q\")], axis=1).dropna()\n    X = pd.DataFrame(index=df.index)\n    for L in range(0, lags):\n        X[f\"P_l{L}\"] = df.P.shift(L)\n    for L in range(1, 4):\n        X[f\"Q_l{L}\"] = df.Q.shift(L)\n    X[\"P_3d\"] = df.P.rolling(3).sum(); X[\"P_7d\"] = df.P.rolling(7).sum()\n    doy = df.index.dayofyear\n    X[\"s\"] = np.sin(2 * np.pi * doy / 365.25); X[\"c\"] = np.cos(2 * np.pi * doy / 365.25)\n    y = df.Q.shift(-horizon)\n    m = X.notna().all(axis=1) & y.notna()\n    return X[m], y[m]\n\n\nclass QMLForecaster:\n    \"\"\"Değişkensel kuantum devresi (VQC) ile regresyon: PCA → açı kodlama (RY) → StronglyEntanglingLayers → <Z0>.\n    Eğitim: default.qubit simülatörü (parametre yayını + backprop; 6 kübit/60 adım ≈ saniyeler).\n    Donanım çıkarımı (isteğe bağlı): backend='ibm' → Qiskit Runtime (pennylane-qiskit), backend='origin' →\n    Origin Wukong / pyqpanda3 (QCloud jetonu varsa donanım, yoksa yerel simülatör). Test kümesinin bir alt kümesi\n    donanımda yeniden değerlendirilir; simülatör tahminleri her zaman üretilir.\"\"\"\n\n    def __init__(self, n_qubits=6, layers=3, epochs=60, backend=\"default.qubit\", seed=42, lr=0.05, batch=48, hw_samples=8):\n        self.n, self.layers, self.epochs, self.backend, self.seed, self.lr, self.batch, self.hw_samples = n_qubits, layers, epochs, backend, seed, lr, batch, hw_samples\n        self.history: List[float] = []\n        self.info = dict(backend=backend, n_qubits=n_qubits, layers=layers, train_device=\"default.qubit (backprop)\")\n\n    def _prep(self, X, fit=False):\n        from sklearn.decomposition import PCA\n        from sklearn.preprocessing import StandardScaler, MinMaxScaler\n        if fit:\n            self.sc = StandardScaler().fit(X)\n            k = min(self.n, X.shape[1])\n            self.pca = PCA(n_components=k, random_state=self.seed).fit(self.sc.transform(X))\n            Z = self.pca.transform(self.sc.transform(X))\n            self.mm = MinMaxScaler((0, np.pi)).fit(Z)\n        Z = self.pca.transform(self.sc.transform(X))\n        Z = self.mm.transform(Z)\n        if Z.shape[1] < self.n:\n            Z = np.hstack([Z, np.zeros((Z.shape[0], self.n - Z.shape[1]))])\n        return np.clip(Z, 0, np.pi)\n\n    def fit(self, X: pd.DataFrame, y: pd.Series):\n        import pennylane as qml\n        from pennylane import numpy as pnp\n        Z = self._prep(X.values, fit=True)\n        self.ymu, self.ysd = float(y.mean()), float(y.std() + 1e-9)\n        yy = ((y.values - self.ymu) / self.ysd).astype(float)\n        dev = qml.device(\"default.qubit\", wires=self.n)\n        n = self.n\n\n        @qml.qnode(dev, diff_method=\"backprop\")\n        def circuit(x, w):\n            qml.AngleEmbedding(x, wires=range(n), rotation=\"Y\")\n            qml.StronglyEntanglingLayers(w, wires=range(n))\n            return qml.expval(qml.PauliZ(0))\n\n        self.circuit = circuit\n        rng = np.random.default_rng(self.seed)\n        w = pnp.array(rng.normal(0, 0.3, (self.layers, n, 3)), requires_grad=True)\n        a = pnp.array(2.0, requires_grad=True); b = pnp.array(0.0, requires_grad=True)\n        opt = qml.AdamOptimizer(self.lr)\n\n        def loss(w, a, b, Xb, yb):\n            return pnp.mean((a * circuit(Xb, w) + b - yb) ** 2)\n        N = len(Z)\n        for _ in range(self.epochs):\n            idx = rng.permutation(N)[: self.batch]\n            (w, a, b), L = opt.step_and_cost(loss, w, a, b, Xb=Z[idx], yb=yy[idx])\n            self.history.append(float(L))\n        self.w, self.a, self.b = np.array(w), float(a), float(b)\n        return self\n\n    def predict(self, X: pd.DataFrame) -> np.ndarray:\n        Z = self._prep(X.values)\n        out = np.asarray(self.circuit(Z, self.w), dtype=float) * self.a + self.b\n        return out * self.ysd + self.ymu\n\n    # ---- donanım çıkarımı ------------------------------------------------\n    def predict_hardware(self, X: pd.DataFrame) -> Optional[np.ndarray]:\n        \"\"\"Test alt kümesini gerçek QPU'da (IBM veya Origin) değerlendirir; kullanılamazsa None.\"\"\"\n        Z = self._prep(X.values)[: self.hw_samples]\n        if self.backend == \"ibm\":\n            try:\n                import pennylane as qml\n                from qiskit_ibm_runtime import QiskitRuntimeService\n                svc = QiskitRuntimeService()\n                bk = svc.least_busy(operational=True, simulator=False, min_num_qubits=self.n)\n                dev = qml.device(\"qiskit.remote\", wires=self.n, backend=bk, shots=1024)\n                n = self.n\n\n                @qml.qnode(dev)\n                def hw(x, w):\n                    qml.AngleEmbedding(x, wires=range(n), rotation=\"Y\")\n                    qml.StronglyEntanglingLayers(w, wires=range(n))\n                    return qml.expval(qml.PauliZ(0))\n                vals = np.array([float(hw(z, self.w)) for z in Z])\n                self.info.update(hw_backend=bk.name, hw_samples=len(Z))\n                return vals * self.a * self.ysd + self.b * self.ysd + self.ymu\n            except Exception as ex:  # noqa: BLE001\n                self.info[\"hw_note\"] = f\"IBM çıkarımı yapılamadı: {str(ex)[:100]}\"\n                return None\n        if self.backend == \"origin\":\n            try:\n                import pyqpanda3.core as pq\n                n = self.n\n                vals = []\n                for z in Z:\n                    prog = pq.QProg()\n                    for i in range(n):\n                        prog << pq.RY(i, float(z[i]))\n                    for L in range(self.layers):\n                        for i in range(n):\n                            phi, th, om = (float(v) for v in self.w[L, i])\n                            prog << pq.RZ(i, phi) << pq.RY(i, th) << pq.RZ(i, om)\n                        r = (L % (n - 1)) + 1 if n > 1 else 0\n                        for i in range(n):\n                            if n > 1:\n                                prog << pq.CNOT(i, (i + r) % n)\n                    prog << pq.measure_all()\n                    if os.environ.get(\"ORIGIN_QCLOUD_TOKEN\"):\n                        from pyqpanda3.qcloud import QCloudService  # type: ignore\n                        svc = QCloudService(os.environ[\"ORIGIN_QCLOUD_TOKEN\"])\n                        res = svc.run(prog, 1024)\n                        counts = res.get_counts() if hasattr(res, \"get_counts\") else res\n                        self.info[\"hw_backend\"] = \"Origin Wukong (QCloud)\"\n                    else:\n                        qvm = pq.CPUQVM(); qvm.run(prog, 1024); counts = qvm.result().get_counts()\n                        self.info[\"hw_backend\"] = \"pyqpanda3 CPUQVM (yerel simülatör)\"\n                    tot = sum(counts.values()); z0 = sum(c * (1 if k[-1] == \"0\" else -1) for k, c in counts.items()) / tot\n                    vals.append(z0)\n                vals = np.array(vals); self.info[\"hw_samples\"] = len(Z)\n                return vals * self.a * self.ysd + self.b * self.ysd + self.ymu\n            except Exception as ex:  # noqa: BLE001\n                self.info[\"hw_note\"] = f\"Origin çıkarımı yapılamadı: {str(ex)[:100]}\"\n                return None\n        return None\n\n\ndef classical_baselines(Xtr, ytr, Xte) -> Dict[str, np.ndarray]:\n    from sklearn.linear_model import Ridge\n    from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor\n    out = {}\n    out[\"Ridge\"] = Ridge(alpha=1.0).fit(Xtr, ytr).predict(Xte)\n    out[\"RandomForest\"] = RandomForestRegressor(200, random_state=0, min_samples_leaf=3).fit(Xtr, ytr).predict(Xte)\n    out[\"GradientBoosting\"] = GradientBoostingRegressor(random_state=0).fit(Xtr, ytr).predict(Xte)\n    return out\n\n\ndef qubo_team_allocation(risk: np.ndarray, teams: int, solver: str = \"anneal\", seed: int = 0) -> Tuple[np.ndarray, dict]:\n    \"\"\"Acil müdahale ekiplerini ilçelere atar: max Σ r_i x_i, Σ x_i = teams (QUBO; SA / D-Wave / QAOA).\"\"\"\n    M = len(risk)\n    r = risk / (risk.max() + 1e-9)\n    lam = 2.0\n    Q = np.zeros((M, M))\n    for i in range(M):\n        Q[i, i] = -r[i] + lam * (1 - 2 * teams)\n        for j in range(i + 1, M):\n            Q[i, j] = 2 * lam\n    info = dict(solver=solver, M=M, teams=teams)\n    if solver == \"dwave\":\n        try:\n            import dimod\n            from dwave.system import DWaveSampler, EmbeddingComposite\n            bqm = dimod.BinaryQuadraticModel.from_qubo({(i, j): Q[i, j] for i in range(M) for j in range(i, M) if Q[i, j] != 0})\n            ss = EmbeddingComposite(DWaveSampler()).sample(bqm, num_reads=200)\n            x = np.array([ss.first.sample[i] for i in range(M)]); info[\"note\"] = \"D-Wave QPU\"\n            return x, info\n        except Exception as ex:  # noqa: BLE001\n            info[\"note\"] = f\"D-Wave kullanılamadı ({ex}); SA'ya dönüldü\"\n    if solver == \"qaoa\" and M <= 10:\n        try:\n            import pennylane as qml\n            from pennylane import numpy as pnp\n            Hc = qml.Hamiltonian([], [])\n            coeffs, ops = [], []\n            for i in range(M):\n                coeffs.append(-0.5 * Q[i, i]); ops.append(qml.PauliZ(i))\n                for j in range(i + 1, M):\n                    if Q[i, j] != 0:\n                        coeffs += [0.25 * Q[i, j], -0.25 * Q[i, j], -0.25 * Q[i, j]]\n                        ops += [qml.PauliZ(i) @ qml.PauliZ(j), qml.PauliZ(i), qml.PauliZ(j)]\n            Hc = qml.Hamiltonian(coeffs, ops)\n            Hm = qml.Hamiltonian([1.0] * M, [qml.PauliX(i) for i in range(M)])\n            dev = qml.device(\"default.qubit\", wires=M)\n\n            def layer(g, b):\n                qml.qaoa.cost_layer(g, Hc); qml.qaoa.mixer_layer(b, Hm)\n\n            @qml.qnode(dev)\n            def cost(p):\n                for i in range(M): qml.Hadamard(i)\n                qml.layer(layer, 2, p[0], p[1])\n                return qml.expval(Hc)\n\n            @qml.qnode(dev)\n            def probs(p):\n                for i in range(M): qml.Hadamard(i)\n                qml.layer(layer, 2, p[0], p[1])\n                return qml.probs(wires=range(M))\n            p = pnp.array([[0.5, 0.5], [0.5, 0.5]], requires_grad=True)\n            opt = qml.AdamOptimizer(0.1)\n            for _ in range(40):\n                p = opt.step(cost, p)\n            pr = probs(p); best = int(np.argmax(pr))\n            x = np.array([(best >> (M - 1 - i)) & 1 for i in range(M)]); info[\"note\"] = \"QAOA (2 katman, simülatör)\"\n            return x, info\n        except Exception as ex:  # noqa: BLE001\n            info[\"note\"] = f\"QAOA başarısız ({ex}); SA'ya dönüldü\"\n    # tavlama benzetimi (simulated annealing)\n    rng = np.random.default_rng(seed)\n    x = np.zeros(M, dtype=int); x[rng.choice(M, min(teams, M), replace=False)] = 1\n\n    def energy(v):\n        return float(v @ Q @ v)\n    E = energy(x); T = 1.0\n    for it in range(4000):\n        i = rng.integers(M); y = x.copy(); y[i] ^= 1\n        Ey = energy(y)\n        if Ey < E or rng.random() < math.exp(-(Ey - E) / T):\n            x, E = y, Ey\n        T = max(0.01, T * 0.999)\n    info.setdefault(\"note\", \"Tavlama benzetimi (klasik yedek)\")\n    return x, info\n\n\n# ===========================================================================\n# 6. MONTE CARLO — yağış/CN/Manning belirsizliği → aşılma olasılığı haritaları\n# ===========================================================================\ndef monte_carlo_riverine(rain: pd.Series, area_km2: float, cn: float, tc_h: float, terrain: Terrain,\n                         rating_fn, runs: int = 24, baseflow: float = 0.0, seed: int = 42,\n                         depth_threshold: float = 0.3) -> dict:\n    rng = np.random.default_rng(seed)\n    peaks, stages = [], []\n    exceed = np.zeros(terrain.hand.shape)\n    depth_stack = []\n    for _ in range(runs):\n        mult = float(np.exp(rng.normal(0, 0.25)))\n        cn_i = float(np.clip(cn + rng.normal(0, 4), 35, 99))\n        n_i = float(np.clip(0.045 * np.exp(rng.normal(0, 0.2)), 0.02, 0.12))\n        q = model_scs_uh(rain * mult, area_km2, cn_i, tc_h, baseflow)\n        rating = rating_fn(n_i)\n        st = stage_from_discharge(rating, float(q.max()))\n        d = hand_inundation(terrain, st)\n        exceed += (d > depth_threshold)\n        depth_stack.append(d)\n        peaks.append(float(q.max())); stages.append(st)\n    stack = np.stack(depth_stack)\n    return dict(peaks=np.array(peaks), stages=np.array(stages), exceed_prob=exceed / runs,\n                depth_p50=np.median(stack, 0), depth_p90=np.percentile(stack, 90, 0),\n                summary=dict(peak_p10=float(np.percentile(peaks, 10)), peak_p50=float(np.percentile(peaks, 50)),\n                             peak_p90=float(np.percentile(peaks, 90)), stage_p50=float(np.median(stages)), runs=runs))\n\n\ndef monte_carlo_pluvial(zf: np.ndarray, rain: pd.Series, lc: np.ndarray, dy: float, dx: float, runs: int = 8,\n                        seed: int = 42, depth_threshold: float = 0.2, max_minutes_each: float = 3.0, sewer_mm_h: float = 0.0) -> dict:\n    rng = np.random.default_rng(seed)\n    exceed = np.zeros(zf.shape); stack = []\n    for _ in range(runs):\n        mult = float(np.exp(rng.normal(0, 0.25)))\n        res = pluvial_ca(zf, rain * mult, lc, dy, dx, drain_hours=1.0, max_minutes=max_minutes_each,\n                         manning_scale=float(np.exp(rng.normal(0, 0.15))), infil_scale=float(np.exp(rng.normal(0, 0.3))),\n                         record_every_min=1e9, sewer_mm_h=sewer_mm_h * float(np.exp(rng.normal(0, 0.3))))\n        exceed += res[\"max_depth\"] > depth_threshold; stack.append(res[\"max_depth\"])\n    stack = np.stack(stack)\n    return dict(exceed_prob=exceed / runs, depth_p50=np.median(stack, 0), depth_p90=np.percentile(stack, 90, 0), runs=runs)\n\n# ===========================================================================\n# 7. ETKİ ANALİZİ — nüfus, yapı, arazi örtüsü, hasar, sigorta, risk skoru\n# ===========================================================================\nDEPTH_CLASSES = [(0.1, 0.3, \"0,1–0,3 m (sığ)\"), (0.3, 1.0, \"0,3–1 m (orta)\"), (1.0, 2.0, \"1–2 m (yüksek)\"), (2.0, 99.0, \">2 m (çok yüksek)\")]\n# JRC küresel derinlik-hasar eğrileri (Huizinga ve diğ. 2017) — Avrupa konut/ticari, hasar oranı\n_JRC_DEPTH = np.array([0, 0.5, 1, 1.5, 2, 3, 4, 5, 6])\n_JRC_RES = np.array([0, 0.25, 0.40, 0.50, 0.60, 0.75, 0.85, 0.95, 1.00])\n_JRC_COM = np.array([0, 0.15, 0.30, 0.45, 0.55, 0.75, 0.90, 1.00, 1.00])\n\n\ndef damage_fraction(depth: np.ndarray, kind=\"res\") -> np.ndarray:\n    curve = _JRC_RES if kind == \"res\" else _JRC_COM\n    return np.interp(depth, _JRC_DEPTH, curve)\n\n\ndef impact_assessment(depth: np.ndarray, pop: np.ndarray, lc: np.ndarray, cell_area_m2: float, cfg: RunConfig,\n                      district_labels: Optional[np.ndarray] = None, district_names: Optional[List[str]] = None,\n                      depth_p90: Optional[np.ndarray] = None) -> dict:\n    \"\"\"wet (>0,1 m) alan/arazi istatistikleri için; nüfus/yapı maruziyeti cfg.exposure_depth_m (vars. 0,3 m) eşiğiyle.\"\"\"\n    wet = depth > 0.1\n    exp_m = depth > cfg.exposure_depth_m\n    cls_rows = []\n    for lo, hi, name in DEPTH_CLASSES:\n        m = (depth >= lo) & (depth < hi)\n        cls_rows.append(dict(sinif=name, alan_km2=float(m.sum() * cell_area_m2 / 1e6), nufus=float(pop[m].sum()),\n                             yapilasmis_km2=float(((lc == 50) & m).sum() * cell_area_m2 / 1e6)))\n    classes = pd.DataFrame(cls_rows)\n    lc_rows = [dict(sinif=WorldCoverClient.CLASSES.get(int(c), str(c)), alan_km2=float(((lc == c) & wet).sum() * cell_area_m2 / 1e6))\n               for c in np.unique(lc)]\n    landcover = pd.DataFrame(lc_rows).sort_values(\"alan_km2\", ascending=False)\n    # hasar: yapılaşmış hücrelerde konut/ticari bölünmesi 70/30, taban alanı oranı 0,35\n    built = (lc == 50) & exp_m\n    fp = 0.35 * cell_area_m2\n    res_loss = float((damage_fraction(depth[built], \"res\") * fp * 0.7 * cfg.residential_max_damage_try_m2).sum())\n    com_loss = float((damage_fraction(depth[built], \"com\") * fp * 0.3 * cfg.commercial_max_damage_try_m2).sum())\n    total_loss = res_loss + com_loss\n    pml90 = None\n    if depth_p90 is not None:\n        b90 = (lc == 50) & (depth_p90 > cfg.exposure_depth_m)\n        pml90 = float((damage_fraction(depth_p90[b90], \"res\") * fp * 0.7 * cfg.residential_max_damage_try_m2).sum()\n                      + (damage_fraction(depth_p90[b90], \"com\") * fp * 0.3 * cfg.commercial_max_damage_try_m2).sum())\n    exposed_pop = float(pop[exp_m].sum()); exposed_pop_shallow = float(pop[wet & ~exp_m].sum())\n    buildings_est = float(built.sum() * cell_area_m2 * 0.35 / 120.0)  # ~120 m² ortalama taban alanı\n    # ilçe tablosu\n    districts = None\n    if district_labels is not None and district_names:\n        rows = []\n        for i, name in enumerate(district_names, start=1):\n            m = district_labels == i\n            if not m.any():\n                continue\n            pw = float(pop[m & exp_m].sum()); dmax = float(depth[m].max()) if m.any() else 0.0\n            dmean = float(depth[m & exp_m].mean()) if (m & exp_m).any() else 0.0\n            rows.append(dict(ilce=name, toplam_nufus=float(pop[m].sum()), etkilenen_nufus=pw,\n                             etkilenen_alan_km2=float((m & wet).sum() * cell_area_m2 / 1e6), maks_derinlik_m=dmax,\n                             ort_derinlik_m=dmean, risk_skoru=pw * (0.5 + dmean)))\n        districts = pd.DataFrame(rows).sort_values(\"risk_skoru\", ascending=False).reset_index(drop=True) if rows else None\n    return dict(classes=classes, landcover=landcover, exposed_pop=exposed_pop, exposed_pop_shallow=exposed_pop_shallow,\n                exposure_depth_m=cfg.exposure_depth_m, exposed_area_km2=float(wet.sum() * cell_area_m2 / 1e6),\n                exposed_area_deep_km2=float(exp_m.sum() * cell_area_m2 / 1e6),\n                buildings_est=buildings_est, loss_try=total_loss, res_loss_try=res_loss, com_loss_try=com_loss,\n                insured_try=total_loss * cfg.insurance_penetration, uninsured_try=total_loss * (1 - cfg.insurance_penetration),\n                pml90_try=pml90, districts=districts, max_depth=float(depth.max()))\n\n\ndef warning_level(exposed_pop: float, max_depth: float, mgm_level: str) -> Tuple[str, str]:\n    \"\"\"Motor seviyesi (MGM MeteoUyarı ile birleşik): yesil / sari / turuncu / kirmizi.\"\"\"\n    score = 0\n    if exposed_pop > 500 or max_depth > 0.5: score = 1\n    if exposed_pop > 5000 or max_depth > 1.0: score = 2\n    if exposed_pop > 25000 or max_depth > 2.0: score = 3\n    mgm = {\"none\": 0, \"unknown\": 0, \"yellow\": 1, \"orange\": 2, \"red\": 3}.get(mgm_level, 0)\n    lvl = max(score, mgm)\n    names = {0: (\"yesil\", \"Yeşil — izleme\"), 1: (\"sari\", \"Sarı — dikkat\"), 2: (\"turuncu\", \"Turuncu — hazırlık / kısmi tahliye\"), 3: (\"kirmizi\", \"Kırmızı — acil tahliye\")}\n    return names[lvl]\n\n\n# ===========================================================================\n# 8. EKRANLAR — Acil durum bilgi paylaşımı, sigorta, bildirim merkezi (HTML)\n# ===========================================================================\n_CSS = \"\"\"<style>\n.trf{font-family:Segoe UI,Arial,sans-serif;max-width:1100px;margin:8px 0;color:#1b2430}\n.trf h2{margin:0 0 6px;font-size:20px}.trf .sub{color:#5b6472;font-size:12px;margin-bottom:10px}\n.trf .kpis{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0 14px}\n.trf .kpi{flex:1 1 150px;background:#f4f6f9;border-radius:10px;padding:10px 12px;border-left:5px solid #2b6cb0}\n.trf .kpi b{display:block;font-size:20px}.trf .kpi span{font-size:12px;color:#5b6472}\n.trf table{border-collapse:collapse;width:100%;font-size:13px}.trf th,.trf td{border-bottom:1px solid #e3e7ee;padding:6px 8px;text-align:left}\n.trf th{background:#eef2f7}.trf .lvl{display:inline-block;padding:3px 10px;border-radius:14px;color:#fff;font-weight:600}\n.trf .yesil{background:#2f855a}.trf .sari{background:#d69e2e}.trf .turuncu{background:#dd6b20}.trf .kirmizi{background:#c53030}\n.trf pre{background:#f4f6f9;padding:10px;border-radius:8px;white-space:pre-wrap;font-size:12px}\n</style>\"\"\"\n\n\ndef _fmt_try(v: float) -> str:\n    if v is None: return \"—\"\n    if v >= 1e9: return f\"{v/1e9:,.2f} milyar ₺\"\n    if v >= 1e6: return f\"{v/1e6:,.1f} milyon ₺\"\n    return f\"{v:,.0f} ₺\"\n\n\ndef screen_emergency(res: dict) -> str:\n    imp, cfg = res[\"impact\"], res[\"cfg\"]\n    lvl, lvl_txt = res[\"warning\"]\n    d = imp.get(\"districts\")\n    rows = \"\"\n    if d is not None:\n        alloc = res.get(\"qubo\", {}).get(\"allocation\", {})\n        for _, r in d.head(12).iterrows():\n            team = \"✅ ekip\" if alloc.get(r.ilce) else \"\"\n            rows += f\"<tr><td>{r.ilce}</td><td>{r.etkilenen_nufus:,.0f}</td><td>{r.etkilenen_alan_km2:.2f}</td><td>{r.maks_derinlik_m:.2f}</td><td>{r.risk_skoru:,.0f}</td><td>{team}</td></tr>\"\n    mgm = res.get(\"mgm_alert\", (\"unknown\", \"\"))\n    return f\"\"\"{_CSS}<div class=\"trf\"><h2>🚨 Acil Durum Bilgi Paylaşım Panosu — {res['title']}</h2>\n<div class=\"sub\">{ENGINE_NAME} v{ENGINE_VERSION} · mod: {cfg.mode} · pencere: {cfg.start} → {cfg.end} · üretim: {res['generated']}</div>\n<div class=\"kpis\">\n<div class=\"kpi\"><b><span class=\"lvl {lvl}\">{lvl_txt}</span></b><span>Motor uyarı seviyesi (MGM MeteoUyarı: {mgm[0]})</span></div>\n<div class=\"kpi\"><b>{imp['exposed_pop']:,.0f}</b><span>Etkilenen nüfus (&gt;{imp['exposure_depth_m']:.1f} m, WorldPop 2025) · sığ (&gt;0,1 m): +{imp['exposed_pop_shallow']:,.0f}</span></div>\n<div class=\"kpi\"><b>{imp['exposed_area_km2']:.2f} km²</b><span>Su altında alan (&gt;0,1 m) · {imp['exposed_area_deep_km2']:.2f} km² (&gt;{imp['exposure_depth_m']:.1f} m)</span></div>\n<div class=\"kpi\"><b>{imp['max_depth']:.2f} m</b><span>Maksimum su derinliği</span></div>\n<div class=\"kpi\"><b>{res['hydro'].get('peak_m3s', 0):,.0f} m³/s</b><span>Tepe debi ({res['hydro'].get('best_model','—')})</span></div>\n<div class=\"kpi\"><b>{res.get('qubo',{}).get('teams','—')}</b><span>Atanan müdahale ekibi (QUBO)</span></div>\n</div>\n<table><tr><th>İlçe</th><th>Etkilenen nüfus</th><th>Alan km²</th><th>Maks derinlik m</th><th>Risk skoru</th><th>Ekip</th></tr>{rows}</table>\n<p class=\"sub\">Paylaşım: AFAD İl Müdürlüğü · Valilik / Kaymakamlık · DSİ Bölge · İtfaiye · 112 · Belediye Fen İşleri · Kızılay. Veri kaynakları ve durumları rapor paketindeki <i>provenance.csv</i> dosyasındadır.</p></div>\"\"\"\n\n\ndef screen_insurance(res: dict) -> str:\n    imp, cfg = res[\"impact\"], res[\"cfg\"]\n    mc = res.get(\"mc_summary\", {})\n    return f\"\"\"{_CSS}<div class=\"trf\"><h2>🛡️ Sigorta ve Finansal Etki Panosu — {res['title']}</h2>\n<div class=\"sub\">Derinlik-hasar: JRC (Huizinga 2017) Avrupa eğrileri · maksimum hasar {cfg.residential_max_damage_try_m2:,.0f} ₺/m² konut, {cfg.commercial_max_damage_try_m2:,.0f} ₺/m² ticari · <b>kalibrasyon gerektirir</b></div>\n<div class=\"kpis\">\n<div class=\"kpi\"><b>{_fmt_try(imp['loss_try'])}</b><span>Tahmini doğrudan yapısal hasar</span></div>\n<div class=\"kpi\"><b>{_fmt_try(imp['insured_try'])}</b><span>Sigortalı pay (penetrasyon %{cfg.insurance_penetration*100:.0f})</span></div>\n<div class=\"kpi\"><b>{_fmt_try(imp['uninsured_try'])}</b><span>Sigortasız pay (DASK taşkını kapsamaz)</span></div>\n<div class=\"kpi\"><b>{_fmt_try(imp.get('pml90_try'))}</b><span>PML (Monte Carlo %90)</span></div>\n<div class=\"kpi\"><b>{imp['buildings_est']:,.0f}</b><span>Etkilenen yapı (tahmini)</span></div>\n<div class=\"kpi\"><b>{(f\"{mc.get('peak_p90'):,.0f} m³/s\" if mc.get('peak_p90') else '—')}</b><span>Tepe debi %90 (MC, n={mc.get('runs','—')})</span></div>\n</div>\n<table><tr><th>Derinlik sınıfı</th><th>Alan km²</th><th>Nüfus</th><th>Yapılaşmış km²</th></tr>\n{''.join(f\"<tr><td>{r.sinif}</td><td>{r.alan_km2:.2f}</td><td>{r.nufus:,.0f}</td><td>{r.yapilasmis_km2:.2f}</td></tr>\" for _, r in imp['classes'].iterrows())}</table>\n<p class=\"sub\">Kullanım: reasürans/portföy PML, TARSİM tarım, belediye altyapı bütçesi. Zarar değerleri il bazlı yeniden inşa maliyetleriyle (ÇŞB birim fiyatları) kalibre edilmelidir.</p></div>\"\"\"\n\n\ndef build_notifications(res: dict) -> List[dict]:\n    lvl, lvl_txt = res[\"warning\"]\n    imp, cfg = res[\"impact\"], res[\"cfg\"]\n    d = imp.get(\"districts\")\n    top = \", \".join(d.head(3).ilce.tolist()) if d is not None and len(d) else cfg.il\n    when = cfg.start if cfg.mode == \"historical\" else \"önümüzdeki saatler\"\n    msgs = []\n    sms = f\"[{lvl_txt.split(' — ')[0].upper()}] {cfg.il}: {top} çevresinde taşkın riski ({when}). Dere yataklarından, alt geçitlerden uzak durun. Bilgi: AFAD 122 / 112.\"\n    msgs.append(dict(kanal=\"SMS (halk)\", hedef=\"Etkilenen ilçe sakinleri\", metin=sms[:160]))\n    msgs.append(dict(kanal=\"Cell Broadcast / Uyarı Sistemi\", hedef=f\"{cfg.il} — riskli ilçeler\", metin=f\"AFAD UYARI: {top} için {lvl_txt}. Tahmini etkilenen nüfus {imp['exposed_pop']:,.0f}. Maks derinlik {imp['max_depth']:.1f} m.\"))\n    msgs.append(dict(kanal=\"E-posta (kurumsal)\", hedef=\"Valilik, AFAD İl Md., DSİ Bölge, Belediye, İtfaiye, 112\",\n                     metin=f\"Konu: {res['title']} — {lvl_txt}\\n\\nMotor çıktısı ({res['generated']}): tepe debi {res['hydro'].get('peak_m3s',0):,.0f} m³/s, su altında alan {imp['exposed_area_km2']:.2f} km², etkilenen nüfus {imp['exposed_pop']:,.0f}, öncelikli ilçeler: {top}. Rapor paketi ektedir.\"))\n    msgs.append(dict(kanal=\"WhatsApp Business / Telegram\", hedef=\"Muhtarlar, mahalle afet gönüllüleri\", metin=f\"⚠️ {top}: {lvl_txt}. Riskli sokaklar için harita paketteki 'derinlik_haritasi.png'. Tahliye noktaları: okul/cami bahçeleri (yüksek kot).\"))\n    msgs.append(dict(kanal=\"API (JSON) — belediye/kurum entegrasyonu\", hedef=\"Webhook\", metin=json.dumps(dict(engine=ENGINE_NAME, version=ENGINE_VERSION, level=lvl, il=cfg.il, districts=(d.head(5).ilce.tolist() if d is not None else []),\n                     exposed_pop=round(imp['exposed_pop']), max_depth_m=round(imp['max_depth'], 2), peak_m3s=round(res['hydro'].get('peak_m3s', 0)), generated=res['generated']), ensure_ascii=False)))\n    return msgs\n\n\ndef screen_notifications(res: dict) -> str:\n    rows = \"\".join(f\"<tr><td><b>{m['kanal']}</b><br><span class='sub'>{m['hedef']}</span></td><td><pre>{m['metin']}</pre></td></tr>\" for m in res[\"notifications\"])\n    return f\"\"\"{_CSS}<div class=\"trf\"><h2>📣 Bildirim Merkezi — {res['title']}</h2>\n<div class=\"sub\">Şablonlar otomatik üretilir; gönderim resmî kanallar (AFAD, Valilik, belediye) üzerinden yapılmalıdır. Çalıştırma sıklığı: {res['cfg'].run_frequency}.</div>\n<table><tr><th style=\"width:26%\">Kanal / Hedef</th><th>Mesaj</th></tr>{rows}</table></div>\"\"\"\n\n# ===========================================================================\n# 9. GÖRSELLER ve RAPOR (DOCX + anlatı + paket)\n# ===========================================================================\ndef _extent(bbox):\n    s, w, n, e = bbox\n    return [w, e, s, n]\n\n\ndef _hillshade(z, az=315, alt=45):\n    az, alt = math.radians(az), math.radians(alt)\n    gy, gx = np.gradient(np.nan_to_num(z))\n    slope = np.pi / 2 - np.arctan(np.hypot(gx, gy) / 30)\n    aspect = np.arctan2(-gx, gy)\n    return np.sin(alt) * np.sin(slope) + np.cos(alt) * np.cos(slope) * np.cos(az - aspect)\n\n\ndef make_figures(res: dict, out: Path) -> Dict[str, Path]:\n    import matplotlib\n    matplotlib.use(\"Agg\")\n    import matplotlib.pyplot as plt\n    figs: Dict[str, Path] = {}\n    cfg, bbox = res[\"cfg\"], res[\"cfg\"].bbox\n    ext = _extent(bbox)\n    rain = res[\"rain\"][\"rain\"]\n    # 1 — hiyetograf + hidrograflar\n    fig, ax = plt.subplots(figsize=(10, 5))\n    for name, q in res[\"hydro\"][\"sims\"].items():\n        ax.plot(q.index, q.values, lw=1.6 if name == res[\"hydro\"].get(\"best_model\") else 1.0, label=name)\n    ref = res[\"hydro\"].get(\"reference\")\n    if ref is not None and len(ref):\n        ax.plot(ref.index, ref.values, \"ko\", ms=4, label=\"GloFAS v4 günlük (Open-Meteo)\")\n    ax.set_ylabel(\"Debi (m³/s)\"); ax.set_xlabel(\"Zaman (UTC)\"); ax.legend(fontsize=8, loc=\"upper left\")\n    ax2 = ax.twinx(); ax2.bar(rain.index, rain.values, width=0.03, color=\"#2b6cb0\", alpha=0.5); ax2.invert_yaxis()\n    ax2.set_ylabel(\"Yağış (mm/saat)\")\n    ax.set_title(f\"{res['title']} — yağış-akış modelleri\", fontsize=11); fig.tight_layout()\n    figs[\"hidrograf\"] = out / \"hidrograf.png\"; fig.savefig(figs[\"hidrograf\"], dpi=130); plt.close(fig)\n    # 2 — model skorları\n    met = res[\"hydro\"][\"metrics\"]\n    if \"KGE\" in met:\n        fig, ax = plt.subplots(figsize=(8, 3.8))\n        x = np.arange(len(met)); ax.bar(x - 0.2, met.KGE.fillna(0), 0.4, label=\"KGE\"); ax.bar(x + 0.2, met.NSE.fillna(0), 0.4, label=\"NSE\")\n        ax.set_xticks(x); ax.set_xticklabels(met.model, rotation=20, ha=\"right\", fontsize=8); ax.axhline(0, color=\"k\", lw=0.5)\n        ax.set_ylim(min(-1, float(np.nanmin(met[[\"KGE\", \"NSE\"]].values)) - 0.1), 1.05); ax.legend(); ax.set_title(\"Klasik modellerin GloFAS'a göre uyumu (günlük)\")\n        fig.tight_layout(); figs[\"model_skor\"] = out / \"model_skorlari.png\"; fig.savefig(figs[\"model_skor\"], dpi=130); plt.close(fig)\n\n    def depth_map(arr, title, fname, cmap=\"Blues\", vmax=None, streams=None):\n        fig, ax = plt.subplots(figsize=(8, 7))\n        ax.imshow(_hillshade(res[\"terrain\"].filled if arr.shape == res[\"terrain\"].filled.shape else block_reduce(res[\"terrain\"].filled, arr.shape[0])),\n                  cmap=\"gray\", extent=ext, alpha=0.85)\n        m = np.ma.masked_less_equal(arr, 0.05 if vmax is None or vmax > 1 else 0.02)\n        im = ax.imshow(m, cmap=cmap, extent=ext, vmin=0, vmax=vmax or max(float(np.nanpercentile(arr, 99.5)), 0.5), alpha=0.9)\n        if streams is not None and streams.shape == arr.shape:\n            ax.contour(np.flipud(streams.astype(float)), levels=[0.5], colors=\"#1a365d\", linewidths=0.4, extent=ext, origin=\"lower\")\n        plt.colorbar(im, ax=ax, shrink=0.7, label=\"m\" if vmax is None or vmax > 1 else \"olasılık\")\n        ax.set_title(title); ax.set_xlabel(\"Boylam\"); ax.set_ylabel(\"Enlem\"); fig.tight_layout()\n        p = out / fname; fig.savefig(p, dpi=130); plt.close(fig); return p\n    if res.get(\"depth_riverine\") is not None:\n        figs[\"derinlik_nehir\"] = depth_map(res[\"depth_riverine\"], f\"Nehir taşkını derinliği — HAND (seviye {res['hydro'].get('stage_m', 0):.2f} m)\", \"derinlik_nehir.png\", streams=res[\"terrain\"].streams)\n    if res.get(\"pluvial\") is not None:\n        figs[\"derinlik_pluvyal\"] = depth_map(res[\"pluvial\"][\"max_depth\"], \"Kentsel (plüvyal) taşkın — 2B hücresel otomat maks. derinlik\", \"derinlik_pluvyal.png\", cmap=\"PuBu\")\n    figs[\"derinlik_birlesik\"] = depth_map(res[\"depth\"], \"Birleşik maksimum su derinliği\", \"derinlik_haritasi.png\", streams=res[\"terrain\"].streams)\n    if res.get(\"mc_riv\") is not None:\n        figs[\"asilma\"] = depth_map(res[\"mc_riv\"][\"exceed_prob\"], f\"Monte Carlo — derinlik >0,3 m aşılma olasılığı (n={res['mc_riv']['summary']['runs']})\", \"asilma_olasiligi.png\", cmap=\"YlOrRd\", vmax=1.0)\n    if res.get(\"mc_plu\") is not None:\n        figs[\"asilma_pluvyal\"] = depth_map(res[\"mc_plu\"][\"exceed_prob\"], f\"Monte Carlo (plüvyal) — >0,2 m aşılma olasılığı (n={res['mc_plu']['runs']})\", \"asilma_pluvyal.png\", cmap=\"YlOrRd\", vmax=1.0)\n    if res.get(\"gfm\") is not None:\n        g = res[\"gfm\"]\n        fig, ax = plt.subplots(figsize=(8, 7))\n        ax.imshow(_hillshade(res[\"terrain\"].filled), cmap=\"gray\", extent=ext, alpha=0.85)\n        both = (res[\"depth\"] > 0.1).astype(int) + 2 * (g[\"extent\"] > 0.5).astype(int)\n        cmap = matplotlib.colors.ListedColormap([\"none\", \"#3182ce\", \"#e53e3e\", \"#805ad5\"])\n        ax.imshow(both, cmap=cmap, extent=ext, vmin=0, vmax=3, alpha=0.75)\n        ax.set_title(f\"Doğrulama — mavi: model, kırmızı: Sentinel-1 GFM, mor: örtüşme · CSI={g['csi']:.2f}\")\n        fig.tight_layout(); figs[\"dogrulama\"] = out / \"dogrulama_gfm.png\"; fig.savefig(figs[\"dogrulama\"], dpi=130); plt.close(fig)\n    q = res.get(\"qml\")\n    if q:\n        fig, axs = plt.subplots(1, 2, figsize=(11, 4))\n        axs[0].plot(q[\"history\"]); axs[0].set_title(f\"VQC eğitim kaybı ({q['info'].get('backend')}, {q['info'].get('n_qubits')} kübit)\"); axs[0].set_xlabel(\"adım\")\n        axs[1].plot(q[\"y_test\"].values, \"k-\", lw=1.5, label=\"GloFAS (gerçek)\")\n        for k, v in q[\"preds\"].items():\n            axs[1].plot(v, lw=1, label=f\"{k} (RMSE {q['scores'][k]['RMSE']:.1f})\")\n        axs[1].legend(fontsize=7); axs[1].set_title(\"Test dönemi 1 gün ileri debi tahmini (m³/s)\")\n        fig.tight_layout(); figs[\"qml\"] = out / \"qml_tahmin.png\"; fig.savefig(figs[\"qml\"], dpi=130); plt.close(fig)\n    d = res[\"impact\"].get(\"districts\")\n    if d is not None and len(d):\n        fig, ax = plt.subplots(figsize=(8, 4))\n        top = d.head(10); ax.barh(top.ilce[::-1], top.etkilenen_nufus[::-1], color=\"#c53030\")\n        ax.set_xlabel(\"Etkilenen nüfus\"); ax.set_title(\"İlçelere göre etkilenen nüfus (WorldPop 2025)\"); fig.tight_layout()\n        figs[\"ilce\"] = out / \"ilce_etki.png\"; fig.savefig(figs[\"ilce\"], dpi=130); plt.close(fig)\n    return figs\n\n\ndef narrative(res: dict, lang=\"tr\") -> str:\n    imp, cfg, hy = res[\"impact\"], res[\"cfg\"], res[\"hydro\"]\n    lvl, lvl_txt = res[\"warning\"]\n    if cfg.llm_provider == \"gemini\" and os.environ.get(\"GEMINI_API_KEY\"):\n        try:\n            from google import genai\n            client = genai.Client(api_key=os.environ[\"GEMINI_API_KEY\"])\n            facts = dict(baslik=res[\"title\"], mod=cfg.mode, pencere=f\"{cfg.start}→{cfg.end}\", yagis_toplam_mm=round(float(res[\"rain\"][\"rain\"].sum()), 1),\n                         yagis_kaynak=res[\"rain\"][\"source\"], tepe_debi=round(hy.get(\"peak_m3s\", 0)), en_iyi_model=hy.get(\"best_model\"),\n                         seviye_m=round(hy.get(\"stage_m\", 0), 2), etkilenen_nufus=round(imp[\"exposed_pop\"]), alan_km2=round(imp[\"exposed_area_km2\"], 2),\n                         maks_derinlik=round(imp[\"max_depth\"], 2), hasar_try=round(imp[\"loss_try\"]), uyari=lvl_txt,\n                         ilceler=(imp[\"districts\"].head(5).ilce.tolist() if imp.get(\"districts\") is not None else []),\n                         qml=res.get(\"qml\", {}).get(\"scores\"), mc=res.get(\"mc_summary\"))\n            lang_txt = \"Türkçe\" if lang == \"tr\" else \"İngilizce\"\n            prompt = (f\"Sen bir taşkın risk analistisin. Aşağıdaki simülasyon sonuçlarını {lang_txt} olarak, kamu yöneticilerine yönelik, \"\n                      f\"4 paragraflık sade bir brifing metnine dönüştür (durum, hidrolojik bulgular, etki ve öneriler). Rakam uydurma. JSON: {json.dumps(facts, ensure_ascii=False, default=str)}\")\n            r = client.models.generate_content(model=cfg.gemini_model, contents=prompt)\n            return r.text\n        except Exception as ex:  # noqa: BLE001\n            log.warning(f\"Gemini anlatısı üretilemedi ({ex}); şablon kullanılıyor\")\n    top = \", \".join(imp[\"districts\"].head(3).ilce.tolist()) if imp.get(\"districts\") is not None and len(imp[\"districts\"]) else cfg.il\n    if lang == \"en\":\n        return (f\"{res['title']}: the {ENGINE_NAME} run ({cfg.mode} mode, {cfg.start} to {cfg.end}) used a rainfall input of \"\n                f\"{float(res['rain']['rain'].sum()):.0f} mm ({res['rain']['source']}). The best-fitting classical model ({hy.get('best_model')}) gives a peak discharge of \"\n                f\"{hy.get('peak_m3s', 0):,.0f} m³/s and a river stage of {hy.get('stage_m', 0):.2f} m. Inundation covers {imp['exposed_area_km2']:.2f} km² with a maximum depth of \"\n                f\"{imp['max_depth']:.2f} m; about {imp['exposed_pop']:,.0f} residents are exposed, mostly in {top}. Estimated direct building damage is {_fmt_try(imp['loss_try'])}. \"\n                f\"Engine warning level: {lvl_txt}. Recommended actions: pre-position teams in the priority districts, issue public warnings through official channels, and verify the modelled extent with field reports.\")\n    return (f\"{res['title']} için {ENGINE_NAME} çalıştırması ({cfg.mode} modu, {cfg.start} – {cfg.end}) toplam {float(res['rain']['rain'].sum()):.0f} mm yağış girdisi \"\n            f\"({res['rain']['source']}) kullanmıştır. En iyi uyumu veren klasik model ({hy.get('best_model')}) {hy.get('peak_m3s', 0):,.0f} m³/s tepe debi ve \"\n            f\"{hy.get('stage_m', 0):.2f} m su seviyesi üretmiştir. Taşma alanı {imp['exposed_area_km2']:.2f} km², maksimum derinlik {imp['max_depth']:.2f} m; \"\n            f\"yaklaşık {imp['exposed_pop']:,.0f} kişi etkilenmektedir (öncelikli ilçeler: {top}). Tahmini doğrudan yapısal hasar {_fmt_try(imp['loss_try'])}. \"\n            f\"Motor uyarı seviyesi: {lvl_txt}. Öneriler: öncelikli ilçelerde ekiplerin önceden konuşlandırılması, resmî kanallardan halkın uyarılması ve modellenen \"\n            f\"yayılımın saha bildirimleriyle doğrulanması.\")\n\n\ndef write_docx(res: dict, figs: Dict[str, Path], out: Path, lang=\"tr\") -> Path:\n    from docx import Document\n    from docx.shared import Inches, Pt\n    cfg, imp, hy = res[\"cfg\"], res[\"impact\"], res[\"hydro\"]\n    doc = Document()\n    st = doc.styles[\"Normal\"]; st.font.name = \"Calibri\"; st.font.size = Pt(10.5)\n    T = (lambda tr, en: tr if lang == \"tr\" else en)\n    doc.add_heading(T(f\"{ENGINE_NAME} — Taşkın Simülasyon Raporu\", f\"{ENGINE_NAME} — Flood Simulation Report\"), 0)\n    doc.add_paragraph(f\"{res['title']}\\nBVK Technology · {T('Üretim', 'Generated')}: {res['generated']} · v{ENGINE_VERSION}\")\n    doc.add_heading(T(\"1. Yönetici özeti\", \"1. Executive summary\"), 1)\n    doc.add_paragraph(narrative(res, lang))\n    lvl, lvl_txt = res[\"warning\"]\n    tbl = doc.add_table(rows=0, cols=2); tbl.style = \"Light Grid Accent 1\"\n    for k, v in [(T(\"Mod / kapsam\", \"Mode / scope\"), f\"{cfg.mode} / {cfg.scope}\"), (T(\"Zaman penceresi\", \"Time window\"), f\"{cfg.start} → {cfg.end}\"),\n                 (T(\"Çalışma alanı (S,W,N,E)\", \"Study area (S,W,N,E)\"), \", \".join(f\"{v:.3f}\" for v in cfg.bbox)),\n                 (T(\"Yağış girdisi\", \"Rainfall input\"), f\"{float(res['rain']['rain'].sum()):.1f} mm — {res['rain']['source']}\"),\n                 (T(\"Tepe debi / seviye\", \"Peak discharge / stage\"), f\"{hy.get('peak_m3s', 0):,.0f} m³/s / {hy.get('stage_m', 0):.2f} m ({hy.get('best_model')})\"),\n                 (T(\"Taşma alanı / maks derinlik\", \"Flooded area / max depth\"), f\"{imp['exposed_area_km2']:.2f} km² / {imp['max_depth']:.2f} m\"),\n                 (T(\"Etkilenen nüfus\", \"Exposed population\"), f\"{imp['exposed_pop']:,.0f}\"), (T(\"Tahmini hasar\", \"Estimated damage\"), _fmt_try(imp[\"loss_try\"])),\n                 (T(\"Uyarı seviyesi\", \"Warning level\"), lvl_txt)]:\n        r = tbl.add_row().cells; r[0].text, r[1].text = k, str(v)\n    doc.add_heading(T(\"2. Veri kaynakları ve izlenebilirlik\", \"2. Data sources & provenance\"), 1)\n    prov = res[\"provenance\"]\n    tbl = doc.add_table(rows=1, cols=4); tbl.style = \"Light Grid Accent 1\"\n    for i, h in enumerate([T(\"Katman\", \"Layer\"), T(\"Kaynak\", \"Source\"), T(\"Durum\", \"Status\"), T(\"Detay\", \"Detail\")]): tbl.rows[0].cells[i].text = h\n    for _, r in prov.iterrows():\n        c = tbl.add_row().cells; c[0].text, c[1].text, c[2].text, c[3].text = str(r.katman), str(r.kaynak), str(r.durum), str(r.detay)[:120]\n    doc.add_heading(T(\"3. Yağış ve hidroloji\", \"3. Rainfall & hydrology\"), 1)\n    cat = hy[\"catchment\"]\n    doc.add_paragraph(T(f\"Havza alanı {cat['area_km2']:.1f} km², ana kanal {cat['channel_length_km']:.1f} km, eğim {cat['channel_slope']:.4f}, \"\n                        f\"Kirpich tc {cat['tc_hours']:.2f} saat. Bileşik CN = {hy['cn']:.1f} (hidrolojik toprak grubu {hy['hsg']}, SoilGrids + WorldCover). \"\n                        f\"Modeller ayrı ayrı çalıştırılmış, GloFAS v4 günlük debisi ile karşılaştırılmıştır (GloFAS bir model ürünüdür; DSİ AGİ gözlemi yüklenirse onunla değerlendirilir).\",\n                        f\"Catchment {cat['area_km2']:.1f} km², main channel {cat['channel_length_km']:.1f} km, slope {cat['channel_slope']:.4f}, Kirpich tc {cat['tc_hours']:.2f} h. \"\n                        f\"Composite CN = {hy['cn']:.1f} (HSG {hy['hsg']}). All models run independently and compared with GloFAS v4 daily discharge.\"))\n    met = hy[\"metrics\"]\n    tbl = doc.add_table(rows=1, cols=len(met.columns)); tbl.style = \"Light Grid Accent 1\"\n    for i, h in enumerate(met.columns): tbl.rows[0].cells[i].text = str(h)\n    for _, r in met.iterrows():\n        c = tbl.add_row().cells\n        for i, v in enumerate(r.values): c[i].text = f\"{v:.3f}\" if isinstance(v, float) else str(v)[:19]\n    for key in (\"hidrograf\", \"model_skor\"):\n        if key in figs: doc.add_picture(str(figs[key]), width=Inches(6.2))\n    doc.add_heading(T(\"4. Taşma haritaları\", \"4. Inundation maps\"), 1)\n    plu = res.get(\"pluvial\") or {}\n    doc.add_paragraph(T(f\"Nehir taşkını: HAND ({res['terrain'].hand_source}) + sentetik anahtar eğrisi; kentsel taşkın: 2B ağırlıklı hücresel otomat \"\n                        f\"({plu.get('steps', 0)} adım, {plu.get('runtime_s', 0):.0f} s). Model seçimi: {hy.get('selection_note', '')}\",\n                        \"Riverine: HAND + synthetic rating curve; pluvial: 2-D weighted cellular automaton.\"))\n    for key in (\"derinlik_nehir\", \"derinlik_pluvyal\", \"derinlik_birlesik\", \"dogrulama\"):\n        if key in figs: doc.add_picture(str(figs[key]), width=Inches(5.8))\n    if res.get(\"gfm\") is not None:\n        g = res[\"gfm\"]; doc.add_paragraph(T(f\"Sentinel-1 GFM doğrulaması: isabet {g['hit']:.2f}, yanlış alarm {g['far']:.2f}, CSI {g['csi']:.2f}; S1 taşkın hücresi {g['obs_cells']}, model {g['model_cells']} \"\n                                            f\"(sahneler: {', '.join(g['items'][:3])}). Not: Dar ve dik vadilerde radar taşkın tespiti (gölge/örtme maskesi) çoğu taşmayı yakalayamaz; \"\n                                            f\"düşük CSI tek başına model hatası anlamına gelmez.\",\n                                            f\"Sentinel-1 GFM validation: hit {g['hit']:.2f}, FAR {g['far']:.2f}, CSI {g['csi']:.2f}; S1 flood cells {g['obs_cells']}, model {g['model_cells']}.\"))\n    doc.add_heading(T(\"5. Kuantum katmanı\", \"5. Quantum layer\"), 1)\n    q = res.get(\"qml\")\n    if q:\n        doc.add_paragraph(T(f\"VQC tahmincisi ({q['info']}) günlük 1 gün ileri debi tahmininde test RMSE {q['scores']['QML-VQC']['RMSE']:.1f} m³/s \"\n                            f\"(NSE {q['scores']['QML-VQC']['NSE']:.2f}); klasik referanslar: \" + \", \".join(f\"{k} RMSE {v['RMSE']:.1f}\" for k, v in q[\"scores\"].items() if k != \"QML-VQC\"),\n                            f\"VQC forecaster test RMSE {q['scores']['QML-VQC']['RMSE']:.1f} m³/s vs classical baselines.\"))\n        if \"qml\" in figs: doc.add_picture(str(figs[\"qml\"]), width=Inches(6.2))\n    qb = res.get(\"qubo\")\n    if qb:\n        doc.add_paragraph(T(f\"QUBO ekip tahsisi ({qb['info'].get('note')}): {qb['teams']} ekip → \" + \", \".join(k for k, v in qb[\"allocation\"].items() if v),\n                            f\"QUBO team allocation: {qb['teams']} teams → \" + \", \".join(k for k, v in qb[\"allocation\"].items() if v)))\n    doc.add_heading(T(\"6. Belirsizlik (Monte Carlo)\", \"6. Uncertainty (Monte Carlo)\"), 1)\n    mc = res.get(\"mc_summary\", {})\n    if mc:\n        doc.add_paragraph(T(f\"{mc.get('runs')} çalıştırma; tepe debi P10/P50/P90 = {mc.get('peak_p10', 0):,.0f} / {mc.get('peak_p50', 0):,.0f} / {mc.get('peak_p90', 0):,.0f} m³/s.\",\n                            f\"{mc.get('runs')} runs; peak P10/P50/P90 = {mc.get('peak_p10', 0):,.0f} / {mc.get('peak_p50', 0):,.0f} / {mc.get('peak_p90', 0):,.0f} m³/s.\"))\n    for key in (\"asilma\", \"asilma_pluvyal\"):\n        if key in figs: doc.add_picture(str(figs[key]), width=Inches(5.8))\n    doc.add_heading(T(\"7. Etki, sigorta ve bildirim\", \"7. Impact, insurance & notification\"), 1)\n    tbl = doc.add_table(rows=1, cols=4); tbl.style = \"Light Grid Accent 1\"\n    for i, h in enumerate([T(\"Derinlik sınıfı\", \"Depth class\"), \"km²\", T(\"Nüfus\", \"Population\"), T(\"Yapılaşmış km²\", \"Built-up km²\")]): tbl.rows[0].cells[i].text = h\n    for _, r in imp[\"classes\"].iterrows():\n        c = tbl.add_row().cells; c[0].text, c[1].text, c[2].text, c[3].text = r.sinif, f\"{r.alan_km2:.2f}\", f\"{r.nufus:,.0f}\", f\"{r.yapilasmis_km2:.2f}\"\n    doc.add_paragraph(T(f\"Hasar {_fmt_try(imp['loss_try'])} (konut {_fmt_try(imp['res_loss_try'])}, ticari {_fmt_try(imp['com_loss_try'])}); sigortalı {_fmt_try(imp['insured_try'])}, \"\n                        f\"sigortasız {_fmt_try(imp['uninsured_try'])}; PML90 {_fmt_try(imp.get('pml90_try'))}.\",\n                        f\"Damage {_fmt_try(imp['loss_try'])}; insured {_fmt_try(imp['insured_try'])}; PML90 {_fmt_try(imp.get('pml90_try'))}.\"))\n    if \"ilce\" in figs: doc.add_picture(str(figs[\"ilce\"]), width=Inches(5.8))\n    for m in res[\"notifications\"][:3]:\n        doc.add_paragraph(f\"[{m['kanal']} → {m['hedef']}] {m['metin']}\")\n    doc.add_heading(T(\"8. Sınırlılıklar\", \"8. Limitations\"), 1)\n    doc.add_paragraph(T(\"ERA5/Open-Meteo yağışı konvektif ekstremleri düşük gösterebilir; olaylarda MGM istasyon toplamlarına ölçekleme uygulanmıştır. \"\n                        \"GloFAS gözlem değil model ürünüdür. HAND yöntemi hidrodinamik model (HEC-RAS 2D, LISFLOOD-FP) yerine hızlı tarama içindir; hücresel otomat \"\n                        \"kanalizasyon kapasitesini temsil etmez. Hasar eğrileri ve birim maliyetler yerel verilerle kalibre edilmelidir. Copernicus 30 m DEM kentsel mikro-topografyayı çözemez; \"\n                        \"HGM 12 m SYM (kamu kurumları için ücretsiz) ile değiştirilmesi önerilir.\",\n                        \"ERA5 underestimates convective extremes; GloFAS is a model, not observation; HAND/CA are screening tools; damage curves need local calibration; \"\n                        \"30 m DEM cannot resolve urban micro-topography — HGM 12 m DSM recommended for public bodies.\"))\n    p = out / (f\"TRFlood_Rapor_{slugify(res['title'])}.docx\" if lang == \"tr\" else f\"TRFlood_Report_{slugify(res['title'])}.docx\")\n    doc.save(p)\n    return p\n\n\n# ===========================================================================\n# 10. BORU HATTI — uçtan uca çalıştırma\n# ===========================================================================\ndef _rain_index(start: str, hours: int, dt_h: float = 1.0) -> pd.DatetimeIndex:\n    return pd.date_range(pd.Timestamp(start, tz=\"UTC\"), periods=int(hours / dt_h), freq=f\"{int(dt_h*60)}min\")\n\n\ndef acquire_terrain(cfg: RunConfig, prov: Provenance) -> Tuple[Terrain, np.ndarray, bool]:\n    \"\"\"DEM (Copernicus GLO-30) + arazi örtüsü (WorldCover) → su maskesi ile arazi analizi. (terrain, lc, synthetic)\"\"\"\n    lat_c, _ = cfg.center\n    synthetic = False\n    try:\n        dem, tr = CopernicusDEM().read(cfg.bbox, \"DEM\", max_px=cfg.grid_max)\n        prov.add(\"DEM\", \"Copernicus GLO-30 (AWS, 1\\\")\", \"ok\", f\"ızgara {dem.shape}, ~{abs(tr.a)*111320*math.cos(math.radians(lat_c)):.0f} m\")\n    except Exception as ex:  # noqa: BLE001\n        prov.add(\"DEM\", \"Copernicus GLO-30\", \"sentetik\", f\"okunamadı: {str(ex)[:80]}\")\n        dem, tr = synthetic_dem(cfg.bbox, n=min(cfg.grid_max, 200), seed=cfg.seed); synthetic = True\n    lc = None\n    if not synthetic:\n        try:\n            lc = WorldCoverClient().read_to_grid(cfg.bbox, dem.shape)\n            prov.add(\"Arazi örtüsü\", \"ESA WorldCover 10 m (2021, CC BY 4.0)\", \"ok\", f\"yapılaşmış %{(lc == 50).mean()*100:.1f}, su %{(lc == 80).mean()*100:.1f}\")\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Arazi örtüsü\", \"ESA WorldCover\", \"sentetik\", str(ex)[:80])\n    if lc is None:\n        lc = synthetic_landcover(dem, cfg.seed)\n    stream_area = 1.0 if bbox_area_km2(cfg.bbox) > 300 else 0.3\n    terrain = build_terrain(dem, tr, lat_c, stream_area_km2=stream_area, water_mask=(lc == 80))\n    prov.add(\"HAND\", terrain.hand_source, \"ok\", f\"dere hücresi {int(terrain.streams.sum())}, kara %{terrain.valid.mean()*100:.0f}\")\n    return terrain, lc, synthetic\n\n\ndef acquire_layers(cfg: RunConfig, prov: Provenance, terrain: Terrain, lc: np.ndarray, synthetic: bool) -> dict:\n    shape = terrain.dem.shape\n    pop = None\n    if not synthetic:\n        try:\n            pop = WorldPopClient().read_to_grid(cfg.bbox, shape); prov.add(\"Nüfus\", \"WorldPop TUR 2025 100 m (R2024B)\", \"ok\", f\"toplam {pop.sum():,.0f}\")\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Nüfus\", \"WorldPop\", \"sentetik\", str(ex)[:80])\n    if pop is None:\n        pop = synthetic_population(lc, cfg.seed)\n    labels, names = None, None\n    try:\n        feats = GeoBoundariesClient().features_in_bbox(cfg.bbox, \"ADM2\")\n        if feats:\n            labels = rasterize_features(feats, terrain.transform, shape); names = [f[\"name\"] for f in feats]\n            prov.add(\"İdari sınır\", \"geoBoundaries TUR ADM2 (ODbL)\", \"ok\", f\"{len(feats)} ilçe\")\n    except Exception as ex:  # noqa: BLE001\n        prov.add(\"İdari sınır\", \"geoBoundaries\", \"yok\", str(ex)[:80])\n    hsg, soil = \"B\", {}\n    try:\n        hsg, soil = SoilGridsClient().hsg(*cfg.center); prov.add(\"Toprak\", \"ISRIC SoilGrids v2\", \"ok\", f\"HSG {hsg} {soil}\")\n    except Exception as ex:  # noqa: BLE001\n        prov.add(\"Toprak\", \"SoilGrids\", \"varsayılan B\", str(ex)[:80])\n    return dict(lc=lc, pop=pop, labels=labels, names=names, hsg=hsg, soil=soil)\n\n\ndef acquire_rainfall(cfg: RunConfig, prov: Provenance, lat: float, lon: float) -> dict:\n    om = OpenMeteoClient()\n    ev = EVENTS.get(cfg.event_key) if cfg.scope == \"event\" else None\n    out: dict = dict(checks={}, source=\"\", scale=1.0)\n    rain = temp = None\n    if cfg.mode == \"historical\":\n        s = (pd.Timestamp(cfg.start) - pd.Timedelta(days=2)).date().isoformat()\n        e = (pd.Timestamp(cfg.end) + pd.Timedelta(days=2)).date().isoformat()\n        try:\n            h = om.archive_hourly(lat, lon, s, e)\n            rain = h[\"precipitation\"].fillna(0.0); temp = h[\"temperature_2m\"].ffill().fillna(15.0)\n            prov.add(\"Yağış\", \"Open-Meteo arşiv (ERA5/ERA5-Land)\", \"ok\", f\"{s}→{e}, toplam {rain.sum():.1f} mm\")\n            out[\"source\"] = \"Open-Meteo/ERA5 saatlik\"\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Yağış\", \"Open-Meteo arşiv\", \"sentetik\", str(ex)[:80])\n        try:  # CHIRPS kontrolü (en fazla 3 gün)\n            days = pd.date_range(cfg.start, cfg.end)[:3]\n            vals = [CHIRPSClient().daily_mean_mm(cfg.bbox, d.date()) for d in days]\n            vals = [v for v in vals if v is not None]\n            if vals:\n                out[\"checks\"][\"CHIRPS_gunluk_ort_mm\"] = round(float(np.nansum(vals)), 1)\n                prov.add(\"Yağış kontrol\", \"CHIRPS v2.0 0,05°\", \"ok\", f\"olay günleri toplam {np.nansum(vals):.1f} mm\")\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Yağış kontrol\", \"CHIRPS\", \"yok\", str(ex)[:60])\n        if (pd.Timestamp.utcnow().tz_localize(None) - pd.Timestamp(cfg.end)).days <= 6:\n            try:\n                st = MGMClient().toplam_yagis_bbox(cfg.end, cfg.bbox)\n                if len(st):\n                    out[\"checks\"][\"MGM_istasyon_maks_mm\"] = float(st.yagis_mm.max()); prov.add(\"Yağış kontrol\", \"MGM AWOS 24 s toplam\", \"ok\", f\"{len(st)} istasyon, maks {st.yagis_mm.max():.1f} mm\")\n            except Exception as ex:  # noqa: BLE001\n                prov.add(\"Yağış kontrol\", \"MGM toplamyagis\", \"yok\", str(ex)[:60])\n    else:\n        try:\n            f = om.forecast_hourly(lat, lon, days=cfg.forecast_days if cfg.mode == \"forecast\" else 2, past_days=1 if cfg.mode == \"forecast\" else 3)\n            rain = f[\"precipitation\"].fillna(0.0); temp = f[\"temperature_2m\"].ffill().fillna(15.0)\n            out[\"prob\"] = f.get(\"precipitation_probability\")\n            prov.add(\"Yağış\", \"Open-Meteo tahmin (best_match: ICON/GFS/ECMWF)\", \"ok\", f\"toplam {rain.sum():.1f} mm, {len(rain)} saat\")\n            out[\"source\"] = \"Open-Meteo çok-modelli tahmin\" if cfg.mode == \"forecast\" else \"Open-Meteo analiz+tahmin (nowcast)\"\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Yağış\", \"Open-Meteo tahmin\", \"sentetik\", str(ex)[:80])\n        try:\n            mgm = MGMClient()\n            loc = mgm.merkez_lokasyon(lat, lon)\n            if loc.get(\"sondurumIstNo\"):\n                sd = mgm.sondurum(loc[\"merkezId\"])\n                out[\"checks\"][\"MGM_sondurum\"] = {k: sd.get(k) for k in (\"veriZamani\", \"yagis1Saat\", \"yagis6Saat\", \"yagis12Saat\", \"yagis24Saat\", \"sicaklik\")}\n                prov.add(\"Gözlem\", f\"MGM AWOS {loc.get('ilce')} ({loc.get('sondurumIstNo')})\", \"ok\", f\"24 s {sd.get('yagis24Saat')} mm\")\n            if loc.get(\"gunlukTahminIstNo\"):\n                out[\"checks\"][\"MGM_gunluk_tahmin\"] = mgm.tahmin_gunluk(loc[\"gunlukTahminIstNo\"])\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Gözlem\", \"MGM sondurum\", \"yok\", str(ex)[:60])\n    if rain is None:\n        total = (ev or {}).get(\"yagis_mm\") or 120.0\n        hours = max(int(round((ev or {}).get(\"yagis_sure_saat\") or 24)), 1)\n        core = scs_type2_hyetograph(total, hours)\n        start0 = pd.Timestamp(cfg.start or date.today().isoformat(), tz=\"UTC\") - pd.Timedelta(days=1)\n        idx = pd.date_range(start0, periods=hours + 72, freq=\"h\")\n        rain = pd.Series(0.0, index=idx, name=\"precipitation\")\n        peak_ts = pd.Timestamp(ev[\"tepe_saat_utc\"], tz=\"UTC\") if ev and ev.get(\"tepe_saat_utc\") else start0 + pd.Timedelta(hours=36)\n        first = (peak_ts - pd.Timedelta(hours=hours / 2)).floor(\"h\")\n        for k, v in enumerate(core.values):\n            ts = first + pd.Timedelta(hours=k)\n            if ts in rain.index:\n                rain[ts] = v\n        temp = pd.Series(18.0, index=rain.index); out[\"source\"] = f\"Sentetik SCS Tip-II hiyetografı ({total} mm / {hours} s, {(ev or {}).get('yagis_kaynak', 'varsayılan')})\"\n    out[\"rain_raw\"] = rain.copy()\n    # Olay ölçekleme: ERA5 konvektif ekstremleri düşük gösterir → MGM istasyon toplamına ölçekle\n    if ev and ev.get(\"yagis_mm\") and cfg.mode == \"historical\" and \"Sentetik\" not in out[\"source\"]:\n        w0 = pd.Timestamp(cfg.start, tz=\"UTC\"); w1 = pd.Timestamp(cfg.end, tz=\"UTC\") + pd.Timedelta(days=1)\n        win = (rain.index >= w0) & (rain.index < w1)\n        tot = float(rain[win].sum())\n        out[\"checks\"][\"ERA5_olay_toplam_mm\"] = round(tot, 1); out[\"checks\"][\"MGM_rapor_mm\"] = ev[\"yagis_mm\"]\n        if tot < max(0.12 * ev[\"yagis_mm\"], 10.0):\n            # ERA5 olayı neredeyse görmemiş (<%12) → raporlanan toplam/süre ile olay hiyetografı yerleştirilir;\n            # aksi halde ERA5 zamansal deseni korunup MGM toplamına ölçeklenir\n            hours = max(int(round(ev.get(\"yagis_sure_saat\") or 24)), 1)\n            core = scs_type2_hyetograph(ev[\"yagis_mm\"], hours)\n            peak_ts = pd.Timestamp(ev[\"tepe_saat_utc\"], tz=\"UTC\") if ev.get(\"tepe_saat_utc\") else rain[win].idxmax()\n            start_ts = (peak_ts - pd.Timedelta(hours=hours / 2)).floor(\"h\")\n            rain = rain.copy(); rain[win] = 0.0\n            idx = pd.date_range(start_ts, periods=hours, freq=\"h\")\n            for ts, v in zip(idx, core.values):\n                if ts in rain.index:\n                    rain[ts] = v\n            out[\"scale\"] = None\n            out[\"source\"] = f\"ERA5 arka plan + MGM olay hiyetografı ({ev['yagis_mm']} mm / {hours} s, SCS Tip-II)\"\n            prov.add(\"Yağış olay hiyetografı\", ev[\"yagis_kaynak\"], \"uygulandı\", f\"ERA5 olay penceresi {tot:.0f} mm → {ev['yagis_mm']} mm / {hours} s\")\n        elif tot < 0.75 * ev[\"yagis_mm\"]:\n            k = ev[\"yagis_mm\"] / tot\n            rain = rain.copy(); rain[win] = rain[win] * k; out[\"scale\"] = round(k, 2)\n            out[\"source\"] += f\" × {k:.2f} (MGM istasyon toplamı {ev['yagis_mm']} mm'ye ölçekli)\"\n            prov.add(\"Yağış ölçekleme\", ev[\"yagis_kaynak\"], \"uygulandı\", f\"ERA5 {tot:.0f} mm → {ev['yagis_mm']} mm\")\n    out[\"rain\"] = rain; out[\"temp\"] = temp\n    return out\n\n\ndef locate_glofas_river_cell(om: \"OpenMeteoClient\", lat: float, lon: float, radius_deg: float = 0.05) -> Tuple[float, float, float]:\n    \"\"\"GloFAS 0,05° ızgarasında çıkış noktası çevresindeki 3×3 hücreyi yoklar; en yüksek ortalama debili hücreyi\n    (ana akarsu) döndürür. Open-Meteo memba alanını vermediği için bu dolaylı seçim kullanılır.\"\"\"\n    best = (lat, lon, -1.0)\n    for dlat in (-radius_deg, 0.0, radius_deg):\n        for dlon in (-radius_deg, 0.0, radius_deg):\n            try:\n                d = om.flood_daily(lat + dlat, lon + dlon, past_days=30, forecast_days=1, model=\"seamless_v4\")\n                m = float(d[\"river_discharge\"].mean())\n                if m > best[2]:\n                    best = (lat + dlat, lon + dlon, m)\n            except Exception:  # noqa: BLE001\n                continue\n    return best\n\n\ndef acquire_discharge(cfg: RunConfig, prov: Provenance, lat: float, lon: float) -> dict:\n    om = OpenMeteoClient(); out: dict = {}\n    glat, glon, gmean = locate_glofas_river_cell(om, lat, lon)\n    out[\"glofas_point\"] = (glat, glon)\n    if gmean >= 0:\n        prov.add(\"GloFAS hücre seçimi\", \"Open-Meteo Flood API 3×3 yoklama\", \"ok\", f\"({glat:.3f}, {glon:.3f}) ort. {gmean:.1f} m³/s\")\n    lat, lon = glat, glon\n    try:\n        if cfg.mode == \"historical\":\n            s = (pd.Timestamp(cfg.start) - pd.Timedelta(days=10)).date().isoformat(); e = (pd.Timestamp(cfg.end) + pd.Timedelta(days=5)).date().isoformat()\n            d = om.flood_daily(lat, lon, start=s, end=e, model=\"consolidated_v4\")\n        else:\n            d = om.flood_daily(lat, lon, past_days=30, forecast_days=max(cfg.forecast_days, 3), model=\"seamless_v4\")\n        out[\"reference\"] = d[\"river_discharge\"]\n        out[\"baseflow\"] = float(d[\"river_discharge\"].iloc[:5].mean())\n        prov.add(\"Nehir debisi\", \"GloFAS v4 (Open-Meteo Flood API)\", \"ok\", f\"{len(d)} gün, maks {d.river_discharge.max():.1f} m³/s\")\n    except Exception as ex:  # noqa: BLE001\n        out[\"reference\"] = None; out[\"baseflow\"] = 0.5\n        prov.add(\"Nehir debisi\", \"Open-Meteo Flood API\", \"yok\", str(ex)[:80])\n    # QML eğitim serisi: 3 yıl günlük yağış + GloFAS\n    try:\n        e = (pd.Timestamp(cfg.end) if cfg.mode == \"historical\" else pd.Timestamp.utcnow().tz_localize(None)) - pd.Timedelta(days=8)\n        s = e - pd.Timedelta(days=3 * 365)\n        pr = om.archive_daily(lat, lon, s.date().isoformat(), e.date().isoformat())[\"precipitation_sum\"]\n        q = om.flood_daily(lat, lon, start=s.date().isoformat(), end=e.date().isoformat(), model=\"consolidated_v4\")[\"river_discharge\"]\n        out[\"train_rain\"], out[\"train_q\"] = pr, q\n        prov.add(\"QML eğitim serisi\", \"Open-Meteo arşiv + GloFAS consolidated\", \"ok\", f\"{len(q)} gün\")\n    except Exception as ex:  # noqa: BLE001\n        prov.add(\"QML eğitim serisi\", \"Open-Meteo\", \"sentetik\", str(ex)[:80])\n        idx = pd.date_range(\"2023-01-01\", periods=900, freq=\"D\", tz=\"UTC\"); rng = np.random.default_rng(cfg.seed)\n        pr = pd.Series(np.maximum(rng.gamma(0.4, 6.0, 900) * (1 + 0.6 * np.sin(2 * np.pi * np.arange(900) / 365)), 0), index=idx)\n        q = pd.Series(np.convolve(pr.values, np.exp(-np.arange(12) / 3.0))[:900] * 0.8 + 3, index=idx)\n        out[\"train_rain\"], out[\"train_q\"] = pr, q\n    return out\n\n\ndef run_pipeline(cfg: RunConfig, progress=None) -> dict:\n    \"\"\"Tüm katmanları çalıştırır; sözlük döndürür ve rapor paketini out_dir altına yazar.\"\"\"\n    t0 = time.time()\n    cfg.resolve()\n    np.random.seed(cfg.seed)\n    prov = Provenance()\n    out = Path(cfg.out_dir) / f\"{slugify(cfg.event_key if cfg.scope == 'event' else cfg.il)}_{cfg.mode}_{datetime.utcnow():%Y%m%d_%H%M}\"\n    out.mkdir(parents=True, exist_ok=True)\n    title = EVENTS[cfg.event_key][\"ad\"] if cfg.scope == \"event\" else f\"{cfg.il} — {cfg.mode}\"\n    res: dict = dict(cfg=cfg, title=title, generated=datetime.utcnow().strftime(\"%Y-%m-%d %H:%M UTC\"), out_dir=out)\n    say = progress or (lambda m: log.info(m))\n\n    say(\"1/8 Arazi: DEM + arazi örtüsü + HAND\"); terrain, lc, synthetic = acquire_terrain(cfg, prov); res[\"terrain\"] = terrain\n    say(\"2/8 Katmanlar: nüfus, ilçe sınırları, toprak\"); lay = acquire_layers(cfg, prov, terrain, lc, synthetic)\n    cat = terrain.catchment_props()\n    oi, oj = cat[\"outlet_rc\"]; olon = terrain.transform.c + (oj + 0.5) * terrain.transform.a; olat = terrain.transform.f + (oi + 0.5) * terrain.transform.e\n    cat[\"outlet_latlon\"] = (float(olat), float(olon))\n    lat_c, lon_c = cfg.center\n    say(\"3/8 Yağış ve gözlemler\"); rain = acquire_rainfall(cfg, prov, lat_c, lon_c); res[\"rain\"] = rain\n    say(\"4/8 Nehir debisi (GloFAS) ve eğitim serileri\"); dis = acquire_discharge(cfg, prov, olat, olon)\n    # MGM uyarı seviyesi (bugün) — nowcast/forecast'ta ana sinyal, historical'da bilgi\n    mgm_level = (\"unknown\", \"\")\n    try:\n        ilceler = MGMClient().ilceler(cfg.il)\n        mgm_level = MGMClient().uyari_seviyesi(ilceler.merkezId.tolist()) if len(ilceler) else (\"none\", \"\")\n        prov.add(\"MeteoUyarı\", \"MGM meteoalarm/today\", \"ok\", f\"{cfg.il}: {mgm_level[0]}\")\n    except Exception as ex:  # noqa: BLE001\n        prov.add(\"MeteoUyarı\", \"MGM\", \"yok\", str(ex)[:60])\n    res[\"mgm_alert\"] = mgm_level\n\n    # ---- hidroloji\n    say(\"5/8 Hidroloji: 5 klasik model + GR4J\")\n    cn_mean, cn_grid = composite_cn(lay[\"lc\"], lay[\"hsg\"], amc=\"III\" if cfg.mode == \"historical\" else \"II\")\n    r = rain[\"rain\"]; temp = rain[\"temp\"].reindex(r.index).ffill().fillna(15.0)\n    daily_rain = r.resample(\"1D\").sum()\n    sims = run_classical_models(r, cat[\"area_km2\"], cn_mean, cat[\"tc_hours\"], pet_mm_h=0.15, temp_c=temp.values,\n                                baseflow=dis[\"baseflow\"], daily_rain=daily_rain)\n    metrics = evaluate_models(sims, dis.get(\"reference\"))\n    peaks = {k: float(q.max()) for k, q in sims.items()}\n    peak_med = float(np.median(list(peaks.values())))\n    ref = dis.get(\"reference\")\n    ref_peak = float(ref.max()) if ref is not None and len(ref) else None\n    if \"KGE\" in metrics and metrics.KGE.notna().any() and ref_peak and 0.2 < ref_peak / max(peak_med, 1e-6) < 5:\n        best = metrics.iloc[0][\"model\"]; sel_note = \"KGE sıralaması (GloFAS günlük referans)\"\n    else:\n        best = \"SCS-CN + SCS UH\"\n        sel_note = (\"GloFAS tepe değeri (%s m³/s) model medyanıyla (%s m³/s) tutarsız — 5 km GloFAS ızgarası küçük/dik havzaları çözemez; \"\n                    \"DSİ uygulamasına uygun olarak olay tabanlı SCS-CN + sentetik birim hidrograf esas alındı. DSİ AGİ gözlemi yüklenirse sıralama gözleme göre yapılır.\"\n                    % (f\"{ref_peak:.1f}\" if ref_peak else \"yok\", f\"{peak_med:.0f}\"))\n    q_best = sims[best]; peak = float(q_best.max())\n    hydro = dict(sims=sims, metrics=metrics, best_model=best, selection_note=sel_note, peak_m3s=peak, peak_median_m3s=peak_med, catchment=cat,\n                 cn=cn_mean, hsg=lay[\"hsg\"], reference=dis.get(\"reference\"), baseflow=dis[\"baseflow\"], glofas_point=dis.get(\"glofas_point\"))\n    res[\"hydro\"] = hydro\n\n    # ---- taşma\n    say(\"6/8 Taşma: HAND nehir taşkını + 2B plüvyal otomat + Monte Carlo\")\n    depth_riv = None; depth = np.zeros(terrain.dem.shape, dtype=\"float32\")\n    rating_fn = lambda n: synthetic_rating_curve(terrain, cat[\"channel_slope\"], manning_n=n)  # noqa: E731\n    if cfg.flood_type in (\"riverine\", \"both\"):\n        rating = rating_fn(0.045); stage = stage_from_discharge(rating, peak)\n        depth_riv = hand_inundation(terrain, stage); hydro[\"stage_m\"] = stage; hydro[\"rating\"] = rating\n        depth = np.maximum(depth, depth_riv)\n        res[\"mc_riv\"] = monte_carlo_riverine(r, cat[\"area_km2\"], cn_mean, cat[\"tc_hours\"], terrain, rating_fn, runs=cfg.mc_runs,\n                                             baseflow=dis[\"baseflow\"], seed=cfg.seed)\n        res[\"mc_summary\"] = res[\"mc_riv\"][\"summary\"]\n    res[\"depth_riverine\"] = depth_riv\n    plu = None\n    if cfg.flood_type in (\"pluvial\", \"both\"):\n        zf_p = block_reduce(terrain.filled, cfg.pluvial_grid_max)\n        lc_p = _fit_shape(lay[\"lc\"], zf_p.shape)\n        fac = terrain.filled.shape[0] / zf_p.shape[0]\n        # olay penceresi: en yağışlı 12 saat + 2 saat boşaltım\n        wlen = min(12, len(r)); roll = r.rolling(wlen, min_periods=1).sum(); c_end = roll.idxmax()\n        win = r[(r.index > c_end - pd.Timedelta(hours=wlen)) & (r.index <= c_end)]\n        if len(win) == 0 or win.sum() < 1:\n            win = r.iloc[:wlen]\n        plu = pluvial_ca(zf_p, win, lc_p, terrain.dy_m * fac, terrain.dx_m * fac, drain_hours=2.0, max_minutes=8.0, sewer_mm_h=cfg.sewer_capacity_mm_h)\n        plu[\"grid_shape\"] = zf_p.shape; plu[\"window\"] = (str(win.index[0]), str(win.index[-1]), float(win.sum()))\n        depth = np.maximum(depth, _fit_shape(plu[\"max_depth\"], depth.shape))\n        zf_mc = block_reduce(terrain.filled, cfg.mc_grid_max); fac_mc = terrain.filled.shape[0] / zf_mc.shape[0]\n        res[\"mc_plu\"] = monte_carlo_pluvial(zf_mc, win, _fit_shape(lay[\"lc\"], zf_mc.shape), terrain.dy_m * fac_mc, terrain.dx_m * fac_mc,\n                                            runs=max(4, cfg.mc_runs // 4), seed=cfg.seed, sewer_mm_h=cfg.sewer_capacity_mm_h)\n        if \"mc_summary\" not in res:\n            res[\"mc_summary\"] = dict(runs=res[\"mc_plu\"][\"runs\"], peak_p10=0, peak_p50=0, peak_p90=0)\n    res[\"pluvial\"] = plu; res[\"depth\"] = depth\n    # GFM doğrulaması\n    res[\"gfm\"] = None\n    if cfg.mode == \"historical\" and (EVENTS.get(cfg.event_key, {}).get(\"gfm_kontrol\") if cfg.scope == \"event\" else True) and not synthetic:\n        try:\n            g = GFMClient().flood_extent_to_grid(cfg.bbox, cfg.start, (pd.Timestamp(cfg.end) + pd.Timedelta(days=4)).date().isoformat(), depth.shape)\n            if g:\n                ext, items = g; mod = depth > 0.1; obs = ext > 0.5\n                hit = float((mod & obs).sum() / max(obs.sum(), 1)); far = float((mod & ~obs).sum() / max(mod.sum(), 1))\n                csi = float((mod & obs).sum() / max((mod | obs).sum(), 1))\n                res[\"gfm\"] = dict(extent=ext, items=items, hit=hit, far=far, csi=csi, obs_cells=int(obs.sum()), model_cells=int(mod.sum()))\n                prov.add(\"Doğrulama\", \"CEMS GFM Sentinel-1 taşkın yayılımı (EODC)\", \"ok\", f\"{len(items)} sahne, S1 {int(obs.sum())} hücre, CSI {csi:.2f}\")\n            else:\n                prov.add(\"Doğrulama\", \"CEMS GFM\", \"sahne yok\", \"olay penceresinde Sentinel-1 geçişi bulunamadı\")\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"Doğrulama\", \"CEMS GFM\", \"yok\", str(ex)[:80])\n\n    # ---- kuantum\n    say(\"7/8 Kuantum: VQC tahmin + QUBO ekip tahsisi\")\n    res[\"qml\"] = None\n    if cfg.quantum_backend != \"none\":\n        try:\n            X, y = build_forecast_dataset(dis[\"train_rain\"], dis[\"train_q\"])\n            n_te = max(30, int(len(X) * 0.2)); Xtr, Xte, ytr, yte = X.iloc[:-n_te], X.iloc[-n_te:], y.iloc[:-n_te], y.iloc[-n_te:]\n            qf = QMLForecaster(cfg.n_qubits, cfg.qml_layers, cfg.qml_epochs, cfg.quantum_backend, cfg.seed).fit(Xtr, ytr)\n            preds = {\"QML-VQC\": qf.predict(Xte)}; preds.update(classical_baselines(Xtr, ytr, Xte))\n            scores = {k: dict(RMSE=float(np.sqrt(np.mean((v - yte.values) ** 2))), NSE=nse(yte.values, v)) for k, v in preds.items()}\n            hw = qf.predict_hardware(Xte) if cfg.quantum_backend in (\"ibm\", \"origin\") else None\n            if hw is not None:\n                scores[\"QML-VQC (donanım)\"] = dict(RMSE=float(np.sqrt(np.mean((hw - yte.values[: len(hw)]) ** 2))), NSE=nse(yte.values[: len(hw)], hw))\n            res[\"qml\"] = dict(history=qf.history, preds=preds, scores=scores, y_test=yte, info=qf.info, next_day=float(preds[\"QML-VQC\"][-1]), hw_preds=hw)\n            prov.add(\"QML\", f\"PennyLane VQC ({qf.info.get('backend')})\", \"ok\", f\"test RMSE {scores['QML-VQC']['RMSE']:.1f}\")\n        except Exception as ex:  # noqa: BLE001\n            prov.add(\"QML\", \"PennyLane\", \"hata\", str(ex)[:100])\n    # ---- etki\n    say(\"8/8 Etki, ekranlar, rapor\")\n    mc90 = res[\"mc_riv\"][\"depth_p90\"] if res.get(\"mc_riv\") else (_fit_shape(res[\"mc_plu\"][\"depth_p90\"], depth.shape) if res.get(\"mc_plu\") else None)\n    imp = impact_assessment(depth, lay[\"pop\"], lay[\"lc\"], terrain.dy_m * terrain.dx_m, cfg, lay[\"labels\"], lay[\"names\"], mc90)\n    res[\"impact\"] = imp\n    res[\"warning\"] = warning_level(imp[\"exposed_pop\"], imp[\"max_depth\"], mgm_level[0])\n    res[\"qubo\"] = None\n    if cfg.qubo_solver != \"none\" and imp.get(\"districts\") is not None and len(imp[\"districts\"]) >= 2:\n        d = imp[\"districts\"]; teams = int(np.clip(math.ceil(len(d) / 3), 1, 6))\n        x, info = qubo_team_allocation(d.risk_skoru.values, teams, solver=cfg.qubo_solver, seed=cfg.seed)\n        res[\"qubo\"] = dict(teams=int(x.sum()), allocation=dict(zip(d.ilce, x.tolist())), info=info)\n    res[\"notifications\"] = build_notifications(res)\n    res[\"provenance\"] = prov.frame()\n    # ---- çıktılar\n    figs = make_figures(res, out); res[\"figures\"] = figs\n    for lang in ([\"tr\", \"en\"] if cfg.report_lang == \"both\" else [cfg.report_lang]):\n        res.setdefault(\"reports\", []).append(write_docx(res, figs, out, lang))\n    (out / \"acil_durum_panosu.html\").write_text(screen_emergency(res), encoding=\"utf-8\")\n    (out / \"sigorta_panosu.html\").write_text(screen_insurance(res), encoding=\"utf-8\")\n    (out / \"bildirim_merkezi.html\").write_text(screen_notifications(res), encoding=\"utf-8\")\n    res[\"provenance\"].to_csv(out / \"provenance.csv\", index=False)\n    hydro[\"metrics\"].to_csv(out / \"model_skorlari.csv\", index=False)\n    pd.DataFrame({k: v for k, v in sims.items()}).to_csv(out / \"hidrograflar.csv\")\n    if imp.get(\"districts\") is not None:\n        imp[\"districts\"].to_csv(out / \"ilce_etki.csv\", index=False)\n    np.save(out / \"derinlik_haritasi.npy\", depth)\n    _write_geotiff(out / \"derinlik_haritasi.tif\", depth, terrain.transform)\n    manifest = dict(engine=ENGINE_NAME, version=ENGINE_VERSION, title=title, generated=res[\"generated\"], config=json.loads(cfg.to_json()),\n                    catchment=cat, hydro=dict(best_model=best, peak_m3s=peak, stage_m=hydro.get(\"stage_m\")), impact={k: v for k, v in imp.items() if isinstance(v, (int, float, str))},\n                    warning=res[\"warning\"], mgm_alert=mgm_level, qml=(res[\"qml\"] or {}).get(\"scores\"), qubo=res.get(\"qubo\"), rain_checks=rain[\"checks\"],\n                    runtime_s=round(time.time() - t0, 1))\n    (out / \"manifest.json\").write_text(json.dumps(manifest, ensure_ascii=False, indent=2, default=str), encoding=\"utf-8\")\n    bundle = Path(cfg.out_dir) / f\"{out.name}_paket.zip\"\n    with zipfile.ZipFile(bundle, \"w\", zipfile.ZIP_DEFLATED) as z:\n        for p in out.rglob(\"*\"):\n            if p.is_file(): z.write(p, p.relative_to(out.parent))\n    res[\"bundle\"] = bundle; res[\"runtime_s\"] = time.time() - t0\n    say(f\"Tamamlandı: {out} ({res['runtime_s']:.0f} s) → paket {bundle.name}\")\n    return res\n\n\ndef _write_geotiff(path: Path, arr: np.ndarray, transform):\n    try:\n        import rasterio\n        with rasterio.open(path, \"w\", driver=\"GTiff\", height=arr.shape[0], width=arr.shape[1], count=1, dtype=\"float32\",\n                           crs=\"EPSG:4326\", transform=transform, compress=\"deflate\") as dst:\n            dst.write(arr.astype(\"float32\"), 1)\n    except Exception as ex:  # noqa: BLE001\n        log.warning(f\"GeoTIFF yazılamadı: {ex}\")\n\n\n# ===========================================================================\n# 11. ULUSAL TARAMA — 81 il için hızlı risk endeksi (tahmin + GloFAS anomali + MGM uyarı)\n# ===========================================================================\ndef national_screening(days: int = 3, provinces: Optional[List[str]] = None, progress=None) -> pd.DataFrame:\n    om, mgm = OpenMeteoClient(), MGMClient()\n    alarms = None\n    try:\n        alarms = mgm.meteoalarm(\"today\")\n    except Exception:  # noqa: BLE001\n        pass\n    rows = []\n    items = [(k, v) for k, v in PROVINCES.items() if not provinces or slugify(v[0]) in {slugify(p) for p in provinces}]\n    for code, (name, lat, lon) in items:\n        row = dict(plaka=code, il=name, lat=lat, lon=lon, yagis_mm=np.nan, glofas_oran=np.nan, mgm_uyari=\"unknown\")\n        try:\n            f = om.forecast_hourly(lat, lon, days=days, past_days=0)\n            row[\"yagis_mm\"] = float(f[\"precipitation\"].sum()); row[\"maks_saatlik_mm\"] = float(f[\"precipitation\"].max())\n        except Exception:  # noqa: BLE001\n            pass\n        try:\n            d = om.flood_daily(lat, lon, past_days=30, forecast_days=days, model=\"seamless_v4\")\n            base = d[\"river_discharge\"].iloc[:30].mean(); row[\"glofas_oran\"] = float(d[\"river_discharge\"].iloc[30:].max() / (base + 1e-6))\n        except Exception:  # noqa: BLE001\n            pass\n        if alarms is not None:\n            try:\n                ids = mgm.ilceler(name).merkezId.tolist(); lvl = \"none\"\n                order = {\"none\": 0, \"yellow\": 1, \"orange\": 2, \"red\": 3}\n                for a in alarms:\n                    for L in (\"red\", \"orange\", \"yellow\"):\n                        if set(a.get(\"towns\", {}).get(L, [])) & set(ids) and order[L] > order[lvl]: lvl = L\n                row[\"mgm_uyari\"] = lvl\n            except Exception:  # noqa: BLE001\n                pass\n        rows.append(row)\n        if progress: progress(f\"{name}: {row['yagis_mm']:.0f} mm, GloFAS ×{row['glofas_oran']:.1f}, MGM {row['mgm_uyari']}\")\n    df = pd.DataFrame(rows)\n    z = lambda s: (s - s.mean()) / (s.std() + 1e-9)  # noqa: E731\n    df[\"risk_endeksi\"] = (0.5 * z(df.yagis_mm.fillna(0)) + 0.3 * z(np.log1p(df.glofas_oran.fillna(1)))\n                          + 0.2 * df.mgm_uyari.map({\"none\": 0, \"unknown\": 0, \"yellow\": 1, \"orange\": 2, \"red\": 3}).fillna(0))\n    return df.sort_values(\"risk_endeksi\", ascending=False).reset_index(drop=True)\n\n\ndef load_observed_discharge(csv_path: str, time_col: str = \"tarih\", q_col: str = \"debi_m3s\") -> pd.Series:\n    \"\"\"DSİ AGİ / kullanıcı gözlem serisi (CSV) — GloFAS yerine referans olarak kullanılır.\"\"\"\n    df = pd.read_csv(csv_path)\n    s = pd.Series(df[q_col].values, index=pd.to_datetime(df[time_col], utc=True)).sort_index()\n    return s.resample(\"1D\").mean()\n"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3764667c",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "3764667c",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695659984,
     "user_tz": -180,
     "elapsed": 7333,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "27d1f3b3-f1b2-4959-a41a-84fd92a6495a"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "IBM Quantum hesabı kaydedildi\n",
      "Etkin: ['GEMINI_API_KEY'] · CDS: False · Earthdata: False · IBM: True\n"
     ]
    }
   ],
   "source": "#@title 2 · Erişim anahtarları (isteğe bağlı — boş bırakılabilir) { display-mode: \"form\" }\n#@markdown Anahtar girilmeyen kaynaklar atlanır; motor anahtarsız açık veriyle çalışmaya devam eder.\n#@markdown **Colab Secrets** (🔑 sol panel) kullanıyorsanız aynı adlarla tanımlayın; form alanları boşsa oradan okunur.\nimport os\nfrom pathlib import Path\nGEMINI_API_KEY = \"\"  #@param {type:\"string\"}\nGOOGLE_FLOOD_API_KEY = \"\"  #@param {type:\"string\"}\nCDS_API_TOKEN = \"\"  #@param {type:\"string\"}\nCDS_URL = \"https://cds.climate.copernicus.eu/api\"  #@param [\"https://cds.climate.copernicus.eu/api\", \"https://ewds.climate.copernicus.eu/api\"]\nEARTHDATA_USER = \"\"  #@param {type:\"string\"}\nEARTHDATA_PASS = \"\"  #@param {type:\"string\"}\nIBM_QUANTUM_TOKEN = \"\"  #@param {type:\"string\"}\nORIGIN_QCLOUD_TOKEN = \"\"  #@param {type:\"string\"}\nDWAVE_API_TOKEN = \"\"  #@param {type:\"string\"}\nOPENTOPO_API_KEY = \"\"  #@param {type:\"string\"}\n\ndef _secret(name, val):\n    if val: return val\n    try:\n        from google.colab import userdata\n        return userdata.get(name)\n    except Exception:\n        return \"\"\nfor k in [\"GEMINI_API_KEY\",\"GOOGLE_FLOOD_API_KEY\",\"ORIGIN_QCLOUD_TOKEN\",\"DWAVE_API_TOKEN\",\"OPENTOPO_API_KEY\"]:\n    v = _secret(k, globals()[k])\n    if v: os.environ[k] = v\ntok = _secret(\"CDS_API_TOKEN\", CDS_API_TOKEN)\nif tok:\n    Path.home().joinpath(\".cdsapirc\").write_text(f\"url: {CDS_URL}\\nkey: {tok}\\n\")\neu, ep = _secret(\"EARTHDATA_USER\", EARTHDATA_USER), _secret(\"EARTHDATA_PASS\", EARTHDATA_PASS)\nif eu and ep:\n    p = Path.home()/\".netrc\"; p.write_text(f\"machine urs.earthdata.nasa.gov login {eu} password {ep}\\n\"); p.chmod(0o600)\nit = _secret(\"IBM_QUANTUM_TOKEN\", IBM_QUANTUM_TOKEN)\nif it:\n    try:\n        from qiskit_ibm_runtime import QiskitRuntimeService\n        QiskitRuntimeService.save_account(channel=\"ibm_quantum_platform\", token=it, overwrite=True)\n        print(\"IBM Quantum hesabı kaydedildi\")\n    except Exception as e:\n        print(\"IBM Quantum kaydı atlandı:\", e)\ndw = _secret(\"DWAVE_API_TOKEN\", DWAVE_API_TOKEN)\nif dw: os.environ[\"DWAVE_API_TOKEN\"] = dw\nprint(\"Etkin:\", [k for k in [\"GEMINI_API_KEY\",\"GOOGLE_FLOOD_API_KEY\",\"ORIGIN_QCLOUD_TOKEN\",\"DWAVE_API_TOKEN\",\"OPENTOPO_API_KEY\"] if os.environ.get(k)],\n      \"· CDS:\", bool(tok), \"· Earthdata:\", bool(eu and ep), \"· IBM:\", bool(it))\n"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1d60e186",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "1d60e186",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695673595,
     "user_tz": -180,
     "elapsed": 113,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "4f8424d7-ae5e-4fec-ba55-3649425680f7"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "{\n",
      "  \"mode\": \"historical\",\n",
      "  \"scope\": \"event\",\n",
      "  \"event_key\": \"bozkurt_2021\",\n",
      "  \"il\": \"Kastamonu\",\n",
      "  \"havza\": \"Batı Karadeniz\",\n",
      "  \"bbox\": [\n",
      "    41.725,\n",
      "    33.825,\n",
      "    42.025,\n",
      "    34.125\n",
      "  ],\n",
      "  \"half_deg\": 0.15,\n",
      "  \"start\": \"2021-08-10\",\n",
      "  \"end\": \"2021-08-12\",\n",
      "  \"forecast_days\": 5,\n",
      "  \"nowcast_hours\": 12,\n",
      "  \"run_frequency\": \"daily\",\n",
      "  \"flood_type\": \"riverine\",\n",
      "  \"grid_max\": 260,\n",
      "  \"pluvial_grid_max\": 220,\n",
      "  \"mc_runs\": 16,\n",
      "  \"mc_grid_max\": 120,\n",
      "  \"quantum_backend\": \"default.qubit\",\n",
      "  \"n_qubits\": 6,\n",
      "  \"qml_epochs\": 60,\n",
      "  \"qml_layers\": 3,\n",
      "  \"qubo_solver\": \"anneal\",\n",
      "  \"llm_provider\": \"template\",\n",
      "  \"gemini_model\": \"gemini-2.5-flash\",\n",
      "  \"out_dir\": \"trflood_out\",\n",
      "  \"report_lang\": \"tr\",\n",
      "  \"seed\": 42,\n",
      "  \"residential_max_damage_try_m2\": 9000.0,\n",
      "  \"commercial_max_damage_try_m2\": 14000.0,\n",
      "  \"insurance_penetration\": 0.12,\n",
      "  \"persons_per_building\": 3.2,\n",
      "  \"sewer_capacity_mm_h\": 10.0,\n",
      "  \"exposure_depth_m\": 0.3\n",
      "}\n",
      "\n",
      "Referans olay: Kastamonu Bozkurt – Ezine Çayı Taşkını | 2021-08-10 → 2021-08-12 | 451.7 mm / 72 s | 71 can kaybı Kastamonu + 10 Sinop (MGM); 82 (NHESS 2022)\n"
     ]
    }
   ],
   "source": "#@title 3 · Çalıştırma yapılandırması { display-mode: \"form\" }\nimport importlib, trflood_engine as te; importlib.reload(te)\n#@markdown ### Mod ve kapsam\nmode = \"historical\"  #@param [\"historical\", \"forecast\", \"nowcast\"]\nscope = \"event\"  #@param [\"event\", \"il\", \"havza\", \"turkiye\", \"bbox\"]\nevent_key = \"bozkurt_2021\"  #@param [\"bozkurt_2021\", \"istanbul_2023\", \"sanliurfa_2023\", \"giresun_dereli_2020\", \"rize_2021\", \"rize_2025\", \"izmir_2021\", \"izmir_2026\", \"antalya_manavgat_2024\", \"ankara_mamak_2018\", \"hatay_samandag_2026\", \"rize_2026\"]\nil = \"Kastamonu\"  #@param [\"Adana\",\"Adıyaman\",\"Afyonkarahisar\",\"Ağrı\",\"Amasya\",\"Ankara\",\"Antalya\",\"Artvin\",\"Aydın\",\"Balıkesir\",\"Bilecik\",\"Bingöl\",\"Bitlis\",\"Bolu\",\"Burdur\",\"Bursa\",\"Çanakkale\",\"Çankırı\",\"Çorum\",\"Denizli\",\"Diyarbakır\",\"Edirne\",\"Elazığ\",\"Erzincan\",\"Erzurum\",\"Eskişehir\",\"Gaziantep\",\"Giresun\",\"Gümüşhane\",\"Hakkari\",\"Hatay\",\"Isparta\",\"Mersin\",\"İstanbul\",\"İzmir\",\"Kars\",\"Kastamonu\",\"Kayseri\",\"Kırklareli\",\"Kırşehir\",\"Kocaeli\",\"Konya\",\"Kütahya\",\"Malatya\",\"Manisa\",\"Kahramanmaraş\",\"Mardin\",\"Muğla\",\"Muş\",\"Nevşehir\",\"Niğde\",\"Ordu\",\"Rize\",\"Sakarya\",\"Samsun\",\"Siirt\",\"Sinop\",\"Sivas\",\"Tekirdağ\",\"Tokat\",\"Trabzon\",\"Tunceli\",\"Şanlıurfa\",\"Uşak\",\"Van\",\"Yozgat\",\"Zonguldak\",\"Aksaray\",\"Bayburt\",\"Karaman\",\"Kırıkkale\",\"Batman\",\"Şırnak\",\"Bartın\",\"Ardahan\",\"Iğdır\",\"Yalova\",\"Karabük\",\"Kilis\",\"Osmaniye\",\"Düzce\"]\nhavza = \"Batı Karadeniz\"  #@param [\"Meriç-Ergene\",\"Marmara\",\"Susurluk\",\"Kuzey Ege\",\"Gediz\",\"Küçük Menderes\",\"Büyük Menderes\",\"Batı Akdeniz\",\"Antalya\",\"Burdur\",\"Akarçay\",\"Sakarya\",\"Batı Karadeniz\",\"Yeşilırmak\",\"Kızılırmak\",\"Konya Kapalı\",\"Doğu Akdeniz\",\"Seyhan\",\"Asi\",\"Ceyhan\",\"Fırat-Dicle\",\"Doğu Karadeniz\",\"Çoruh\",\"Aras\",\"Van Gölü\"]\nbbox_SWNE = \"\"  #@param {type:\"string\"}\nhalf_deg = 0.15  #@param {type:\"number\"}\nflood_type = \"auto\"  #@param [\"auto\", \"riverine\", \"pluvial\", \"both\"]\nstart_date = \"\"  #@param {type:\"string\"}\nend_date = \"\"  #@param {type:\"string\"}\nforecast_days = 5  #@param {type:\"integer\"}\nrun_frequency = \"daily\"  #@param [\"hourly\", \"daily\", \"weekly\"]\n#@markdown ### Hesap bütçesi\ngrid_max = 260  #@param {type:\"integer\"}\npluvial_grid_max = 220  #@param {type:\"integer\"}\nmc_runs = 16  #@param {type:\"integer\"}\n#@markdown ### Kuantum\nquantum_backend = \"default.qubit\"  #@param [\"default.qubit\", \"ibm\", \"origin\", \"none\"]\nn_qubits = 6  #@param {type:\"integer\"}\nqml_epochs = 60  #@param {type:\"integer\"}\nqml_layers = 3  #@param {type:\"integer\"}\nqubo_solver = \"anneal\"  #@param [\"anneal\", \"qaoa\", \"dwave\", \"none\"]\n#@markdown ### Rapor ve etki\nllm_provider = \"template\"  #@param [\"template\", \"gemini\"]\nreport_lang = \"tr\"  #@param [\"tr\", \"en\", \"both\"]\nsewer_capacity_mm_h = 10.0  #@param {type:\"number\"}\nexposure_depth_m = 0.3  #@param {type:\"number\"}\ninsurance_penetration = 0.12  #@param {type:\"number\"}\n\nbbox = tuple(float(x) for x in bbox_SWNE.split(\",\")) if bbox_SWNE.strip() else None\ncfg = te.RunConfig(mode=mode, scope=scope, event_key=event_key, il=il, havza=havza, bbox=bbox, half_deg=half_deg,\n                   start=start_date or None, end=end_date or None, forecast_days=forecast_days, run_frequency=run_frequency,\n                   flood_type=flood_type, grid_max=grid_max, pluvial_grid_max=pluvial_grid_max, mc_runs=mc_runs,\n                   quantum_backend=quantum_backend, n_qubits=n_qubits, qml_epochs=qml_epochs, qml_layers=qml_layers,\n                   qubo_solver=qubo_solver, llm_provider=llm_provider, report_lang=report_lang,\n                   sewer_capacity_mm_h=sewer_capacity_mm_h, exposure_depth_m=exposure_depth_m, insurance_penetration=insurance_penetration)\ncfg.resolve()\nprint(cfg.to_json())\nif scope == \"event\":\n    ev = te.EVENTS[event_key]; print(\"\\nReferans olay:\", ev[\"ad\"], \"|\", ev[\"baslangic\"], \"→\", ev[\"bitis\"], \"|\", ev[\"yagis_mm\"], \"mm /\", ev[\"yagis_sure_saat\"], \"s |\", ev[\"kayip\"])\n"
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "989bb730",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000,
     "output_embedded_package_id": "1MEsq9CMnpYpM6KDpo_69M_ChUmT6wBne"
    },
    "id": "989bb730",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695854361,
     "user_tz": -180,
     "elapsed": 173103,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "7d1afb2a-f139-4a12-ab11-09cdb6cec3fc"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": "Output hidden; open in https://colab.research.google.com to view."
     },
     "metadata": {}
    }
   ],
   "source": "#@title 4 · Uçtan uca çalıştır (≈1–4 dk) { display-mode: \"form\" }\nfrom IPython.display import display, Image, Markdown\nimport pandas as pd\nres = te.run_pipeline(cfg, progress=lambda m: print(\"▶\", m))\nhy, imp = res[\"hydro\"], res[\"impact\"]\ndisplay(Markdown(f\"## {res['title']}\\n**Uyarı seviyesi:** {res['warning'][1]} (MGM MeteoUyarı: {res['mgm_alert'][0]})  \\n\"\n                 f\"**Yağış girdisi:** {float(res['rain']['rain'].sum()):.0f} mm — {res['rain']['source']}  \\n\"\n                 f\"**Havza:** {hy['catchment']['area_km2']:.0f} km², tc {hy['catchment']['tc_hours']:.1f} s, CN {hy['cn']:.0f} (HSG {hy['hsg']})  \\n\"\n                 f\"**Tepe debi:** {hy['peak_m3s']:,.0f} m³/s ({hy['best_model']})\" + (f\" · nehir seviyesi {hy['stage_m']:.2f} m\" if hy.get('stage_m') else \"\") + \"  \\n\"\n                 f\"**Etkilenen nüfus (>{imp['exposure_depth_m']} m):** {imp['exposed_pop']:,.0f} (+{imp['exposed_pop_shallow']:,.0f} sığ) · alan {imp['exposed_area_km2']:.1f} km² · maks derinlik {imp['max_depth']:.1f} m  \\n\"\n                 f\"**Tahmini hasar:** {te._fmt_try(imp['loss_try'])} · PML90 {te._fmt_try(imp.get('pml90_try'))}  \\n\"\n                 f\"**Model seçimi:** {hy['selection_note']}\"))\ndisplay(hy[\"metrics\"].round(3))\nif imp.get(\"districts\") is not None: display(imp[\"districts\"].round(2).head(12))\nif res.get(\"qml\"): display(pd.DataFrame(res[\"qml\"][\"scores\"]).T.round(3)); print(\"QML:\", res[\"qml\"][\"info\"])\ndisplay(res[\"provenance\"][[\"katman\",\"kaynak\",\"durum\",\"detay\"]])\nfor k in [\"hidrograf\",\"model_skor\",\"derinlik_nehir\",\"derinlik_pluvyal\",\"derinlik_birlesik\",\"asilma\",\"asilma_pluvyal\",\"dogrulama\",\"qml\",\"ilce\"]:\n    if k in res[\"figures\"]: display(Image(filename=str(res[\"figures\"][k]), width=820))\n"
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1058124f",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "1058124f",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695984971,
     "user_tz": -180,
     "elapsed": 54,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "9abf4001-c75d-40f4-8f96-48ae06f4a989"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "<style>\n",
       ".trf{font-family:Segoe UI,Arial,sans-serif;max-width:1100px;margin:8px 0;color:#1b2430}\n",
       ".trf h2{margin:0 0 6px;font-size:20px}.trf .sub{color:#5b6472;font-size:12px;margin-bottom:10px}\n",
       ".trf .kpis{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0 14px}\n",
       ".trf .kpi{flex:1 1 150px;background:#f4f6f9;border-radius:10px;padding:10px 12px;border-left:5px solid #2b6cb0}\n",
       ".trf .kpi b{display:block;font-size:20px}.trf .kpi span{font-size:12px;color:#5b6472}\n",
       ".trf table{border-collapse:collapse;width:100%;font-size:13px}.trf th,.trf td{border-bottom:1px solid #e3e7ee;padding:6px 8px;text-align:left}\n",
       ".trf th{background:#eef2f7}.trf .lvl{display:inline-block;padding:3px 10px;border-radius:14px;color:#fff;font-weight:600}\n",
       ".trf .yesil{background:#2f855a}.trf .sari{background:#d69e2e}.trf .turuncu{background:#dd6b20}.trf .kirmizi{background:#c53030}\n",
       ".trf pre{background:#f4f6f9;padding:10px;border-radius:8px;white-space:pre-wrap;font-size:12px}\n",
       "</style><div class=\"trf\"><h2>🚨 Acil Durum Bilgi Paylaşım Panosu — Kastamonu Bozkurt – Ezine Çayı Taşkını</h2>\n",
       "<div class=\"sub\">TR-Flood Engine v1.0.0 · mod: historical · pencere: 2021-08-10 → 2021-08-12 · üretim: 2026-09-29 15:28 UTC</div>\n",
       "<div class=\"kpis\">\n",
       "<div class=\"kpi\"><b><span class=\"lvl kirmizi\">Kırmızı — acil tahliye</span></b><span>Motor uyarı seviyesi (MGM MeteoUyarı: yellow)</span></div>\n",
       "<div class=\"kpi\"><b>1,514</b><span>Etkilenen nüfus (&gt;0.3 m, WorldPop 2025) · sığ (&gt;0,1 m): +652</span></div>\n",
       "<div class=\"kpi\"><b>50.07 km²</b><span>Su altında alan (&gt;0,1 m) · 31.74 km² (&gt;0.3 m)</span></div>\n",
       "<div class=\"kpi\"><b>2.26 m</b><span>Maksimum su derinliği</span></div>\n",
       "<div class=\"kpi\"><b>1,424 m³/s</b><span>Tepe debi (SCS-CN + SCS UH)</span></div>\n",
       "<div class=\"kpi\"><b>3</b><span>Atanan müdahale ekibi (QUBO)</span></div>\n",
       "</div>\n",
       "<table><tr><th>İlçe</th><th>Etkilenen nüfus</th><th>Alan km²</th><th>Maks derinlik m</th><th>Risk skoru</th><th>Ekip</th></tr><tr><td>Bozkurt</td><td>945</td><td>19.82</td><td>2.25</td><td>1,297</td><td></td></tr><tr><td>Abana</td><td>256</td><td>2.19</td><td>2.26</td><td>329</td><td>✅ ekip</td></tr><tr><td>İnebolu</td><td>212</td><td>7.38</td><td>1.38</td><td>248</td><td>✅ ekip</td></tr><tr><td>Çatalzeytin</td><td>54</td><td>5.05</td><td>0.74</td><td>56</td><td></td></tr><tr><td>Devrekani</td><td>46</td><td>15.32</td><td>1.43</td><td>48</td><td>✅ ekip</td></tr><tr><td>Taşköprü</td><td>0</td><td>0.00</td><td>0.00</td><td>0</td><td></td></tr><tr><td>Küre</td><td>0</td><td>0.29</td><td>0.37</td><td>0</td><td></td></tr></table>\n",
       "<p class=\"sub\">Paylaşım: AFAD İl Müdürlüğü · Valilik / Kaymakamlık · DSİ Bölge · İtfaiye · 112 · Belediye Fen İşleri · Kızılay. Veri kaynakları ve durumları rapor paketindeki <i>provenance.csv</i> dosyasındadır.</p></div>"
      ]
     },
     "metadata": {}
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "<style>\n",
       ".trf{font-family:Segoe UI,Arial,sans-serif;max-width:1100px;margin:8px 0;color:#1b2430}\n",
       ".trf h2{margin:0 0 6px;font-size:20px}.trf .sub{color:#5b6472;font-size:12px;margin-bottom:10px}\n",
       ".trf .kpis{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0 14px}\n",
       ".trf .kpi{flex:1 1 150px;background:#f4f6f9;border-radius:10px;padding:10px 12px;border-left:5px solid #2b6cb0}\n",
       ".trf .kpi b{display:block;font-size:20px}.trf .kpi span{font-size:12px;color:#5b6472}\n",
       ".trf table{border-collapse:collapse;width:100%;font-size:13px}.trf th,.trf td{border-bottom:1px solid #e3e7ee;padding:6px 8px;text-align:left}\n",
       ".trf th{background:#eef2f7}.trf .lvl{display:inline-block;padding:3px 10px;border-radius:14px;color:#fff;font-weight:600}\n",
       ".trf .yesil{background:#2f855a}.trf .sari{background:#d69e2e}.trf .turuncu{background:#dd6b20}.trf .kirmizi{background:#c53030}\n",
       ".trf pre{background:#f4f6f9;padding:10px;border-radius:8px;white-space:pre-wrap;font-size:12px}\n",
       "</style><div class=\"trf\"><h2>🛡️ Sigorta ve Finansal Etki Panosu — Kastamonu Bozkurt – Ezine Çayı Taşkını</h2>\n",
       "<div class=\"sub\">Derinlik-hasar: JRC (Huizinga 2017) Avrupa eğrileri · maksimum hasar 9,000 ₺/m² konut, 14,000 ₺/m² ticari · <b>kalibrasyon gerektirir</b></div>\n",
       "<div class=\"kpis\">\n",
       "<div class=\"kpi\"><b>534.6 milyon ₺</b><span>Tahmini doğrudan yapısal hasar</span></div>\n",
       "<div class=\"kpi\"><b>64.2 milyon ₺</b><span>Sigortalı pay (penetrasyon %12)</span></div>\n",
       "<div class=\"kpi\"><b>470.4 milyon ₺</b><span>Sigortasız pay (DASK taşkını kapsamaz)</span></div>\n",
       "<div class=\"kpi\"><b>621.1 milyon ₺</b><span>PML (Monte Carlo %90)</span></div>\n",
       "<div class=\"kpi\"><b>896</b><span>Etkilenen yapı (tahmini)</span></div>\n",
       "<div class=\"kpi\"><b>1,782 m³/s</b><span>Tepe debi %90 (MC, n=16)</span></div>\n",
       "</div>\n",
       "<table><tr><th>Derinlik sınıfı</th><th>Alan km²</th><th>Nüfus</th><th>Yapılaşmış km²</th></tr>\n",
       "<tr><td>0,1–0,3 m (sığ)</td><td>18.33</td><td>652</td><td>0.04</td></tr><tr><td>0,3–1 m (orta)</td><td>25.92</td><td>684</td><td>0.10</td></tr><tr><td>1–2 m (yüksek)</td><td>5.01</td><td>252</td><td>0.01</td></tr><tr><td>>2 m (çok yüksek)</td><td>0.81</td><td>577</td><td>0.20</td></tr></table>\n",
       "<p class=\"sub\">Kullanım: reasürans/portföy PML, TARSİM tarım, belediye altyapı bütçesi. Zarar değerleri il bazlı yeniden inşa maliyetleriyle (ÇŞB birim fiyatları) kalibre edilmelidir.</p></div>"
      ]
     },
     "metadata": {}
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "<style>\n",
       ".trf{font-family:Segoe UI,Arial,sans-serif;max-width:1100px;margin:8px 0;color:#1b2430}\n",
       ".trf h2{margin:0 0 6px;font-size:20px}.trf .sub{color:#5b6472;font-size:12px;margin-bottom:10px}\n",
       ".trf .kpis{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0 14px}\n",
       ".trf .kpi{flex:1 1 150px;background:#f4f6f9;border-radius:10px;padding:10px 12px;border-left:5px solid #2b6cb0}\n",
       ".trf .kpi b{display:block;font-size:20px}.trf .kpi span{font-size:12px;color:#5b6472}\n",
       ".trf table{border-collapse:collapse;width:100%;font-size:13px}.trf th,.trf td{border-bottom:1px solid #e3e7ee;padding:6px 8px;text-align:left}\n",
       ".trf th{background:#eef2f7}.trf .lvl{display:inline-block;padding:3px 10px;border-radius:14px;color:#fff;font-weight:600}\n",
       ".trf .yesil{background:#2f855a}.trf .sari{background:#d69e2e}.trf .turuncu{background:#dd6b20}.trf .kirmizi{background:#c53030}\n",
       ".trf pre{background:#f4f6f9;padding:10px;border-radius:8px;white-space:pre-wrap;font-size:12px}\n",
       "</style><div class=\"trf\"><h2>📣 Bildirim Merkezi — Kastamonu Bozkurt – Ezine Çayı Taşkını</h2>\n",
       "<div class=\"sub\">Şablonlar otomatik üretilir; gönderim resmî kanallar (AFAD, Valilik, belediye) üzerinden yapılmalıdır. Çalıştırma sıklığı: daily.</div>\n",
       "<table><tr><th style=\"width:26%\">Kanal / Hedef</th><th>Mesaj</th></tr><tr><td><b>SMS (halk)</b><br><span class='sub'>Etkilenen ilçe sakinleri</span></td><td><pre>[KIRMIZI] Kastamonu: Bozkurt, Abana, İnebolu çevresinde taşkın riski (2021-08-10). Dere yataklarından, alt geçitlerden uzak durun. Bilgi: AFAD 122 / 112.</pre></td></tr><tr><td><b>Cell Broadcast / Uyarı Sistemi</b><br><span class='sub'>Kastamonu — riskli ilçeler</span></td><td><pre>AFAD UYARI: Bozkurt, Abana, İnebolu için Kırmızı — acil tahliye. Tahmini etkilenen nüfus 1,514. Maks derinlik 2.3 m.</pre></td></tr><tr><td><b>E-posta (kurumsal)</b><br><span class='sub'>Valilik, AFAD İl Md., DSİ Bölge, Belediye, İtfaiye, 112</span></td><td><pre>Konu: Kastamonu Bozkurt – Ezine Çayı Taşkını — Kırmızı — acil tahliye\n",
       "\n",
       "Motor çıktısı (2026-09-29 15:28 UTC): tepe debi 1,424 m³/s, su altında alan 50.07 km², etkilenen nüfus 1,514, öncelikli ilçeler: Bozkurt, Abana, İnebolu. Rapor paketi ektedir.</pre></td></tr><tr><td><b>WhatsApp Business / Telegram</b><br><span class='sub'>Muhtarlar, mahalle afet gönüllüleri</span></td><td><pre>⚠️ Bozkurt, Abana, İnebolu: Kırmızı — acil tahliye. Riskli sokaklar için harita paketteki 'derinlik_haritasi.png'. Tahliye noktaları: okul/cami bahçeleri (yüksek kot).</pre></td></tr><tr><td><b>API (JSON) — belediye/kurum entegrasyonu</b><br><span class='sub'>Webhook</span></td><td><pre>{\"engine\": \"TR-Flood Engine\", \"version\": \"1.0.0\", \"level\": \"kirmizi\", \"il\": \"Kastamonu\", \"districts\": [\"Bozkurt\", \"Abana\", \"İnebolu\", \"Çatalzeytin\", \"Devrekani\"], \"exposed_pop\": 1514, \"max_depth_m\": 2.26, \"peak_m3s\": 1424, \"generated\": \"2026-09-29 15:28 UTC\"}</pre></td></tr></table></div>"
      ]
     },
     "metadata": {}
    }
   ],
   "source": "#@title 5 · Ekranlar — acil durum bilgi paylaşımı · sigorta · bildirim merkezi { display-mode: \"form\" }\nfrom IPython.display import HTML, display\ndisplay(HTML(te.screen_emergency(res)))\ndisplay(HTML(te.screen_insurance(res)))\ndisplay(HTML(te.screen_notifications(res)))\n"
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "3ffde74a",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 907
    },
    "id": "3ffde74a",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790695994724,
     "user_tz": -180,
     "elapsed": 671,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "b3876bc9-b78f-4bde-d9fd-749df998a99d"
   },
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "<folium.folium.Map at 0x7abf3b2a4d70>"
      ],
      "text/html": [
       "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><span style=\"color:#565656\">Make this Notebook Trusted to load map: File -> Trust Notebook</span><iframe srcdoc=\"&lt;!DOCTYPE html&gt;\n",
       "&lt;html&gt;\n",
       "&lt;head&gt;\n",
       "    \n",
       "    &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;\n",
       "    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;script src=&quot;https://code.jquery.com/jquery-3.7.1.min.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.2.0/css/all.min.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css&quot;/&gt;\n",
       "    \n",
       "            &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,\n",
       "                initial-scale=1.0, maximum-scale=1.0, user-scalable=no&quot; /&gt;\n",
       "            &lt;style&gt;\n",
       "                #map_72c2b33363ec242d6f3f76eeac1096b5 {\n",
       "                    position: relative;\n",
       "                    width: 100.0%;\n",
       "                    height: 100.0%;\n",
       "                    left: 0.0%;\n",
       "                    top: 0.0%;\n",
       "                }\n",
       "                .leaflet-container { font-size: 1rem; }\n",
       "            &lt;/style&gt;\n",
       "\n",
       "            &lt;style&gt;html, body {\n",
       "                width: 100%;\n",
       "                height: 100%;\n",
       "                margin: 0;\n",
       "                padding: 0;\n",
       "            }\n",
       "            &lt;/style&gt;\n",
       "\n",
       "            &lt;style&gt;#map {\n",
       "                position:absolute;\n",
       "                top:0;\n",
       "                bottom:0;\n",
       "                right:0;\n",
       "                left:0;\n",
       "                }\n",
       "            &lt;/style&gt;\n",
       "\n",
       "            &lt;script&gt;\n",
       "                L_NO_TOUCH = false;\n",
       "                L_DISABLE_3D = false;\n",
       "            &lt;/script&gt;\n",
       "\n",
       "        \n",
       "    \n",
       "            \n",
       "                &lt;style&gt;\n",
       "                    .leaflet-image-layer {\n",
       "                        /* old android/safari*/\n",
       "                        image-rendering: -webkit-optimize-contrast;\n",
       "                        image-rendering: crisp-edges; /* safari */\n",
       "                        image-rendering: pixelated; /* chrome */\n",
       "                        image-rendering: -moz-crisp-edges; /* firefox */\n",
       "                        image-rendering: -o-crisp-edges; /* opera */\n",
       "                        -ms-interpolation-mode: nearest-neighbor; /* ie */\n",
       "                    }\n",
       "                &lt;/style&gt;\n",
       "            \n",
       "        \n",
       "    \n",
       "            \n",
       "                &lt;style&gt;\n",
       "                    .leaflet-image-layer {\n",
       "                        /* old android/safari*/\n",
       "                        image-rendering: -webkit-optimize-contrast;\n",
       "                        image-rendering: crisp-edges; /* safari */\n",
       "                        image-rendering: pixelated; /* chrome */\n",
       "                        image-rendering: -moz-crisp-edges; /* firefox */\n",
       "                        image-rendering: -o-crisp-edges; /* opera */\n",
       "                        -ms-interpolation-mode: nearest-neighbor; /* ie */\n",
       "                    }\n",
       "                &lt;/style&gt;\n",
       "            \n",
       "        \n",
       "&lt;/head&gt;\n",
       "&lt;body&gt;\n",
       "    \n",
       "    \n",
       "            &lt;div class=&quot;folium-map&quot; id=&quot;map_72c2b33363ec242d6f3f76eeac1096b5&quot; &gt;&lt;/div&gt;\n",
       "        \n",
       "&lt;/body&gt;\n",
       "&lt;script&gt;\n",
       "    \n",
       "    \n",
       "            var map_72c2b33363ec242d6f3f76eeac1096b5 = L.map(\n",
       "                &quot;map_72c2b33363ec242d6f3f76eeac1096b5&quot;,\n",
       "                {\n",
       "                    center: [41.875, 33.975],\n",
       "                    crs: L.CRS.EPSG3857,\n",
       "                    ...{\n",
       "  &quot;zoom&quot;: 11,\n",
       "  &quot;zoomControl&quot;: true,\n",
       "  &quot;preferCanvas&quot;: false,\n",
       "}\n",
       "\n",
       "                }\n",
       "            );\n",
       "\n",
       "            \n",
       "\n",
       "        \n",
       "    \n",
       "            var tile_layer_8ef93413fc0b4aecacd6b7eb65b600b3 = L.tileLayer(\n",
       "                &quot;https://tile.openstreetmap.org/{z}/{x}/{y}.png&quot;,\n",
       "                {\n",
       "  &quot;minZoom&quot;: 0,\n",
       "  &quot;maxZoom&quot;: 19,\n",
       "  &quot;maxNativeZoom&quot;: 19,\n",
       "  &quot;noWrap&quot;: false,\n",
       "  &quot;attribution&quot;: &quot;\\u0026copy; \\u003ca href=\\&quot;https://www.openstreetmap.org/copyright\\&quot;\\u003eOpenStreetMap\\u003c/a\\u003e contributors&quot;,\n",
       "  &quot;subdomains&quot;: &quot;abc&quot;,\n",
       "  &quot;detectRetina&quot;: false,\n",
       "  &quot;tms&quot;: false,\n",
       "  &quot;opacity&quot;: 1,\n",
       "}\n",
       "\n",
       "            );\n",
       "        \n",
       "    \n",
       "            tile_layer_8ef93413fc0b4aecacd6b7eb65b600b3.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "            var image_overlay_fbcb4295205a3e8f54bd712db58c2422 = L.imageOverlay(\n",
       "                &quot;data:image/png;base64,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&quot;,\n",
       "                [[41.725, 33.825], [42.025, 34.125]],\n",
       "                {\n",
       "  &quot;opacity&quot;: 0.9,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            image_overlay_fbcb4295205a3e8f54bd712db58c2422.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "            var image_overlay_a9205b942cbf5ece2434812ac5b8fa04 = L.imageOverlay(\n",
       "                &quot;data:image/png;base64,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&quot;,\n",
       "                [[41.725, 33.825], [42.025, 34.125]],\n",
       "                {\n",
       "  &quot;opacity&quot;: 0.8,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "        function geo_json_ed4765b32d940951e089761d58a1bd03_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_ed4765b32d940951e089761d58a1bd03_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_ed4765b32d940951e089761d58a1bd03 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_ed4765b32d940951e089761d58a1bd03_onEachFeature,\n",
       "            \n",
       "                style: geo_json_ed4765b32d940951e089761d58a1bd03_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_ed4765b32d940951e089761d58a1bd03_add (data) {\n",
       "            geo_json_ed4765b32d940951e089761d58a1bd03\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_ed4765b32d940951e089761d58a1bd03_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[33.7172379, 41.5648951], [33.7247, 41.5450998], [33.7509732, 41.5460313], [33.7584403, 41.5438579], [33.7679816, 41.5355777], [33.7726831, 41.5338181], [33.7831924, 41.5397179], [33.792872, 41.5414775], [33.7973579, 41.5378836], [33.8085107, 41.5372788], [33.8153717, 41.5333827], [33.8283838, 41.5307261], [33.8376106, 41.5328514], [33.8465282, 41.5320628], [33.8513959, 41.5267677], [33.8624166, 41.5329545], [33.8763984, 41.5341664], [33.8822479, 41.5370215], [33.8862323, 41.5463089], [33.8934445, 41.5489656], [33.9031491, 41.5510617], [33.9163154, 41.5473063], [33.998813, 41.5701088], [34.0317299, 41.5900682], [34.0492866, 41.6143444], [34.050109, 41.6177502], [34.04236, 41.6440605], [34.0644819, 41.6541972], [34.0775351, 41.6583246], [34.0836672, 41.6674034], [34.0910066, 41.6728042], [34.1095336, 41.681206], [34.1157678, 41.6903313], [34.1217527, 41.7102535], [34.1227502, 41.7266335], [34.1190002, 41.7283923], [34.0929876, 41.7496529], [34.084604, 41.7538226], [34.0764745, 41.753633], [34.0627559, 41.7642455], [34.0629307, 41.7750812], [34.0584477, 41.7816144], [34.0581393, 41.7888997], [34.0468757, 41.7909617], [34.0442107, 41.7929487], [34.0452164, 41.7938109], [34.0427272, 41.7972549], [34.0365168, 41.7999728], [34.0340528, 41.7978172], [34.0231909, 41.7971986], [34.0188662, 41.7998603], [34.0145436, 41.7967432], [34.0001403, 41.7936318], [33.9943286, 41.7950495], [33.9900449, 41.7918515], [33.9832756, 41.7939147], [33.9687583, 41.8108436], [33.9638156, 41.8190773], [33.9645175, 41.8263392], [33.9749478, 41.8343151], [33.9709506, 41.8388216], [33.9492794, 41.8432451], [33.9294939, 41.8437523], [33.9128883, 41.8542825], [33.893395, 41.851834], [33.8811314, 41.8554272], [33.8815783, 41.8366777], [33.8844097, 41.8277653], [33.8733356, 41.8084237], [33.8537937, 41.8018179], [33.8431707, 41.8036911], [33.840885, 41.7997132], [33.8428859, 41.7931515], [33.8358762, 41.7862762], [33.8391938, 41.7757881], [33.8263202, 41.765467], [33.8160017, 41.7598848], [33.8102324, 41.7511719], [33.7974498, 41.7464631], [33.7729356, 41.7339367], [33.7881668, 41.722199], [33.7911506, 41.7060849], [33.7761112, 41.6891788], [33.77349, 41.6814685], [33.7759632, 41.6733272], [33.7856374, 41.6677534], [33.7964064, 41.6661626], [33.7995952, 41.6600691], [33.7972768, 41.6556749], [33.7915423, 41.6536688], [33.7886958, 41.648216], [33.7833777, 41.645031], [33.7805191, 41.6374069], [33.7971385, 41.6305089], [33.7984524, 41.6285965], [33.7851064, 41.6249266], [33.7684413, 41.6287516], [33.7618721, 41.6271493], [33.7579081, 41.6222911], [33.7537816, 41.6223938], [33.7555937, 41.6184219], [33.7483187, 41.6108137], [33.7487384, 41.6089259], [33.766015, 41.6036803], [33.7697319, 41.5953481], [33.7612996, 41.5903036], [33.7598985, 41.5860861], [33.7546805, 41.5816992], [33.7495634, 41.5807681], [33.7463825, 41.5819578], [33.74653, 41.5769537], [33.7381537, 41.5737848], [33.7392454, 41.5689348], [33.7315088, 41.5689746], [33.7327401, 41.5661279], [33.7310088, 41.5649685], [33.7225122, 41.5639074], [33.7172379, 41.5648951]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_ed4765b32d940951e089761d58a1bd03.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     Devrekani: 46 kişi, maks 1.4 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_ed4765b32d940951e089761d58a1bd03.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "        function geo_json_c746a6744f25844cf23d87e07aac40a1_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_c746a6744f25844cf23d87e07aac40a1_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_c746a6744f25844cf23d87e07aac40a1 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_c746a6744f25844cf23d87e07aac40a1_onEachFeature,\n",
       "            \n",
       "                style: geo_json_c746a6744f25844cf23d87e07aac40a1_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_c746a6744f25844cf23d87e07aac40a1_add (data) {\n",
       "            geo_json_c746a6744f25844cf23d87e07aac40a1\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_c746a6744f25844cf23d87e07aac40a1_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[33.5001691, 41.8328939], [33.5118304, 41.8240149], [33.5256999, 41.8193962], [33.544745, 41.817547], [33.5549632, 41.8146271], [33.5601673, 41.8063504], [33.5600586, 41.7997901], [33.5677782, 41.7747421], [33.5673526, 41.765122], [33.5787712, 41.7653848], [33.6011638, 41.7559112], [33.6022845, 41.7517818], [33.6245137, 41.751525], [33.6311381, 41.7471123], [33.6346868, 41.7375798], [33.6413112, 41.7328131], [33.6633135, 41.7253974], [33.6902842, 41.7261037], [33.7160719, 41.7238083], [33.7323962, 41.7264569], [33.7420139, 41.7331476], [33.7587007, 41.7347943], [33.7729356, 41.7339367], [33.7974498, 41.7464631], [33.8102324, 41.7511719], [33.8160017, 41.7598848], [33.8263202, 41.765467], [33.8391938, 41.7757881], [33.8358762, 41.7862762], [33.8428859, 41.7931515], [33.840885, 41.7997132], [33.8431707, 41.8036911], [33.8421676, 41.8065531], [33.8340995, 41.8141538], [33.808401, 41.8264002], [33.8020498, 41.8317243], [33.7941108, 41.8346819], [33.7833932, 41.8349777], [33.7750623, 41.8384598], [33.7678663, 41.8442184], [33.7618269, 41.8521646], [33.7468738, 41.8509998], [33.7396171, 41.854824], [33.7368991, 41.8606121], [33.721796, 41.8649783], [33.7199681, 41.873609], [33.7081121, 41.8763907], [33.6971526, 41.8763907], [33.6922582, 41.874158], [33.685024, 41.8761731], [33.6827662, 41.8789829], [33.6850292, 41.8849145], [33.6833613, 41.889038], [33.6720869, 41.8938702], [33.6699134, 41.9001836], [33.6579458, 41.9131714], [33.6449806, 41.9152224], [33.6317501, 41.9132826], [33.614542, 41.9060434], [33.6074918, 41.8939997], [33.5916676, 41.8996313], [33.5867592, 41.906724], [33.5729048, 41.9089595], [33.5613029, 41.9019863], [33.5576519, 41.8981148], [33.5437139, 41.8996835], [33.5383761, 41.8956939], [33.5267722, 41.8971801], [33.4871895, 41.8910218], [33.4795854, 41.8824945], [33.4774934, 41.8741587], [33.4797827, 41.8701061], [33.4788625, 41.8625015], [33.485653, 41.8588063], [33.5000696, 41.855432], [33.5056747, 41.8520812], [33.5122695, 41.8520455], [33.5082896, 41.846236], [33.5016504, 41.8411294], [33.5001691, 41.8328939]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_c746a6744f25844cf23d87e07aac40a1.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     Küre: 0 kişi, maks 0.4 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_c746a6744f25844cf23d87e07aac40a1.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "        function geo_json_b766adbbc6f3abe89b267a40cc8832e6_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_b766adbbc6f3abe89b267a40cc8832e6_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_b766adbbc6f3abe89b267a40cc8832e6 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_b766adbbc6f3abe89b267a40cc8832e6_onEachFeature,\n",
       "            \n",
       "                style: geo_json_b766adbbc6f3abe89b267a40cc8832e6_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_b766adbbc6f3abe89b267a40cc8832e6_add (data) {\n",
       "            geo_json_b766adbbc6f3abe89b267a40cc8832e6\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_b766adbbc6f3abe89b267a40cc8832e6_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[33.9163154, 41.5473063], [33.9170959, 41.5428136], [33.9211589, 41.5387508], [33.9196611, 41.5334764], [33.9215283, 41.5312143], [33.9205659, 41.5280983], [33.9329278, 41.5175112], [33.9337795, 41.5150003], [33.9291078, 41.494519], [33.9371658, 41.4919499], [33.9393677, 41.4894384], [33.949083, 41.4871286], [33.9636669, 41.4839775], [33.9733038, 41.4842372], [33.9893535, 41.4805208], [33.9857559, 41.4641649], [33.9710231, 41.4478378], [33.9580558, 41.4399868], [33.9351137, 41.431013], [33.9435923, 41.4272736], [33.9445898, 41.4231599], [33.9505747, 41.4192331], [33.9566006, 41.411592], [33.9546668, 41.4080244], [33.9585545, 41.4012785], [33.9550634, 41.3943572], [33.9617964, 41.3868739], [33.9630432, 41.3793898], [33.9710231, 41.3739632], [33.995212, 41.3702205], [34.0114211, 41.3642317], [34.0208972, 41.3543115], [34.030124, 41.351878], [34.0393507, 41.3449515], [34.0543129, 41.3400837], [34.0702726, 41.3325942], [34.0912198, 41.3299726], [34.0867311, 41.323231], [34.087978, 41.3183616], [34.1079276, 41.3159268], [34.1126657, 41.3181744], [34.1231392, 41.3179871], [34.1490785, 41.3035533], [34.1607942, 41.3020653], [34.1575524, 41.2955082], [34.1587993, 41.2898873], [34.1535625, 41.2893251], [34.1440864, 41.2683359], [34.1480763, 41.2610255], [34.1383341, 41.2575875], [34.1254859, 41.2577695], [34.1173314, 41.2511842], [34.1158907, 41.2308367], [34.1106372, 41.2236932], [34.0864898, 41.20826], [34.0892234, 41.2028601], [34.1115, 41.1827], [34.1136, 41.1732], [34.1186, 41.1699], [34.1284, 41.1688], [34.1297, 41.1735], [34.1378, 41.1785], [34.1459, 41.1785], [34.1532, 41.1819], [34.1604, 41.1774], [34.1637, 41.1781], [34.1654, 41.1803], [34.1762, 41.1814], [34.1771, 41.1736], [34.1867, 41.1721], [34.1975, 41.1745], [34.2003, 41.1783], [34.2078, 41.1768], [34.2176, 41.1825], [34.2410393, 41.1915214], [34.2439684, 41.1994166], [34.2606315, 41.2089787], [34.2938318, 41.2126978], [34.292327, 41.2235659], [34.2942899, 41.2289606], [34.2992142, 41.2325482], [34.2993681, 41.2399544], [34.3139871, 41.2459712], [34.3216814, 41.2531444], [34.3190653, 41.2580033], [34.3109095, 41.2642498], [34.3114091, 41.2702832], [34.3205326, 41.2729774], [34.3311122, 41.2811089], [34.3354402, 41.2865294], [34.3364019, 41.2930334], [34.3573206, 41.2942979], [34.3977152, 41.2803862], [34.394349, 41.2624664], [34.4001966, 41.2578392], [34.4026588, 41.2521705], [34.4094297, 41.2555255], [34.412969, 41.2655895], [34.4222021, 41.2695221], [34.4231254, 41.2790057], [34.4300502, 41.2880254], [34.4446692, 41.297275], [34.4608994, 41.304785], [34.4602782, 41.3092181], [34.4668848, 41.3279043], [34.4809598, 41.344316], [34.4833264, 41.3509213], [34.474991, 41.3617915], [34.4786677, 41.3661681], [34.4814507, 41.3802656], [34.4783077, 41.3855007], [34.4743717, 41.3883457], [34.4733898, 41.3991251], [34.4625921, 41.405008], [34.4604104, 41.4116638], [34.455321, 41.4132011], [34.449588, 41.4252445], [34.4472376, 41.4404779], [34.4531762, 41.4511705], [34.4526852, 41.4607746], [34.4308312, 41.4905151], [34.4419714, 41.5045335], [34.4256159, 41.5217409], [34.4108914, 41.5303328], [34.3996315, 41.5329264], [34.3790605, 41.5449202], [34.3628202, 41.5481614], [34.3400838, 41.5552915], [34.3335877, 41.565013], [34.3164813, 41.5698732], [34.3037056, 41.5711692], [34.3004576, 41.5748951], [34.3047883, 41.5862333], [34.3043552, 41.596436], [34.3008906, 41.5998366], [34.276855, 41.6137607], [34.2697093, 41.6322137], [34.2701424, 41.6435418], [34.2785873, 41.6498524], [34.2775047, 41.6610157], [34.2909299, 41.6658687], [34.3006741, 41.6731475], [34.300241, 41.6799403], [34.3026229, 41.6883494], [34.2976426, 41.7030628], [34.3034891, 41.7062961], [34.3102017, 41.7142169], [34.3253775, 41.7418973], [34.3099046, 41.7465038], [34.2986065, 41.7449873], [34.2843367, 41.7378281], [34.2680043, 41.7364595], [34.254442, 41.7372493], [34.2437468, 41.7425057], [34.2447563, 41.7534766], [34.2214913, 41.7432288], [34.1968559, 41.7450436], [34.1478191, 41.7321004], [34.1398001, 41.7370528], [34.1190002, 41.7283923], [34.1227502, 41.7266335], [34.1217527, 41.7102535], [34.1157678, 41.6903313], [34.1095336, 41.681206], [34.0910066, 41.6728042], [34.0836672, 41.6674034], [34.0775351, 41.6583246], [34.0644819, 41.6541972], [34.04236, 41.6440605], [34.050109, 41.6177502], [34.0492866, 41.6143444], [34.0317299, 41.5900682], [33.998813, 41.5701088], [33.9163154, 41.5473063]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_b766adbbc6f3abe89b267a40cc8832e6.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     Taşköprü: 0 kişi, maks 0.0 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_b766adbbc6f3abe89b267a40cc8832e6.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "        function geo_json_beb85619729e2a7fd708a823bf9af9d1_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_beb85619729e2a7fd708a823bf9af9d1_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_beb85619729e2a7fd708a823bf9af9d1 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_beb85619729e2a7fd708a823bf9af9d1_onEachFeature,\n",
       "            \n",
       "                style: geo_json_beb85619729e2a7fd708a823bf9af9d1_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_beb85619729e2a7fd708a823bf9af9d1_add (data) {\n",
       "            geo_json_beb85619729e2a7fd708a823bf9af9d1\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_beb85619729e2a7fd708a823bf9af9d1_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[34.1190002, 41.7283923], [34.1398001, 41.7370528], [34.1478191, 41.7321004], [34.1968559, 41.7450436], [34.2214913, 41.7432288], [34.2447563, 41.7534766], [34.273462, 41.7631012], [34.2783854, 41.7677527], [34.287986, 41.7868449], [34.289381, 41.8075829], [34.286427, 41.8207318], [34.2773187, 41.8354065], [34.2897092, 41.8566177], [34.2764981, 41.8752557], [34.2690802, 41.8816342], [34.2655353, 41.8822207], [34.2637271, 41.8863899], [34.2586771, 41.8880609], [34.2572635, 41.8920721], [34.2540887, 41.893738], [34.254401, 41.8967017], [34.2509273, 41.8969984], [34.2448231, 41.9065909], [34.2459986, 41.9097507], [34.2375328, 41.915236], [34.2376555, 41.9205266], [34.2356906, 41.9237172], [34.2311375, 41.925877], [34.2300582, 41.9304366], [34.2247051, 41.9355836], [34.2237142, 41.9384633], [34.2281363, 41.9420291], [34.228226, 41.954659], [34.212577, 41.9547984], [34.1744344, 41.9593179], [34.170361, 41.9617558], [34.1713749, 41.9640218], [34.1691862, 41.9612854], [34.167931, 41.9618997], [34.1679095, 41.9656971], [34.1733501, 41.9647865], [34.1687249, 41.9663193], [34.163339, 41.9652025], [34.1625344, 41.9670133], [34.1339324, 41.9706975], [34.1186106, 41.974469], [34.1145993, 41.9614975], [34.1161132, 41.9491127], [34.1033526, 41.9383344], [34.0979456, 41.9302897], [34.1054857, 41.9125175], [34.1025058, 41.9035166], [34.1046899, 41.884228], [34.094528, 41.8672034], [34.0932578, 41.8584528], [34.099609, 41.8530127], [34.1123114, 41.8620005], [34.1231084, 41.863183], [34.1504185, 41.8579798], [34.1488307, 41.8530127], [34.1405742, 41.8459162], [34.1408917, 41.8397652], [34.1618507, 41.829118], [34.1643911, 41.8246219], [34.1685194, 41.8227288], [34.1736004, 41.8149189], [34.1732828, 41.798586], [34.1694721, 41.7893525], [34.1516888, 41.7765656], [34.1221557, 41.7512208], [34.1100884, 41.7493255], [34.0929876, 41.7496529], [34.1190002, 41.7283923]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_beb85619729e2a7fd708a823bf9af9d1.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     Çatalzeytin: 54 kişi, maks 0.7 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_beb85619729e2a7fd708a823bf9af9d1.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "        function geo_json_56400531c49e8816888378ae870b0157_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_56400531c49e8816888378ae870b0157_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_56400531c49e8816888378ae870b0157 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_56400531c49e8816888378ae870b0157_onEachFeature,\n",
       "            \n",
       "                style: geo_json_56400531c49e8816888378ae870b0157_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_56400531c49e8816888378ae870b0157_add (data) {\n",
       "            geo_json_56400531c49e8816888378ae870b0157\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_56400531c49e8816888378ae870b0157_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[34.0929876, 41.7496529], [34.1100884, 41.7493255], [34.1221557, 41.7512208], [34.1516888, 41.7765656], [34.1694721, 41.7893525], [34.1732828, 41.798586], [34.1736004, 41.8149189], [34.1685194, 41.8227288], [34.1643911, 41.8246219], [34.1618507, 41.829118], [34.1408917, 41.8397652], [34.1405742, 41.8459162], [34.1488307, 41.8530127], [34.1504185, 41.8579798], [34.1231084, 41.863183], [34.1123114, 41.8620005], [34.099609, 41.8530127], [34.0932578, 41.8584528], [34.094528, 41.8672034], [34.1046899, 41.884228], [34.1025058, 41.9035166], [34.0921397, 41.9160992], [34.0632706, 41.9218183], [34.0544796, 41.9293458], [34.048283, 41.941476], [34.0315853, 41.9638526], [34.0234657, 41.9670691], [34.0198772, 41.9647876], [34.0157058, 41.9653177], [34.0099551, 41.9684958], [34.007235, 41.9660595], [34.008191, 41.9625083], [34.0013576, 41.9617523], [33.9971969, 41.9676466], [33.9881115, 41.9673916], [33.9806013, 41.9724676], [33.9759233, 41.9757505], [33.974834, 41.9798291], [33.96589, 41.980267], [33.9627707, 41.9793086], [33.9672566, 41.9797702], [33.966541, 41.977824], [33.964125, 41.977331], [33.963801, 41.978617], [33.963426, 41.976567], [33.9442645, 41.9737698], [33.9300731, 41.9746446], [33.913662, 41.9729215], [33.9152083, 41.960085], [33.9186131, 41.9503494], [33.918356, 41.9389987], [33.9235164, 41.9330929], [33.918753, 41.9180308], [33.9235164, 41.9094645], [33.9151805, 41.8935103], [33.918753, 41.8881914], [33.9290737, 41.8808032], [33.9322493, 41.86632], [33.9298676, 41.8615901], [33.920385, 41.8613724], [33.9187953, 41.8574961], [33.9128883, 41.8542825], [33.9294939, 41.8437523], [33.9492794, 41.8432451], [33.9709506, 41.8388216], [33.9749478, 41.8343151], [33.9645175, 41.8263392], [33.9638156, 41.8190773], [33.9687583, 41.8108436], [33.9832756, 41.7939147], [33.9900449, 41.7918515], [33.9943286, 41.7950495], [34.0001403, 41.7936318], [34.0145436, 41.7967432], [34.0188662, 41.7998603], [34.0231909, 41.7971986], [34.0340528, 41.7978172], [34.0365168, 41.7999728], [34.0427272, 41.7972549], [34.0452164, 41.7938109], [34.0442107, 41.7929487], [34.0468757, 41.7909617], [34.0581393, 41.7888997], [34.0584477, 41.7816144], [34.0629307, 41.7750812], [34.0627559, 41.7642455], [34.0764745, 41.753633], [34.084604, 41.7538226], [34.0929876, 41.7496529]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_56400531c49e8816888378ae870b0157.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     Bozkurt: 945 kişi, maks 2.2 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_56400531c49e8816888378ae870b0157.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "        function geo_json_52d275b28295320903d2233b0c9eda08_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_52d275b28295320903d2233b0c9eda08_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_52d275b28295320903d2233b0c9eda08 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_52d275b28295320903d2233b0c9eda08_onEachFeature,\n",
       "            \n",
       "                style: geo_json_52d275b28295320903d2233b0c9eda08_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_52d275b28295320903d2233b0c9eda08_add (data) {\n",
       "            geo_json_52d275b28295320903d2233b0c9eda08\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_52d275b28295320903d2233b0c9eda08_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[34.1186106, 41.974469], [34.0944278, 41.9793527], [34.0747642, 41.9783864], [34.0569481, 41.9803863], [34.04952, 41.9798101], [34.0459189, 41.981545], [34.0391485, 41.9796645], [34.0277185, 41.9795138], [34.0232832, 41.9812381], [34.022991, 41.979901], [34.0196416, 41.9797912], [34.0200704, 41.9815526], [34.0250121, 41.9825032], [34.0212914, 41.9823417], [34.0183891, 41.9809866], [33.9852706, 41.9791146], [33.974834, 41.9798291], [33.9759233, 41.9757505], [33.9806013, 41.9724676], [33.9881115, 41.9673916], [33.9971969, 41.9676466], [34.0013576, 41.9617523], [34.008191, 41.9625083], [34.007235, 41.9660595], [34.0099551, 41.9684958], [34.0157058, 41.9653177], [34.0198772, 41.9647876], [34.0234657, 41.9670691], [34.0315853, 41.9638526], [34.048283, 41.941476], [34.0544796, 41.9293458], [34.0632706, 41.9218183], [34.0921397, 41.9160992], [34.1025058, 41.9035166], [34.1054857, 41.9125175], [34.0979456, 41.9302897], [34.1033526, 41.9383344], [34.1161132, 41.9491127], [34.1145993, 41.9614975], [34.1186106, 41.974469]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_52d275b28295320903d2233b0c9eda08.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     Abana: 256 kişi, maks 2.3 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_52d275b28295320903d2233b0c9eda08.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "        function geo_json_3c910b158102f95881028bc506c100e3_styler(feature) {\n",
       "            switch(feature.id) {\n",
       "                default:\n",
       "                    return {&quot;color&quot;: &quot;#555&quot;, &quot;fill&quot;: false, &quot;weight&quot;: 1};\n",
       "            }\n",
       "        }\n",
       "\n",
       "        function geo_json_3c910b158102f95881028bc506c100e3_onEachFeature(feature, layer) {\n",
       "\n",
       "            layer.on({\n",
       "            });\n",
       "        };\n",
       "        var geo_json_3c910b158102f95881028bc506c100e3 = L.geoJson(null, {\n",
       "                onEachFeature: geo_json_3c910b158102f95881028bc506c100e3_onEachFeature,\n",
       "            \n",
       "                style: geo_json_3c910b158102f95881028bc506c100e3_styler,\n",
       "            ...{\n",
       "}\n",
       "        });\n",
       "\n",
       "        function geo_json_3c910b158102f95881028bc506c100e3_add (data) {\n",
       "            geo_json_3c910b158102f95881028bc506c100e3\n",
       "                .addData(data);\n",
       "        }\n",
       "            geo_json_3c910b158102f95881028bc506c100e3_add({&quot;features&quot;: [{&quot;geometry&quot;: {&quot;coordinates&quot;: [[[33.9128883, 41.8542825], [33.9187953, 41.8574961], [33.920385, 41.8613724], [33.9298676, 41.8615901], [33.9322493, 41.86632], [33.9290737, 41.8808032], [33.918753, 41.8881914], [33.9151805, 41.8935103], [33.9235164, 41.9094645], [33.918753, 41.9180308], [33.9235164, 41.9330929], [33.918356, 41.9389987], [33.9186131, 41.9503494], [33.9152083, 41.960085], [33.913662, 41.9729215], [33.9083312, 41.9739355], [33.9043644, 41.9720136], [33.8946746, 41.971543], [33.89232, 41.9725406], [33.8924626, 41.9742636], [33.8918476, 41.9726069], [33.8891379, 41.9733424], [33.8886565, 41.9743828], [33.8916426, 41.9756419], [33.8946821, 41.9750124], [33.8916069, 41.9759534], [33.8813296, 41.9734816], [33.8548474, 41.9747539], [33.8295283, 41.9723954], [33.8123513, 41.9762192], [33.8062007, 41.9748607], [33.8039276, 41.9764577], [33.8016457, 41.9754372], [33.7979108, 41.9767294], [33.7918939, 41.9734557], [33.7838892, 41.9731244], [33.7716594, 41.9758149], [33.7697607, 41.9775445], [33.7705536, 41.9789677], [33.7672409, 41.9782078], [33.7647511, 41.9810589], [33.7730086, 41.9800621], [33.7772907, 41.9820021], [33.7715208, 41.9809126], [33.7675392, 41.9819342], [33.7528101, 41.9778366], [33.7334444, 41.9777876], [33.7166873, 41.9805237], [33.6799724, 41.9804836], [33.6631747, 41.9840426], [33.6244769, 41.9852209], [33.6204885, 41.9869983], [33.6203608, 41.9855272], [33.6183738, 41.9856416], [33.6167527, 41.9873748], [33.6214678, 41.9879964], [33.617499, 41.9882703], [33.61505, 41.986534], [33.583416, 41.988624], [33.577931, 41.990833], [33.5714003, 41.9906922], [33.5707908, 41.9864309], [33.5817166, 41.9745313], [33.5834953, 41.9652744], [33.5814626, 41.96074], [33.571299, 41.956961], [33.5705367, 41.94052], [33.5674876, 41.9335265], [33.5729048, 41.9089595], [33.5867592, 41.906724], [33.5916676, 41.8996313], [33.6074918, 41.8939997], [33.614542, 41.9060434], [33.6317501, 41.9132826], [33.6449806, 41.9152224], [33.6579458, 41.9131714], [33.6699134, 41.9001836], [33.6720869, 41.8938702], [33.6833613, 41.889038], [33.6850292, 41.8849145], [33.6827662, 41.8789829], [33.685024, 41.8761731], [33.6922582, 41.874158], [33.6971526, 41.8763907], [33.7081121, 41.8763907], [33.7199681, 41.873609], [33.721796, 41.8649783], [33.7368991, 41.8606121], [33.7396171, 41.854824], [33.7468738, 41.8509998], [33.7618269, 41.8521646], [33.7678663, 41.8442184], [33.7750623, 41.8384598], [33.7833932, 41.8349777], [33.7941108, 41.8346819], [33.8020498, 41.8317243], [33.808401, 41.8264002], [33.8340995, 41.8141538], [33.8421676, 41.8065531], [33.8431707, 41.8036911], [33.8537937, 41.8018179], [33.8733356, 41.8084237], [33.8844097, 41.8277653], [33.8815783, 41.8366777], [33.8811314, 41.8554272], [33.893395, 41.851834], [33.9128883, 41.8542825]]], &quot;type&quot;: &quot;Polygon&quot;}, &quot;id&quot;: &quot;0&quot;, &quot;type&quot;: &quot;Feature&quot;}], &quot;type&quot;: &quot;FeatureCollection&quot;});\n",
       "\n",
       "        \n",
       "    \n",
       "            geo_json_3c910b158102f95881028bc506c100e3.bindTooltip(\n",
       "                `&lt;div&gt;\n",
       "                     İnebolu: 212 kişi, maks 1.4 m\n",
       "                 &lt;/div&gt;`,\n",
       "                {\n",
       "  &quot;sticky&quot;: true,\n",
       "}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            geo_json_3c910b158102f95881028bc506c100e3.addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "    \n",
       "            var layer_control_1d234bca1a68b47e74be52ba74b9f038_layers = {\n",
       "                base_layers : {\n",
       "                    &quot;openstreetmap&quot; : tile_layer_8ef93413fc0b4aecacd6b7eb65b600b3,\n",
       "                },\n",
       "                overlays :  {\n",
       "                    &quot;Su derinli\\u011fi (m)&quot; : image_overlay_fbcb4295205a3e8f54bd712db58c2422,\n",
       "                    &quot;A\\u015f\\u0131lma olas\\u0131l\\u0131\\u011f\\u0131 (\\u003e0,3 m)&quot; : image_overlay_a9205b942cbf5ece2434812ac5b8fa04,\n",
       "                    &quot;Devrekani&quot; : geo_json_ed4765b32d940951e089761d58a1bd03,\n",
       "                    &quot;K\\u00fcre&quot; : geo_json_c746a6744f25844cf23d87e07aac40a1,\n",
       "                    &quot;Ta\\u015fk\\u00f6pr\\u00fc&quot; : geo_json_b766adbbc6f3abe89b267a40cc8832e6,\n",
       "                    &quot;\\u00c7atalzeytin&quot; : geo_json_beb85619729e2a7fd708a823bf9af9d1,\n",
       "                    &quot;Bozkurt&quot; : geo_json_56400531c49e8816888378ae870b0157,\n",
       "                    &quot;Abana&quot; : geo_json_52d275b28295320903d2233b0c9eda08,\n",
       "                    &quot;\\u0130nebolu&quot; : geo_json_3c910b158102f95881028bc506c100e3,\n",
       "                },\n",
       "            };\n",
       "            let layer_control_1d234bca1a68b47e74be52ba74b9f038 = L.control.layers(\n",
       "                layer_control_1d234bca1a68b47e74be52ba74b9f038_layers.base_layers,\n",
       "                layer_control_1d234bca1a68b47e74be52ba74b9f038_layers.overlays,\n",
       "                {\n",
       "  &quot;position&quot;: &quot;topright&quot;,\n",
       "  &quot;collapsed&quot;: true,\n",
       "  &quot;autoZIndex&quot;: true,\n",
       "}\n",
       "            ).addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "\n",
       "        \n",
       "    \n",
       "            var rectangle_23ac63cb86c81c7dc7d769ccdd01a388 = L.rectangle(\n",
       "                [[41.725, 33.825], [42.025, 34.125]],\n",
       "                {&quot;bubblingMouseEvents&quot;: true, &quot;color&quot;: &quot;#2b6cb0&quot;, &quot;dashArray&quot;: null, &quot;dashOffset&quot;: null, &quot;fill&quot;: false, &quot;fillColor&quot;: &quot;#2b6cb0&quot;, &quot;fillOpacity&quot;: 0.2, &quot;fillRule&quot;: &quot;evenodd&quot;, &quot;lineCap&quot;: &quot;round&quot;, &quot;lineJoin&quot;: &quot;round&quot;, &quot;noClip&quot;: false, &quot;opacity&quot;: 1.0, &quot;smoothFactor&quot;: 1.0, &quot;stroke&quot;: true, &quot;weight&quot;: 1}\n",
       "            ).addTo(map_72c2b33363ec242d6f3f76eeac1096b5);\n",
       "        \n",
       "&lt;/script&gt;\n",
       "&lt;/html&gt;\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
      ]
     },
     "metadata": {},
     "execution_count": 7
    }
   ],
   "source": "#@title 6 · İnteraktif harita (folium) { display-mode: \"form\" }\nimport numpy as np, folium, matplotlib, matplotlib.pyplot as plt\nfrom matplotlib import colors\ns, w, n, e = cfg.bbox\ndepth = res[\"depth\"]; vmax = max(float(np.nanpercentile(depth, 99.5)), 0.5)\nrgba = plt.get_cmap(\"Blues\")(np.clip(depth / vmax, 0, 1)); rgba[..., 3] = np.where(depth > 0.05, 0.85, 0.0)\nm = folium.Map(location=[(s+n)/2, (w+e)/2], zoom_start=11, tiles=\"OpenStreetMap\")\nfolium.raster_layers.ImageOverlay(image=(rgba*255).astype(\"uint8\"), bounds=[[s, w], [n, e]], opacity=0.9, name=\"Su derinliği (m)\").add_to(m)\nif res.get(\"mc_riv\") is not None:\n    pr = res[\"mc_riv\"][\"exceed_prob\"]; rg = plt.get_cmap(\"YlOrRd\")(np.clip(pr, 0, 1)); rg[..., 3] = np.where(pr > 0.05, 0.7, 0.0)\n    folium.raster_layers.ImageOverlay(image=(rg*255).astype(\"uint8\"), bounds=[[s, w], [n, e]], opacity=0.8, name=\"Aşılma olasılığı (>0,3 m)\", show=False).add_to(m)\nfor ft in te.GeoBoundariesClient().features_in_bbox(cfg.bbox, \"ADM2\"):\n    fs, fw, fn, fe = ft[\"bbox\"]; d = res[\"impact\"].get(\"districts\")\n    row = d[d.ilce == ft[\"name\"]] if d is not None else None\n    txt = f\"{ft['name']}: {row.etkilenen_nufus.iloc[0]:,.0f} kişi, maks {row.maks_derinlik_m.iloc[0]:.1f} m\" if row is not None and len(row) else ft[\"name\"]\n    folium.GeoJson(ft[\"geometry\"], name=ft[\"name\"], style_function=lambda x: dict(color=\"#555\", weight=1, fill=False), tooltip=txt).add_to(m)\nfolium.LayerControl().add_to(m)\nfolium.Rectangle([[s, w], [n, e]], color=\"#2b6cb0\", weight=1, fill=False).add_to(m)\nm\n"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "6e3f9100",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "6e3f9100",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790696144134,
     "user_tz": -180,
     "elapsed": 129889,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "53f7a668-5db6-4bd6-d531-e94727946337"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:34 INFO [DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~96 m\n",
      "INFO:trflood:[DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~96 m\n",
      "15:33:34 INFO [Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %0.2, su %16.0\n",
      "INFO:trflood:[Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %0.2, su %16.0\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 1/8 Arazi: DEM + arazi örtüsü + HAND\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:35 INFO [HAND] computed (GLO-30 DEM, D8): ok dere hücresi 3094, kara %83\n",
      "INFO:trflood:[HAND] computed (GLO-30 DEM, D8): ok dere hücresi 3094, kara %83\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 2/8 Katmanlar: nüfus, ilçe sınırları, toprak\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:35 WARNING WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "WARNING:trflood:WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "15:33:35 INFO [Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 15,356\n",
      "INFO:trflood:[Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 15,356\n",
      "15:33:36 INFO [İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 7 ilçe\n",
      "INFO:trflood:[İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 7 ilçe\n",
      "15:33:39 INFO [Toprak] ISRIC SoilGrids v2: ok HSG B {'clay': 25.9, 'sand': 34.1}\n",
      "INFO:trflood:[Toprak] ISRIC SoilGrids v2: ok HSG B {'clay': 25.9, 'sand': 34.1}\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 3/8 Yağış ve gözlemler\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:39 INFO [Yağış] Open-Meteo arşiv (ERA5/ERA5-Land): ok 2021-08-08→2021-08-14, toplam 111.2 mm\n",
      "INFO:trflood:[Yağış] Open-Meteo arşiv (ERA5/ERA5-Land): ok 2021-08-08→2021-08-14, toplam 111.2 mm\n",
      "15:33:39 INFO [Yağış kontrol] CHIRPS v2.0 0,05°: ok olay günleri toplam 192.3 mm\n",
      "INFO:trflood:[Yağış kontrol] CHIRPS v2.0 0,05°: ok olay günleri toplam 192.3 mm\n",
      "15:33:39 WARNING [Yağış ölçekleme] MGM 2021 Yıllık İklim Raporu (Bozkurt/Mamatlar, 3 gün): uygulandı ERA5 90 mm → 451.7 mm\n",
      "WARNING:trflood:[Yağış ölçekleme] MGM 2021 Yıllık İklim Raporu (Bozkurt/Mamatlar, 3 gün): uygulandı ERA5 90 mm → 451.7 mm\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 4/8 Nehir debisi (GloFAS) ve eğitim serileri\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:41 INFO [GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (41.981, 33.949) ort. 3.1 m³/s\n",
      "INFO:trflood:[GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (41.981, 33.949) ort. 3.1 m³/s\n",
      "15:33:42 INFO [Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 18 gün, maks 6.9 m³/s\n",
      "INFO:trflood:[Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 18 gün, maks 6.9 m³/s\n",
      "15:33:42 INFO [QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "INFO:trflood:[QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "15:33:45 INFO [MeteoUyarı] MGM meteoalarm/today: ok Kastamonu: yellow\n",
      "INFO:trflood:[MeteoUyarı] MGM meteoalarm/today: ok Kastamonu: yellow\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 5/8 Hidroloji: 5 klasik model + GR4J\n",
      "[bozkurt_2021] 6/8 Taşma: HAND nehir taşkını + 2B plüvyal otomat + Monte Carlo\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:49 INFO [Doğrulama] CEMS GFM Sentinel-1 taşkın yayılımı (EODC): ok 7 sahne, S1 4 hücre, CSI 0.00\n",
      "INFO:trflood:[Doğrulama] CEMS GFM Sentinel-1 taşkın yayılımı (EODC): ok 7 sahne, S1 4 hücre, CSI 0.00\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 7/8 Kuantum: VQC tahmin + QUBO ekip tahsisi\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:33:57 INFO [QML] PennyLane VQC (default.qubit): ok test RMSE 2.6\n",
      "INFO:trflood:[QML] PennyLane VQC (default.qubit): ok test RMSE 2.6\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[bozkurt_2021] 8/8 Etki, ekranlar, rapor\n",
      "[bozkurt_2021] Tamamlandı: trflood_out/bozkurt_2021_historical_20260929_1533 (27 s) → paket bozkurt_2021_historical_20260929_1533_paket.zip\n",
      "[istanbul_2023] 1/8 Arazi: DEM + arazi örtüsü + HAND\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:34:06 INFO [DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~58 m\n",
      "INFO:trflood:[DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~58 m\n",
      "15:34:09 INFO [Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %50.3, su %10.2\n",
      "INFO:trflood:[Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %50.3, su %10.2\n",
      "15:34:10 INFO [HAND] computed (GLO-30 DEM, D8): ok dere hücresi 1949, kara %89\n",
      "INFO:trflood:[HAND] computed (GLO-30 DEM, D8): ok dere hücresi 1949, kara %89\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[istanbul_2023] 2/8 Katmanlar: nüfus, ilçe sınırları, toprak\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:34:10 WARNING WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "WARNING:trflood:WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "15:34:10 INFO [Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 3,063,581\n",
      "INFO:trflood:[Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 3,063,581\n",
      "15:34:11 INFO [İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 13 ilçe\n",
      "INFO:trflood:[İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 13 ilçe\n",
      "15:34:37 WARNING [Toprak] SoilGrids: varsayılan B HTTPSConnectionPool(host='rest.isric.org', port=443): Read timed out. (read time\n",
      "WARNING:trflood:[Toprak] SoilGrids: varsayılan B HTTPSConnectionPool(host='rest.isric.org', port=443): Read timed out. (read time\n",
      "15:34:37 INFO [Yağış] Open-Meteo arşiv (ERA5/ERA5-Land): ok 2023-09-03→2023-09-07, toplam 4.0 mm\n",
      "INFO:trflood:[Yağış] Open-Meteo arşiv (ERA5/ERA5-Land): ok 2023-09-03→2023-09-07, toplam 4.0 mm\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[istanbul_2023] 3/8 Yağış ve gözlemler\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:34:38 INFO [Yağış kontrol] CHIRPS v2.0 0,05°: ok olay günleri toplam 0.0 mm\n",
      "INFO:trflood:[Yağış kontrol] CHIRPS v2.0 0,05°: ok olay günleri toplam 0.0 mm\n",
      "15:34:38 WARNING [Yağış olay hiyetografı] İstanbul Valiliği basın açıklaması 2023/72 (18:30–21:30 yerel): uygulandı ERA5 olay penceresi 3 mm → 125.0 mm / 3 s\n",
      "WARNING:trflood:[Yağış olay hiyetografı] İstanbul Valiliği basın açıklaması 2023/72 (18:30–21:30 yerel): uygulandı ERA5 olay penceresi 3 mm → 125.0 mm / 3 s\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[istanbul_2023] 4/8 Nehir debisi (GloFAS) ve eğitim serileri\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:34:39 INFO [GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (40.981, 28.761) ort. 1.8 m³/s\n",
      "INFO:trflood:[GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (40.981, 28.761) ort. 1.8 m³/s\n",
      "15:34:39 INFO [Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 16 gün, maks 1.3 m³/s\n",
      "INFO:trflood:[Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 16 gün, maks 1.3 m³/s\n",
      "15:34:40 INFO [QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "INFO:trflood:[QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "15:34:40 INFO [MeteoUyarı] MGM meteoalarm/today: ok İstanbul: yellow\n",
      "INFO:trflood:[MeteoUyarı] MGM meteoalarm/today: ok İstanbul: yellow\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[istanbul_2023] 5/8 Hidroloji: 5 klasik model + GR4J\n",
      "[istanbul_2023] 6/8 Taşma: HAND nehir taşkını + 2B plüvyal otomat + Monte Carlo\n",
      "[istanbul_2023] 7/8 Kuantum: VQC tahmin + QUBO ekip tahsisi\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:35:41 INFO [QML] PennyLane VQC (default.qubit): ok test RMSE 0.9\n",
      "INFO:trflood:[QML] PennyLane VQC (default.qubit): ok test RMSE 0.9\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[istanbul_2023] 8/8 Etki, ekranlar, rapor\n",
      "[istanbul_2023] Tamamlandı: trflood_out/istanbul_2023_historical_20260929_1534 (103 s) → paket istanbul_2023_historical_20260929_1534_paket.zip\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "                                               olay             tip  yagis_mm  \\\n",
       "0            Kastamonu Bozkurt – Ezine Çayı Taşkını  riverine_flash       473   \n",
       "1  İstanbul Başakşehir–Küçükçekmece Kentsel Taşkını   urban_pluvial       126   \n",
       "\n",
       "   tepe_m3s            model  seviye_m  alan_km2   nufus           hasar  \\\n",
       "0      1424  SCS-CN + SCS UH      2.26      50.1    1514  534.6 milyon ₺   \n",
       "1      1049  SCS-CN + SCS UH      0.00      27.8  149735   9.28 milyar ₺   \n",
       "\n",
       "                    uyari  qml_rmse  \\\n",
       "0  Kırmızı — acil tahliye      2.56   \n",
       "1  Kırmızı — acil tahliye      0.89   \n",
       "\n",
       "                                              paket  \n",
       "0   bozkurt_2021_historical_20260929_1533_paket.zip  \n",
       "1  istanbul_2023_historical_20260929_1534_paket.zip  "
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-f6ce792c-c276-4730-be3a-ae0637d98af6\" class=\"colab-df-container\">\n",
       "    <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>olay</th>\n",
       "      <th>tip</th>\n",
       "      <th>yagis_mm</th>\n",
       "      <th>tepe_m3s</th>\n",
       "      <th>model</th>\n",
       "      <th>seviye_m</th>\n",
       "      <th>alan_km2</th>\n",
       "      <th>nufus</th>\n",
       "      <th>hasar</th>\n",
       "      <th>uyari</th>\n",
       "      <th>qml_rmse</th>\n",
       "      <th>paket</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Kastamonu Bozkurt – Ezine Çayı Taşkını</td>\n",
       "      <td>riverine_flash</td>\n",
       "      <td>473</td>\n",
       "      <td>1424</td>\n",
       "      <td>SCS-CN + SCS UH</td>\n",
       "      <td>2.26</td>\n",
       "      <td>50.1</td>\n",
       "      <td>1514</td>\n",
       "      <td>534.6 milyon ₺</td>\n",
       "      <td>Kırmızı — acil tahliye</td>\n",
       "      <td>2.56</td>\n",
       "      <td>bozkurt_2021_historical_20260929_1533_paket.zip</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>İstanbul Başakşehir–Küçükçekmece Kentsel Taşkını</td>\n",
       "      <td>urban_pluvial</td>\n",
       "      <td>126</td>\n",
       "      <td>1049</td>\n",
       "      <td>SCS-CN + SCS UH</td>\n",
       "      <td>0.00</td>\n",
       "      <td>27.8</td>\n",
       "      <td>149735</td>\n",
       "      <td>9.28 milyar ₺</td>\n",
       "      <td>Kırmızı — acil tahliye</td>\n",
       "      <td>0.89</td>\n",
       "      <td>istanbul_2023_historical_20260929_1534_paket.zip</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "    <div class=\"colab-df-buttons\">\n",
       "\n",
       "  <div class=\"colab-df-container\">\n",
       "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-f6ce792c-c276-4730-be3a-ae0637d98af6')\"\n",
       "            title=\"Convert this dataframe to an interactive table.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
       "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "\n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    .colab-df-buttons div {\n",
       "      margin-bottom: 4px;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "    <script>\n",
       "      const buttonEl =\n",
       "        document.querySelector('#df-f6ce792c-c276-4730-be3a-ae0637d98af6 button.colab-df-convert');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      async function convertToInteractive(key) {\n",
       "        const element = document.querySelector('#df-f6ce792c-c276-4730-be3a-ae0637d98af6');\n",
       "        const dataTable =\n",
       "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                    [key], {});\n",
       "        if (!dataTable) return;\n",
       "\n",
       "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "          + ' to learn more about interactive tables.';\n",
       "        element.innerHTML = '';\n",
       "        dataTable['output_type'] = 'display_data';\n",
       "        await google.colab.output.renderOutput(dataTable, element);\n",
       "        const docLink = document.createElement('div');\n",
       "        docLink.innerHTML = docLinkHtml;\n",
       "        element.appendChild(docLink);\n",
       "      }\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "\n",
       "    </div>\n",
       "  </div>\n"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "dataframe",
       "summary": "{\n  \"name\": \"    print(\\\"run_poc kutusunu i\\u015faretleyip h\\u00fccreyi \\u00e7al\\u0131\\u015ft\\u0131r\\u0131n\",\n  \"rows\": 2,\n  \"fields\": [\n    {\n      \"column\": \"olay\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"\\u0130stanbul Ba\\u015fak\\u015fehir\\u2013K\\u00fc\\u00e7\\u00fck\\u00e7ekmece Kentsel Ta\\u015fk\\u0131n\\u0131\",\n          \"Kastamonu Bozkurt \\u2013 Ezine \\u00c7ay\\u0131 Ta\\u015fk\\u0131n\\u0131\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"tip\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"urban_pluvial\",\n          \"riverine_flash\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"yagis_mm\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 245,\n        \"min\": 126,\n        \"max\": 473,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          126,\n          473\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"tepe_m3s\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 265,\n        \"min\": 1049,\n        \"max\": 1424,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          1049,\n          1424\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"model\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"SCS-CN + SCS UH\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"seviye_m\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1.5980613254815972,\n        \"min\": 0.0,\n        \"max\": 2.26,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          0.0\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"alan_km2\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 15.76848122046001,\n        \"min\": 27.8,\n        \"max\": 50.1,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          27.8\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"nufus\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 104808,\n        \"min\": 1514,\n        \"max\": 149735,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          149735\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"hasar\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"9.28 milyar \\u20ba\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"uyari\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 1,\n        \"samples\": [\n          \"K\\u0131rm\\u0131z\\u0131 \\u2014 acil tahliye\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"qml_rmse\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1.1808683245815343,\n        \"min\": 0.89,\n        \"max\": 2.56,\n        \"num_unique_values\": 2,\n        \"samples\": [\n          0.89\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"paket\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"istanbul_2023_historical_20260929_1534_paket.zip\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    }
   ],
   "source": "#@title 7 · Çift-şehir POC — Bozkurt 2021 (nehir) + İstanbul 2023 (kentsel) { display-mode: \"form\" }\n#@markdown Malezya Shah Alam / Kota Bharu çiftinin Türkiye karşılığı. Her ikisi ardışık çalıştırılır ve karşılaştırma tablosu üretilir.\nrun_poc = True  #@param {type:\"boolean\"}\nimport copy, pandas as pd\npoc_results = {}\nif run_poc:\n    for key in te.DEFAULT_POC_PAIR:\n        c = copy.deepcopy(cfg); c.mode, c.scope, c.event_key, c.flood_type, c.bbox, c.start, c.end = \"historical\", \"event\", key, \"auto\", None, None, None\n        poc_results[key] = te.run_pipeline(c, progress=lambda m, k=key: print(f\"[{k}] {m}\"))\n    rows = []\n    for k, r in poc_results.items():\n        rows.append(dict(olay=r[\"title\"], tip=te.EVENTS[k][\"tip\"], yagis_mm=round(float(r[\"rain\"][\"rain\"].sum())), tepe_m3s=round(r[\"hydro\"][\"peak_m3s\"]),\n                         model=r[\"hydro\"][\"best_model\"], seviye_m=round(r[\"hydro\"].get(\"stage_m\", 0), 2), alan_km2=round(r[\"impact\"][\"exposed_area_km2\"], 1),\n                         nufus=round(r[\"impact\"][\"exposed_pop\"]), hasar=te._fmt_try(r[\"impact\"][\"loss_try\"]), uyari=r[\"warning\"][1],\n                         qml_rmse=round(r[\"qml\"][\"scores\"][\"QML-VQC\"][\"RMSE\"], 2) if r.get(\"qml\") else None, paket=r[\"bundle\"].name))\n    display(pd.DataFrame(rows))\nelse:\n    print(\"run_poc kutusunu işaretleyip hücreyi çalıştırın.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b61a4554",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "b61a4554",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790696343615,
     "user_tz": -180,
     "elapsed": 142600,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "35419ece-5a59-4349-cbde-40530226f4df"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "   Adana: 24 mm, GloFAS ×5.3, MGM none\n",
      "   Adıyaman: 15 mm, GloFAS ×1.0, MGM none\n",
      "   Afyonkarahisar: 5 mm, GloFAS ×10.4, MGM none\n",
      "   Ağrı: 10 mm, GloFAS ×0.9, MGM none\n",
      "   Amasya: 5 mm, GloFAS ×1.6, MGM none\n",
      "   Ankara: 5 mm, GloFAS ×4.0, MGM none\n",
      "   Antalya: 2 mm, GloFAS ×1.8, MGM none\n",
      "   Artvin: 26 mm, GloFAS ×1.1, MGM none\n",
      "   Aydın: 0 mm, GloFAS ×2.7, MGM none\n",
      "   Balıkesir: 9 mm, GloFAS ×2.9, MGM none\n",
      "   Bilecik: 24 mm, GloFAS ×6.1, MGM none\n",
      "   Bingöl: 18 mm, GloFAS ×0.8, MGM none\n",
      "   Bitlis: 18 mm, GloFAS ×0.0, MGM none\n",
      "   Bolu: 22 mm, GloFAS ×6.6, MGM none\n",
      "   Burdur: 2 mm, GloFAS ×1.3, MGM none\n",
      "   Bursa: 54 mm, GloFAS ×17.3, MGM yellow\n",
      "   Çanakkale: 7 mm, GloFAS ×1.0, MGM none\n",
      "   Çankırı: 4 mm, GloFAS ×1.9, MGM none\n",
      "   Çorum: 5 mm, GloFAS ×1.2, MGM none\n",
      "   Denizli: 3 mm, GloFAS ×7.7, MGM none\n",
      "   Diyarbakır: 14 mm, GloFAS ×1.0, MGM none\n",
      "   Edirne: 4 mm, GloFAS ×2.7, MGM none\n",
      "   Elazığ: 27 mm, GloFAS ×2.1, MGM none\n",
      "   Erzincan: 11 mm, GloFAS ×1.2, MGM none\n",
      "   Erzurum: 20 mm, GloFAS ×0.9, MGM none\n",
      "   Eskişehir: 10 mm, GloFAS ×7.4, MGM none\n",
      "   Gaziantep: 1 mm, GloFAS ×1.2, MGM none\n",
      "   Giresun: 13 mm, GloFAS ×1.6, MGM none\n",
      "   Gümüşhane: 11 mm, GloFAS ×1.2, MGM none\n",
      "   Hakkari: 3 mm, GloFAS ×0.6, MGM none\n",
      "   Hatay: 0 mm, GloFAS ×1.5, MGM none\n",
      "   Isparta: 5 mm, GloFAS ×1.0, MGM none\n",
      "   Mersin: 30 mm, GloFAS ×1.6, MGM none\n",
      "   İstanbul: 27 mm, GloFAS ×10.5, MGM yellow\n",
      "   İzmir: 0 mm, GloFAS ×1.5, MGM none\n",
      "   Kars: 18 mm, GloFAS ×0.5, MGM none\n",
      "   Kastamonu: 3 mm, GloFAS ×1.0, MGM yellow\n",
      "   Kayseri: 0 mm, GloFAS ×5.8, MGM none\n",
      "   Kırklareli: 8 mm, GloFAS ×2.8, MGM none\n",
      "   Kırşehir: 2 mm, GloFAS ×1.0, MGM none\n",
      "   Kocaeli: 41 mm, GloFAS ×5.7, MGM yellow\n",
      "   Konya: 0 mm, GloFAS ×1.7, MGM none\n",
      "   Kütahya: 2 mm, GloFAS ×4.9, MGM none\n",
      "   Malatya: 3 mm, GloFAS ×15.0, MGM none\n",
      "   Manisa: 1 mm, GloFAS ×1.4, MGM none\n",
      "   Kahramanmaraş: 13 mm, GloFAS ×1.2, MGM none\n",
      "   Mardin: 4 mm, GloFAS ×1.0, MGM none\n",
      "   Muğla: 6 mm, GloFAS ×1.1, MGM none\n",
      "   Muş: 5 mm, GloFAS ×1.1, MGM none\n",
      "   Nevşehir: 1 mm, GloFAS ×2.2, MGM none\n",
      "   Niğde: 3 mm, GloFAS ×1.9, MGM none\n",
      "   Ordu: 3 mm, GloFAS ×1.6, MGM none\n",
      "   Rize: 32 mm, GloFAS ×1.7, MGM none\n",
      "   Sakarya: 56 mm, GloFAS ×1.7, MGM yellow\n",
      "   Samsun: 8 mm, GloFAS ×1.5, MGM none\n",
      "   Siirt: 20 mm, GloFAS ×0.9, MGM none\n",
      "   Sinop: 12 mm, GloFAS ×nan, MGM yellow\n",
      "   Sivas: 3 mm, GloFAS ×1.2, MGM none\n",
      "   Tekirdağ: 9 mm, GloFAS ×4.1, MGM none\n",
      "   Tokat: 17 mm, GloFAS ×1.7, MGM none\n",
      "   Trabzon: 6 mm, GloFAS ×1.7, MGM none\n",
      "   Tunceli: 10 mm, GloFAS ×1.0, MGM none\n",
      "   Şanlıurfa: 5 mm, GloFAS ×1.0, MGM none\n",
      "   Uşak: 1 mm, GloFAS ×6.7, MGM none\n",
      "   Van: 2 mm, GloFAS ×3.6, MGM none\n",
      "   Yozgat: 10 mm, GloFAS ×1.2, MGM none\n",
      "   Zonguldak: 43 mm, GloFAS ×10.1, MGM yellow\n",
      "   Aksaray: 1 mm, GloFAS ×4.8, MGM none\n",
      "   Bayburt: 22 mm, GloFAS ×0.9, MGM none\n",
      "   Karaman: 0 mm, GloFAS ×1.9, MGM none\n",
      "   Kırıkkale: 17 mm, GloFAS ×1.3, MGM none\n",
      "   Batman: 10 mm, GloFAS ×0.8, MGM none\n",
      "   Şırnak: 15 mm, GloFAS ×0.0, MGM none\n",
      "   Bartın: 18 mm, GloFAS ×1.5, MGM none\n",
      "   Ardahan: 18 mm, GloFAS ×1.0, MGM none\n",
      "   Iğdır: 3 mm, GloFAS ×1.5, MGM none\n",
      "   Yalova: 47 mm, GloFAS ×8.3, MGM yellow\n",
      "   Karabük: 12 mm, GloFAS ×4.1, MGM none\n",
      "   Kilis: 3 mm, GloFAS ×1.0, MGM none\n",
      "   Osmaniye: 29 mm, GloFAS ×2.7, MGM none\n",
      "   Düzce: 46 mm, GloFAS ×9.1, MGM yellow\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "    plaka              il    lat    lon  yagis_mm  glofas_oran mgm_uyari  \\\n",
       "0      16           Bursa  40.19  29.06      53.7        17.34    yellow   \n",
       "1      81           Düzce  40.84  31.16      46.5         9.10    yellow   \n",
       "2      77          Yalova  40.65  29.27      46.7         8.25    yellow   \n",
       "3      67       Zonguldak  41.45  31.79      43.4        10.08    yellow   \n",
       "4      54         Sakarya  40.77  30.40      55.9         1.68    yellow   \n",
       "5      41         Kocaeli  40.77  29.92      40.9         5.69    yellow   \n",
       "6      34        İstanbul  41.01  28.98      27.2        10.50    yellow   \n",
       "7      11         Bilecik  40.14  29.98      23.8         6.10      none   \n",
       "8      14            Bolu  40.74  31.61      21.6         6.63      none   \n",
       "9       1           Adana  37.00  35.32      23.8         5.32      none   \n",
       "10     80        Osmaniye  37.07  36.25      28.5         2.73      none   \n",
       "11     53            Rize  41.02  40.52      32.1         1.70      none   \n",
       "12     33          Mersin  36.81  34.64      29.8         1.60      none   \n",
       "13     23          Elazığ  38.68  39.22      27.1         2.07      none   \n",
       "14     44         Malatya  38.35  38.31       2.8        14.98      none   \n",
       "15     26       Eskişehir  39.78  30.52      10.1         7.36      none   \n",
       "16      3  Afyonkarahisar  38.76  30.54       5.2        10.41      none   \n",
       "17      8          Artvin  41.18  41.82      26.0         1.07      none   \n",
       "18     78         Karabük  41.20  32.63      12.5         4.14      none   \n",
       "19     20         Denizli  37.78  29.09       2.7         7.75      none   \n",
       "\n",
       "    maks_saatlik_mm  risk_endeksi  \n",
       "0               8.7          2.62  \n",
       "1               6.9          2.05  \n",
       "2               3.6          2.02  \n",
       "3               5.7          1.98  \n",
       "4               7.1          1.77  \n",
       "5               5.2          1.64  \n",
       "6               4.4          1.38  \n",
       "7               4.6          0.82  \n",
       "8               6.4          0.77  \n",
       "9               3.3          0.76  \n",
       "10              5.0          0.69  \n",
       "11              4.0          0.67  \n",
       "12              2.4          0.56  \n",
       "13              7.4          0.54  \n",
       "14              1.1          0.41  \n",
       "15              1.6          0.37  \n",
       "16              0.4          0.34  \n",
       "17              4.3          0.31  \n",
       "18              1.6          0.23  \n",
       "19              1.1          0.11  "
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-e965fdd4-a266-438e-b0ff-ae02a15c3bf1\" class=\"colab-df-container\">\n",
       "    <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>plaka</th>\n",
       "      <th>il</th>\n",
       "      <th>lat</th>\n",
       "      <th>lon</th>\n",
       "      <th>yagis_mm</th>\n",
       "      <th>glofas_oran</th>\n",
       "      <th>mgm_uyari</th>\n",
       "      <th>maks_saatlik_mm</th>\n",
       "      <th>risk_endeksi</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>16</td>\n",
       "      <td>Bursa</td>\n",
       "      <td>40.19</td>\n",
       "      <td>29.06</td>\n",
       "      <td>53.7</td>\n",
       "      <td>17.34</td>\n",
       "      <td>yellow</td>\n",
       "      <td>8.7</td>\n",
       "      <td>2.62</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>81</td>\n",
       "      <td>Düzce</td>\n",
       "      <td>40.84</td>\n",
       "      <td>31.16</td>\n",
       "      <td>46.5</td>\n",
       "      <td>9.10</td>\n",
       "      <td>yellow</td>\n",
       "      <td>6.9</td>\n",
       "      <td>2.05</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>77</td>\n",
       "      <td>Yalova</td>\n",
       "      <td>40.65</td>\n",
       "      <td>29.27</td>\n",
       "      <td>46.7</td>\n",
       "      <td>8.25</td>\n",
       "      <td>yellow</td>\n",
       "      <td>3.6</td>\n",
       "      <td>2.02</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>67</td>\n",
       "      <td>Zonguldak</td>\n",
       "      <td>41.45</td>\n",
       "      <td>31.79</td>\n",
       "      <td>43.4</td>\n",
       "      <td>10.08</td>\n",
       "      <td>yellow</td>\n",
       "      <td>5.7</td>\n",
       "      <td>1.98</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>54</td>\n",
       "      <td>Sakarya</td>\n",
       "      <td>40.77</td>\n",
       "      <td>30.40</td>\n",
       "      <td>55.9</td>\n",
       "      <td>1.68</td>\n",
       "      <td>yellow</td>\n",
       "      <td>7.1</td>\n",
       "      <td>1.77</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>41</td>\n",
       "      <td>Kocaeli</td>\n",
       "      <td>40.77</td>\n",
       "      <td>29.92</td>\n",
       "      <td>40.9</td>\n",
       "      <td>5.69</td>\n",
       "      <td>yellow</td>\n",
       "      <td>5.2</td>\n",
       "      <td>1.64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>34</td>\n",
       "      <td>İstanbul</td>\n",
       "      <td>41.01</td>\n",
       "      <td>28.98</td>\n",
       "      <td>27.2</td>\n",
       "      <td>10.50</td>\n",
       "      <td>yellow</td>\n",
       "      <td>4.4</td>\n",
       "      <td>1.38</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>11</td>\n",
       "      <td>Bilecik</td>\n",
       "      <td>40.14</td>\n",
       "      <td>29.98</td>\n",
       "      <td>23.8</td>\n",
       "      <td>6.10</td>\n",
       "      <td>none</td>\n",
       "      <td>4.6</td>\n",
       "      <td>0.82</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>14</td>\n",
       "      <td>Bolu</td>\n",
       "      <td>40.74</td>\n",
       "      <td>31.61</td>\n",
       "      <td>21.6</td>\n",
       "      <td>6.63</td>\n",
       "      <td>none</td>\n",
       "      <td>6.4</td>\n",
       "      <td>0.77</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>1</td>\n",
       "      <td>Adana</td>\n",
       "      <td>37.00</td>\n",
       "      <td>35.32</td>\n",
       "      <td>23.8</td>\n",
       "      <td>5.32</td>\n",
       "      <td>none</td>\n",
       "      <td>3.3</td>\n",
       "      <td>0.76</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>80</td>\n",
       "      <td>Osmaniye</td>\n",
       "      <td>37.07</td>\n",
       "      <td>36.25</td>\n",
       "      <td>28.5</td>\n",
       "      <td>2.73</td>\n",
       "      <td>none</td>\n",
       "      <td>5.0</td>\n",
       "      <td>0.69</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>53</td>\n",
       "      <td>Rize</td>\n",
       "      <td>41.02</td>\n",
       "      <td>40.52</td>\n",
       "      <td>32.1</td>\n",
       "      <td>1.70</td>\n",
       "      <td>none</td>\n",
       "      <td>4.0</td>\n",
       "      <td>0.67</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>33</td>\n",
       "      <td>Mersin</td>\n",
       "      <td>36.81</td>\n",
       "      <td>34.64</td>\n",
       "      <td>29.8</td>\n",
       "      <td>1.60</td>\n",
       "      <td>none</td>\n",
       "      <td>2.4</td>\n",
       "      <td>0.56</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>23</td>\n",
       "      <td>Elazığ</td>\n",
       "      <td>38.68</td>\n",
       "      <td>39.22</td>\n",
       "      <td>27.1</td>\n",
       "      <td>2.07</td>\n",
       "      <td>none</td>\n",
       "      <td>7.4</td>\n",
       "      <td>0.54</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>44</td>\n",
       "      <td>Malatya</td>\n",
       "      <td>38.35</td>\n",
       "      <td>38.31</td>\n",
       "      <td>2.8</td>\n",
       "      <td>14.98</td>\n",
       "      <td>none</td>\n",
       "      <td>1.1</td>\n",
       "      <td>0.41</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>26</td>\n",
       "      <td>Eskişehir</td>\n",
       "      <td>39.78</td>\n",
       "      <td>30.52</td>\n",
       "      <td>10.1</td>\n",
       "      <td>7.36</td>\n",
       "      <td>none</td>\n",
       "      <td>1.6</td>\n",
       "      <td>0.37</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>3</td>\n",
       "      <td>Afyonkarahisar</td>\n",
       "      <td>38.76</td>\n",
       "      <td>30.54</td>\n",
       "      <td>5.2</td>\n",
       "      <td>10.41</td>\n",
       "      <td>none</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.34</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>8</td>\n",
       "      <td>Artvin</td>\n",
       "      <td>41.18</td>\n",
       "      <td>41.82</td>\n",
       "      <td>26.0</td>\n",
       "      <td>1.07</td>\n",
       "      <td>none</td>\n",
       "      <td>4.3</td>\n",
       "      <td>0.31</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>78</td>\n",
       "      <td>Karabük</td>\n",
       "      <td>41.20</td>\n",
       "      <td>32.63</td>\n",
       "      <td>12.5</td>\n",
       "      <td>4.14</td>\n",
       "      <td>none</td>\n",
       "      <td>1.6</td>\n",
       "      <td>0.23</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>20</td>\n",
       "      <td>Denizli</td>\n",
       "      <td>37.78</td>\n",
       "      <td>29.09</td>\n",
       "      <td>2.7</td>\n",
       "      <td>7.75</td>\n",
       "      <td>none</td>\n",
       "      <td>1.1</td>\n",
       "      <td>0.11</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "    <div class=\"colab-df-buttons\">\n",
       "\n",
       "  <div class=\"colab-df-container\">\n",
       "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-e965fdd4-a266-438e-b0ff-ae02a15c3bf1')\"\n",
       "            title=\"Convert this dataframe to an interactive table.\"\n",
       "            style=\"display:none;\">\n",
       "\n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
       "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
       "  </svg>\n",
       "    </button>\n",
       "\n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    .colab-df-buttons div {\n",
       "      margin-bottom: 4px;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "    <script>\n",
       "      const buttonEl =\n",
       "        document.querySelector('#df-e965fdd4-a266-438e-b0ff-ae02a15c3bf1 button.colab-df-convert');\n",
       "      buttonEl.style.display =\n",
       "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "      async function convertToInteractive(key) {\n",
       "        const element = document.querySelector('#df-e965fdd4-a266-438e-b0ff-ae02a15c3bf1');\n",
       "        const dataTable =\n",
       "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                    [key], {});\n",
       "        if (!dataTable) return;\n",
       "\n",
       "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "          + ' to learn more about interactive tables.';\n",
       "        element.innerHTML = '';\n",
       "        dataTable['output_type'] = 'display_data';\n",
       "        await google.colab.output.renderOutput(dataTable, element);\n",
       "        const docLink = document.createElement('div');\n",
       "        docLink.innerHTML = docLinkHtml;\n",
       "        element.appendChild(docLink);\n",
       "      }\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "\n",
       "    </div>\n",
       "  </div>\n"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "dataframe",
       "summary": "{\n  \"name\": \"    print(\\\"run_screening kutusunu i\\u015faretleyip h\\u00fccreyi \\u00e7al\\u0131\\u015ft\\u0131r\\u0131n\",\n  \"rows\": 20,\n  \"fields\": [\n    {\n      \"column\": \"plaka\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 27,\n        \"min\": 1,\n        \"max\": 81,\n        \"num_unique_values\": 20,\n        \"samples\": [\n          16,\n          8,\n          26\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"il\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 20,\n        \"samples\": [\n          \"Bursa\",\n          \"Artvin\",\n          \"Eski\\u015fehir\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"lat\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 1.5722108971964157,\n        \"min\": 36.81,\n        \"max\": 41.45,\n        \"num_unique_values\": 19,\n        \"samples\": [\n          40.19,\n          41.01,\n          36.81\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"lon\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 4.137004096533728,\n        \"min\": 28.98,\n        \"max\": 41.82,\n        \"num_unique_values\": 20,\n        \"samples\": [\n          29.06,\n          41.82,\n          30.52\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"yagis_mm\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 16.209200603685744,\n        \"min\": 2.7,\n        \"max\": 55.9,\n        \"num_unique_values\": 19,\n        \"samples\": [\n          53.7,\n          40.9,\n          29.8\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"glofas_oran\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 4.507494928041051,\n        \"min\": 1.07,\n        \"max\": 17.34,\n        \"num_unique_values\": 20,\n        \"samples\": [\n          17.34,\n          1.07,\n          7.36\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"mgm_uyari\",\n      \"properties\": {\n        \"dtype\": \"category\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          \"none\",\n          \"yellow\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"maks_saatlik_mm\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 2.370076614351261,\n        \"min\": 0.4,\n        \"max\": 8.7,\n        \"num_unique_values\": 18,\n        \"samples\": [\n          8.7,\n          6.9\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"risk_endeksi\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0.7493618337590571,\n        \"min\": 0.11,\n        \"max\": 2.62,\n        \"num_unique_values\": 20,\n        \"samples\": [\n          2.62,\n          0.31\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "\n",
      "=== Detay: Bursa ===\n",
      "▶ 1/8 Arazi: DEM + arazi örtüsü + HAND\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:37:32 INFO [DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~78 m\n",
      "INFO:trflood:[DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~78 m\n",
      "15:37:33 INFO [Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %22.9, su %0.4\n",
      "INFO:trflood:[Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %22.9, su %0.4\n",
      "15:37:34 INFO [HAND] computed (GLO-30 DEM, D8): ok dere hücresi 4581, kara %99\n",
      "INFO:trflood:[HAND] computed (GLO-30 DEM, D8): ok dere hücresi 4581, kara %99\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "▶ 2/8 Katmanlar: nüfus, ilçe sınırları, toprak\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:37:34 WARNING WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "WARNING:trflood:WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "15:37:34 INFO [Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 1,456,484\n",
      "INFO:trflood:[Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 1,456,484\n",
      "15:37:35 INFO [İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 6 ilçe\n",
      "INFO:trflood:[İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 6 ilçe\n",
      "15:38:02 WARNING [Toprak] SoilGrids: varsayılan B HTTPSConnectionPool(host='rest.isric.org', port=443): Read timed out. (read time\n",
      "WARNING:trflood:[Toprak] SoilGrids: varsayılan B HTTPSConnectionPool(host='rest.isric.org', port=443): Read timed out. (read time\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "▶ 3/8 Yağış ve gözlemler\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:38:03 INFO [Yağış] Open-Meteo tahmin (best_match: ICON/GFS/ECMWF): ok toplam 101.7 mm, 144 saat\n",
      "INFO:trflood:[Yağış] Open-Meteo tahmin (best_match: ICON/GFS/ECMWF): ok toplam 101.7 mm, 144 saat\n",
      "15:38:05 INFO [Gözlem] MGM AWOS Yıldırım (18746): ok 24 s 41.06 mm\n",
      "INFO:trflood:[Gözlem] MGM AWOS Yıldırım (18746): ok 24 s 41.06 mm\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "▶ 4/8 Nehir debisi (GloFAS) ve eğitim serileri\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:38:07 INFO [GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (40.279, 28.890) ort. 8.7 m³/s\n",
      "INFO:trflood:[GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (40.279, 28.890) ort. 8.7 m³/s\n",
      "15:38:07 INFO [Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 35 gün, maks 43.6 m³/s\n",
      "INFO:trflood:[Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 35 gün, maks 43.6 m³/s\n",
      "15:38:08 INFO [QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "INFO:trflood:[QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "15:38:09 INFO [MeteoUyarı] MGM meteoalarm/today: ok Bursa: yellow\n",
      "INFO:trflood:[MeteoUyarı] MGM meteoalarm/today: ok Bursa: yellow\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "▶ 5/8 Hidroloji: 5 klasik model + GR4J\n",
      "▶ 6/8 Taşma: HAND nehir taşkını + 2B plüvyal otomat + Monte Carlo\n",
      "▶ 7/8 Kuantum: VQC tahmin + QUBO ekip tahsisi\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:38:57 INFO [QML] PennyLane VQC (default.qubit): ok test RMSE 5.5\n",
      "INFO:trflood:[QML] PennyLane VQC (default.qubit): ok test RMSE 5.5\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "▶ 8/8 Etki, ekranlar, rapor\n",
      "▶ Tamamlandı: trflood_out/bursa_forecast_20260929_1537 (95 s) → paket bursa_forecast_20260929_1537_paket.zip\n",
      "Bursa → Sarı — dikkat | etkilenen nüfus 0 | paket bursa_forecast_20260929_1537_paket.zip\n"
     ]
    }
   ],
   "source": "#@title 8 · Ulusal tarama — 81 il risk endeksi (≈3–5 dk) { display-mode: \"form\" }\n#@markdown Tahmin yağışı (Open-Meteo, 3 gün) + GloFAS debi anomalisi + MGM MeteoUyarı → il bazlı risk endeksi; en riskli il için detay çalıştırma (isteğe bağlı).\nrun_screening = True  #@param {type:\"boolean\"}\nscreening_days = 3  #@param {type:\"integer\"}\ndetail_top_k = 1  #@param {type:\"integer\"}\nif run_screening:\n    import matplotlib.pyplot as plt\n    scr = te.national_screening(days=screening_days, progress=lambda m: print(\"  \", m))\n    display(scr.head(20).round(2))\n    fig, ax = plt.subplots(figsize=(10, 5.5))\n    sc = ax.scatter(scr.lon, scr.lat, c=scr.risk_endeksi, s=40 + 60*scr.yagis_mm.fillna(0)/max(scr.yagis_mm.max(), 1), cmap=\"YlOrRd\", edgecolor=\"k\", linewidth=0.3)\n    for _, r in scr.head(8).iterrows(): ax.annotate(r.il, (r.lon, r.lat), fontsize=8, xytext=(3, 3), textcoords=\"offset points\")\n    ax.set_xlim(25.5, 45); ax.set_ylim(35.5, 42.5); ax.set_title(f\"Ulusal taşkın risk taraması — {screening_days} gün\"); plt.colorbar(sc, label=\"risk endeksi\"); plt.show()\n    scr.to_csv(\"ulusal_tarama.csv\", index=False)\n    for il_name in scr.head(detail_top_k).il:\n        import copy\n        c = copy.deepcopy(cfg); c.mode, c.scope, c.il, c.bbox, c.flood_type = \"forecast\", \"il\", il_name, None, \"both\"\n        c.half_deg = 0.12; c.resolve()\n        print(f\"\\n=== Detay: {il_name} ===\")\n        r = te.run_pipeline(c, progress=lambda m: print(\"▶\", m))\n        print(il_name, \"→\", r[\"warning\"][1], \"| etkilenen nüfus\", f\"{r['impact']['exposed_pop']:,.0f}\", \"| paket\", r[\"bundle\"].name)\nelse:\n    print(\"run_screening kutusunu işaretleyip hücreyi çalıştırın.\")\n"
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e85c3489",
   "metadata": {
    "id": "e85c3489",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790696387027,
     "user_tz": -180,
     "elapsed": 9,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    }
   },
   "outputs": [],
   "source": "#@title 9 · DSİ AGİ gözlem verisi ile değerlendirme (isteğe bağlı) { display-mode: \"form\" }\n#@markdown CSV sütunları: `tarih` (ISO) ve `debi_m3s`. DSİ Akım Gözlem Yıllığı'ndan çıkarılmış günlük seri yüklenirse modeller GloFAS yerine gözlemle puanlanır.\nupload_observed = False  #@param {type:\"boolean\"}\nif upload_observed:\n    from google.colab import files\n    up = files.upload()\n    for name in up:\n        obs = te.load_observed_discharge(name)\n        met = te.evaluate_models(res[\"hydro\"][\"sims\"], obs)\n        display(met.round(3)); print(\"Gözleme göre en iyi model:\", met.iloc[0][\"model\"])\n"
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "ee855f6b",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 87
    },
    "id": "ee855f6b",
    "executionInfo": {
     "status": "ok",
     "timestamp": 1790696415280,
     "user_tz": -180,
     "elapsed": 22114,
     "user": {
      "displayName": "Joseph Volkan ÖZCAN",
      "userId": "11389530967736397480"
     }
    },
    "outputId": "bd6e74b2-5ed8-456d-f638-16f262eb7a29"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Paket: trflood_out/bozkurt_2021_historical_20260929_1528_paket.zip | 4.1 MB\n",
      "Raporlar: ['TRFlood_Rapor_kastamonu_bozkurt__ezine_cayi_taskini.docx']\n",
      "Mounted at /content/drive\n",
      "Drive'a kopyalandı: /content/drive/MyDrive/TRFlood/raporlar\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ],
      "application/javascript": [
       "\n",
       "    async function download(id, filename, size) {\n",
       "      if (!google.colab.kernel.accessAllowed) {\n",
       "        return;\n",
       "      }\n",
       "      const div = document.createElement('div');\n",
       "      const label = document.createElement('label');\n",
       "      label.textContent = `Downloading \"${filename}\": `;\n",
       "      div.appendChild(label);\n",
       "      const progress = document.createElement('progress');\n",
       "      progress.max = size;\n",
       "      div.appendChild(progress);\n",
       "      document.body.appendChild(div);\n",
       "\n",
       "      const buffers = [];\n",
       "      let downloaded = 0;\n",
       "\n",
       "      const channel = await google.colab.kernel.comms.open(id);\n",
       "      // Send a message to notify the kernel that we're ready.\n",
       "      channel.send({})\n",
       "\n",
       "      for await (const message of channel.messages) {\n",
       "        // Send a message to notify the kernel that we're ready.\n",
       "        channel.send({})\n",
       "        if (message.buffers) {\n",
       "          for (const buffer of message.buffers) {\n",
       "            buffers.push(buffer);\n",
       "            downloaded += buffer.byteLength;\n",
       "            progress.value = downloaded;\n",
       "          }\n",
       "        }\n",
       "      }\n",
       "      const blob = new Blob(buffers, {type: 'application/binary'});\n",
       "      const a = document.createElement('a');\n",
       "      a.href = window.URL.createObjectURL(blob);\n",
       "      a.download = filename;\n",
       "      div.appendChild(a);\n",
       "      a.click();\n",
       "      div.remove();\n",
       "    }\n",
       "  "
      ]
     },
     "metadata": {}
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ],
      "application/javascript": [
       "download(\"download_47a7cafa-5db6-4bc1-ba1e-a3c42f389524\", \"bozkurt_2021_historical_20260929_1528_paket.zip\", 4126167)"
      ]
     },
     "metadata": {}
    }
   ],
   "source": "#@title 10 · Rapor paketini indir / Drive'a kopyala { display-mode: \"form\" }\ncopy_to_drive = True  #@param {type:\"boolean\"}\ndrive_folder = \"TRFlood/raporlar\"  #@param {type:\"string\"}\nfrom google.colab import files\nprint(\"Paket:\", res[\"bundle\"], \"|\", round(res[\"bundle\"].stat().st_size/1e6, 1), \"MB\")\nprint(\"Raporlar:\", [p.name for p in res[\"reports\"]])\nif copy_to_drive:\n    from google.colab import drive; import shutil, os\n    drive.mount(\"/content/drive\", force_remount=False)\n    dst = f\"/content/drive/MyDrive/{drive_folder}\"; os.makedirs(dst, exist_ok=True)\n    shutil.copy(res[\"bundle\"], dst); print(\"Drive'a kopyalandı:\", dst)\nfiles.download(str(res[\"bundle\"]))\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9bb787b6",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "9bb787b6",
    "outputId": "ae4c21e2-7aa2-42e5-ad71-8152f0daf488"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "15:40:25 INFO [DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~96 m\n",
      "INFO:trflood:[DEM] Copernicus GLO-30 (AWS, 1\"): ok ızgara (260, 260), ~96 m\n",
      "15:40:25 INFO [Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %0.2, su %16.0\n",
      "INFO:trflood:[Arazi örtüsü] ESA WorldCover 10 m (2021, CC BY 4.0): ok yapılaşmış %0.2, su %16.0\n",
      "15:40:26 INFO [HAND] computed (GLO-30 DEM, D8): ok dere hücresi 3094, kara %83\n",
      "INFO:trflood:[HAND] computed (GLO-30 DEM, D8): ok dere hücresi 3094, kara %83\n",
      "15:40:26 WARNING WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "WARNING:trflood:WorldPop okunamadı (vsicurl) tur_pop_2025_CN_100m_R2024B_v1.tif: Range downloading not supported by this server!\n",
      "15:40:26 INFO [Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 15,356\n",
      "INFO:trflood:[Nüfus] WorldPop TUR 2025 100 m (R2024B): ok toplam 15,356\n",
      "15:40:27 INFO [İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 7 ilçe\n",
      "INFO:trflood:[İdari sınır] geoBoundaries TUR ADM2 (ODbL): ok 7 ilçe\n",
      "15:40:54 WARNING [Toprak] SoilGrids: varsayılan B HTTPSConnectionPool(host='rest.isric.org', port=443): Read timed out. (read time\n",
      "WARNING:trflood:[Toprak] SoilGrids: varsayılan B HTTPSConnectionPool(host='rest.isric.org', port=443): Read timed out. (read time\n",
      "15:40:55 INFO [Yağış] Open-Meteo tahmin (best_match: ICON/GFS/ECMWF): ok toplam 46.4 mm, 120 saat\n",
      "INFO:trflood:[Yağış] Open-Meteo tahmin (best_match: ICON/GFS/ECMWF): ok toplam 46.4 mm, 120 saat\n",
      "15:40:58 INFO [Gözlem] MGM AWOS Bozkurt (17606): ok 24 s 23.52 mm\n",
      "INFO:trflood:[Gözlem] MGM AWOS Bozkurt (17606): ok 24 s 23.52 mm\n",
      "15:41:00 INFO [GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (41.981, 33.949) ort. 3.1 m³/s\n",
      "INFO:trflood:[GloFAS hücre seçimi] Open-Meteo Flood API 3×3 yoklama: ok (41.981, 33.949) ort. 3.1 m³/s\n",
      "15:41:01 INFO [Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 35 gün, maks 5.7 m³/s\n",
      "INFO:trflood:[Nehir debisi] GloFAS v4 (Open-Meteo Flood API): ok 35 gün, maks 5.7 m³/s\n",
      "15:41:02 INFO [QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "INFO:trflood:[QML eğitim serisi] Open-Meteo arşiv + GloFAS consolidated: ok 1096 gün\n",
      "15:41:02 INFO [MeteoUyarı] MGM meteoalarm/today: ok Kastamonu: yellow\n",
      "INFO:trflood:[MeteoUyarı] MGM meteoalarm/today: ok Kastamonu: yellow\n",
      "15:41:10 INFO [QML] PennyLane VQC (default.qubit): ok test RMSE 2.7\n",
      "INFO:trflood:[QML] PennyLane VQC (default.qubit): ok test RMSE 2.7\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "2026-09-29 15:41 → Kastamonu Bozkurt – Ezine Çayı Taşkını | Sarı — dikkat | nüfus 0 | bozkurt_2021_nowcast_20260929_1540_paket.zip\n"
     ]
    }
   ],
   "source": "#@title 11 · Periyodik çalıştırma (oturum içi) { display-mode: \"form\" }\n#@markdown Colab oturumu açıkken `run_frequency` ayarına göre döngü. Üretimde Cloud Run / Airflow / cron + bu modül (`python -c \"import trflood_engine as te; te.run_pipeline(te.RunConfig(mode='nowcast', scope='il', il='Rize'))\"`) önerilir.\nstart_loop = True  #@param {type:\"boolean\"}\niterations = 3  #@param {type:\"integer\"}\nif start_loop:\n    import time, copy\n    every_h = {\"hourly\": 1, \"daily\": 24, \"weekly\": 168}[cfg.run_frequency]\n    for i in range(iterations):\n        c = copy.deepcopy(cfg); c.mode = \"nowcast\" if cfg.mode == \"historical\" else cfg.mode; c.start = c.end = None; c.resolve()\n        r = te.run_pipeline(c, progress=lambda m: None)\n        print(time.strftime(\"%Y-%m-%d %H:%M\"), \"→\", r[\"title\"], \"|\", r[\"warning\"][1], \"| nüfus\", f\"{r['impact']['exposed_pop']:,.0f}\", \"|\", r[\"bundle\"].name)\n        if i < iterations - 1: time.sleep(every_h * 3600)\n"
  },
  {
   "cell_type": "markdown",
   "id": "12fce85e",
   "metadata": {
    "id": "12fce85e"
   },
   "source": "## Sınırlılıklar ve yol haritası\n\n**Bilinen sınırlılıklar**\n- ERA5/Open-Meteo yağışı konvektif ekstremleri ciddi ölçüde düşük gösterir (Bozkurt 2021: ERA5 ~90 mm vs MGM 451,7 mm). Referans olaylarda MGM istasyon toplamı/süresi ile **olay hiyetografı** yerleştirilir; canlı modda MGM AWOS 24 s toplamları ve MeteoUyarı seviyesi ile birlikte değerlendirin.\n- **GloFAS 5 km** küçük ve dik havzaları (Ezine Çayı gibi) çözemez; motor bu durumu tespit edip DSİ uygulamasına uygun **SCS-CN + sentetik birim hidrograf** yöntemine döner. Kalibrasyon için **DSİ AGİ** verisi (hücre 9) şarttır.\n- HAND + sentetik anahtar eğrisi ve 2B hücresel otomat **tarama** araçlarıdır; kanalizasyon/kültür kapasitesi tek bir parametre (`sewer_capacity_mm_h`) ile temsil edilir. Karar düzeyi çalışmalar için HEC-RAS 2D / LISFLOOD-FP gerekir.\n- Copernicus 30 m DEM kentsel mikro-topografyayı çözemez → **HGM SYM12** (kamu kurumları/üniversiteler) veya belediye LiDAR ile değiştirilmelidir.\n- Hasar eğrileri (JRC/Huizinga 2017) ve birim maliyetler **TL bazında kalibre edilmemiştir**; DASK taşkını kapsamadığından sigortalı pay varsayımdır.\n- Sentinel-1 GFM doğrulaması dar ve dik vadilerde (radar gölge/örtme) sınırlıdır; düşük CSI tek başına model hatası değildir.\n\n**Sonraki adımlar (BVK ürün yolu)**\n1. Erişim başvuruları: CDS/EWDS, Earthdata, CDSE, Google Flood API, EFAS ortaklığı, MEVBİS; resmî yazı: DSİ AGİ, HGM SYM12, SYGM taşkın haritaları.\n2. Kalibrasyon: 3–5 referans olayda DSİ gözlemi + GFM yayılımı ile CN, Manning n, şebeke kapasitesi ve QML hiper-parametrelerinin ayarı.\n3. Donanım: IBM/Wukong'da 12–20 kübit VQC çıkarımı ve D-Wave'de gerçek QUBO tahsisi (hücre 3 → `quantum_backend`, `qubo_solver`).\n4. Ürünleşme: modülün servis olarak (FastAPI + zamanlayıcı) sunulması, MGM MeteoUyarı ile tetiklenen otomatik nowcast, AFAD/belediye webhook entegrasyonu.\n"
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}