Spaces:
Paused
Paused
| """ | |
| Central configuration for MicroClimate-X. | |
| EVERY Veto threshold below has an academic / regulatory citation. | |
| This is intentional โ at thesis defence the panel WILL ask | |
| "why 3500 m, why -5 ยฐC, why 40 km/h?". Be ready to point to this file. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import subprocess | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parent.parent | |
| MODEL_DIR = ROOT / "models" | |
| DATA_DIR = ROOT / "data" | |
| DB_PATH = Path(os.environ.get("MICROCLIMATEX_DB", str(ROOT / "cache.sqlite3"))) | |
| def _detect_git_revision() -> str: | |
| """Best-effort short SHA. Returns "unknown" if git is not available | |
| or this directory isn't a checkout (e.g. inside a Docker image).""" | |
| env = os.environ.get("MICROCLIMATEX_GIT_REV") | |
| if env: | |
| return env | |
| try: | |
| out = subprocess.run( | |
| ["git", "rev-parse", "--short", "HEAD"], | |
| cwd=ROOT, capture_output=True, text=True, timeout=2.0, | |
| ) | |
| if out.returncode == 0: | |
| return out.stdout.strip() | |
| except (FileNotFoundError, subprocess.SubprocessError): # pragma: no cover | |
| pass | |
| return "unknown" | |
| GIT_REVISION = _detect_git_revision() | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Veto thresholds โ one-vote rejection rules | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Citation: Luks et al. (2019) "Wilderness Medical Society Practice | |
| # Guidelines for the Prevention and Treatment of Acute Altitude | |
| # Illness." High altitude (>2500 m) carries clinical risk; severe | |
| # hypoxia onset is well-documented above ~3500 m. | |
| ALTITUDE_HYPOXIA_M = 3500.0 | |
| # Citation: WMO Beaufort scale โ Force 6 "Strong breeze" โ 39-49 km/h, | |
| # the threshold above which outdoor activity becomes hazardous. | |
| GALE_WIND_KMH = 40.0 | |
| # Citation: UIAA Medical Commission frostbite risk guidance โ exposed skin | |
| # freezes rapidly below approximately -5 ยฐC with wind chill. | |
| EXTREME_COLD_C = -5.0 | |
| # Citation: U.S. NWS convective forecasting handbook โ CAPE > 1000 J/kg | |
| # indicates moderate-to-strong instability suitable for | |
| # thunderstorm development. | |
| HIGH_CAPE_JKG = 1000.0 | |
| # Citation: FAA AIM 7-1-12 โ visibility below 100 m is classified as | |
| # Category III instrument-only conditions. Used here as an extreme | |
| # low-visibility threshold (whiteout / dense fog). | |
| LOW_VISIBILITY_M = 100.0 | |
| # Wind alignment with slope normal vector (orographic uplift). The | |
| # threshold 0.7 corresponds to ~45 degrees of slope-facing wind. | |
| OROGRAPHIC_DOT_THRESHOLD = 0.7 | |
| # Wet-flood trigger in a valley basin: high probability of localised rain | |
| # combined with valley-floor topography. | |
| VALLEY_FLOOD_PROB = 0.80 | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Risk scoring (additive penalties when no Veto fires) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| PENALTY = { | |
| "ml_high_rain_prob": 35, # ML predicts >= 70 % rain probability | |
| "ml_mid_rain_prob": 15, # ML predicts 40-70 % rain probability | |
| "valley_floor": 10, | |
| "windward_slope": 20, | |
| "orographic_lift": 25, | |
| "altitude_high": 15, # 2500-3500 m, sub-Veto altitude band | |
| "wind_strong": 10, # 25-40 km/h | |
| } | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Four hazard categories โ matches D5 proposal ยง3.7 / P4.3 | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Fog risk: | |
| # WMO surface synoptic code: fog โ visibility < 1 km, RH typically > 95 %, | |
| # dew-point depression < ~2 ยฐC. Valley/Slope basins trap radiation fog. | |
| FOG_HUMIDITY_PCT = 95.0 | |
| FOG_DEW_DEP_MAX_C = 2.0 | |
| FOG_CLOUD_BASE_MAX_M = 800.0 # from D5 ยง3.7.2 decision table | |
| # Wind gust risk: | |
| # On exposed ridges and mountain passes, sustained 25 km/h winds with | |
| # topographic acceleration commonly gust to Beaufort F6 levels. | |
| GUST_WIND_MIN_KMH = 25.0 # below GALE_WIND_KMH but still risky | |
| # Thunderstorm risk: | |
| # NWS "moderate instability" begins at CAPE 500 J/kg; sharp pressure drop | |
| # often precedes convective initiation. | |
| THUNDER_CAPE_MIN_JKG = 500.0 | |
| THUNDER_PRESSURE_DROP = -2.0 # hPa over past 3 h (matches D5 ยง1.3 example) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Decision Table โ D5 ยง3.7.2 / Table 4.2 (one-to-one with the thesis) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Each rule fires when ALL of its non-None conditions hold. The thesis | |
| # narrative motivates this table as: "macro forecast says no rain, but | |
| # the local terrain conditions imply hidden risk". | |
| DECISION_TABLE_3_7_2 = { | |
| "R1": { | |
| "description": "Hidden rain risk โ macro says no, terrain says yes", | |
| "macro_rain_prob_max": 0.30, | |
| "macro_rain_prob_min": None, | |
| "humidity_min_pct": 85.0, | |
| "wind_into_slope": True, | |
| "terrain": "WindwardSlope", | |
| "pressure_change_3h_max": -1.5, | |
| "cloud_base_max_m": FOG_CLOUD_BASE_MAX_M, | |
| "conclusion_en": "Hidden rain risk: terrain analysis indicates orographic precipitation despite low macro probability.", | |
| "conclusion_zh": "้่้้จ้ฃ้ฉ๏ผๅฎ่ง้ขๆฅๆฆ็ไฝ๏ผไฝๅฐๅฝขๅๆ่กจๆๅญๅจๅฐๅฝขๆฌๅ้ๆฐดใ", | |
| }, | |
| "R2": { | |
| "description": "No significant risk โ terrain not aligned", | |
| "macro_rain_prob_max": 0.30, | |
| "macro_rain_prob_min": None, | |
| "humidity_min_pct": 85.0, | |
| "wind_into_slope": False, | |
| "terrain": "LeewardOrValley", | |
| "pressure_change_3h_max": -1.5, | |
| "cloud_base_max_m": FOG_CLOUD_BASE_MAX_M, | |
| "conclusion_en": "No significant rainfall danger at this spot in this period.", | |
| "conclusion_zh": "ๆญคๅฐๆญคๆถๆ ๆพ่้้จๅฑ้ฉใ", | |
| }, | |
| "R3": { | |
| "description": "Heavy downpour incoming โ avoid exposure", | |
| "macro_rain_prob_max": None, | |
| "macro_rain_prob_min": 0.70, | |
| "humidity_min_pct": None, | |
| "wind_into_slope": True, | |
| "terrain": "WindwardSlope", | |
| "pressure_change_3h_max": None, | |
| "cloud_base_max_m": None, | |
| "conclusion_en": "Heavy downpour incoming. Avoid mountains and valleys.", | |
| "conclusion_zh": "ๅผบ้้จๅณๅฐๅฐๆฅใ่ฏท้ฟๅผๅฑฑๅบไธๅณก่ฐทใ", | |
| }, | |
| "R4": { | |
| "description": "Normal rain โ no terrain amplification", | |
| "macro_rain_prob_max": None, | |
| "macro_rain_prob_min": 0.70, | |
| "humidity_min_pct": None, | |
| "wind_into_slope": None, | |
| "terrain": None, | |
| "pressure_change_3h_max": None, | |
| "cloud_base_max_m": None, | |
| "conclusion_en": "Rain expected, but no terrain-induced amplification. Standard rain precautions apply.", | |
| "conclusion_zh": "้ข่ฎกๆ้จ๏ผไฝๆ ๅฐๅฝขๆฌๅๆพๅคงใๆไธ่ฌ้จๅคฉๆชๆฝๅบๅฏนๅณๅฏใ", | |
| }, | |
| } | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Activity-aware weighting โ D5 ยง3.7 / P4.4 | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Composite = ฮฃ w_i ยท subscore_i, then renormalised to 0-100. | |
| # Rows: activity. Cols: rainfall, fog, wind_gust, thunderstorm. | |
| ACTIVITY_WEIGHTS = { | |
| "hiker": {"rainfall": 1.0, "fog": 1.3, "wind_gust": 1.0, "thunderstorm": 1.4}, | |
| "driver": {"rainfall": 0.8, "fog": 1.5, "wind_gust": 1.3, "thunderstorm": 0.9}, | |
| "construction": {"rainfall": 1.0, "fog": 0.8, "wind_gust": 1.5, "thunderstorm": 1.4}, | |
| "general": {"rainfall": 1.0, "fog": 1.0, "wind_gust": 1.0, "thunderstorm": 1.0}, | |
| } | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Cache TTL (risk-adaptive) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Safety-critical apps must not serve stale "Safe" verdicts during developing | |
| # storms. Bucket TTL by risk band. | |
| TTL_HIGH_RISK_SEC = 60 # any Veto fired OR risk >= 70 | |
| TTL_MID_RISK_SEC = 300 # risk 40-70 | |
| TTL_LOW_RISK_SEC = 600 # risk < 40 | |
| # Grid resolution used as cache key (0.01ยฐ โ 1.1 km at the equator). | |
| GRID_RESOLUTION_DEG = 0.01 | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # External API endpoints | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| OPEN_METEO_FORECAST_URL = "https://api.open-meteo.com/v1/forecast" | |
| OPEN_TOPO_URL = "https://api.opentopodata.org/v1/srtm30m" | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Domain constants | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # WMO definition of trace precipitation. | |
| RAIN_THRESHOLD_MM = 0.1 | |