Spaces:
Sleeping
Sleeping
| """Run-up forecast endpoints""" | |
| from fastapi import APIRouter, HTTPException, Query, Path, Body | |
| from typing import Dict, List, Optional | |
| from datetime import datetime | |
| import uuid | |
| router = APIRouter() | |
| async def forecast_runup( | |
| zone: str = Query(..., description="Coastal zone name"), | |
| source: Optional[str] = Query(None, description="Source region (e.g., 'sumatra', 'chile')"), | |
| parameters: Optional[Dict] = Body(None, description="Parameter values for forecast") | |
| ): | |
| """Generate run-up forecast for a coastal zone""" | |
| # Placeholder for different zones | |
| zone_data = { | |
| "hilo_bay_hawaii": { | |
| "becf": 4.8, | |
| "typical_beach_slope": 0.05, | |
| "shelf_width_km": 22, | |
| "population": 45000 | |
| }, | |
| "khao_lak_thailand": { | |
| "becf": 4.1, | |
| "typical_beach_slope": 0.03, | |
| "shelf_width_km": 65, | |
| "population": 20000 | |
| }, | |
| "banda_aceh_indonesia": { | |
| "becf": 7.3, | |
| "typical_beach_slope": 0.04, | |
| "shelf_width_km": 65, | |
| "population": 250000 | |
| } | |
| } | |
| if zone not in zone_data: | |
| # Return generic forecast | |
| runup = 5.0 # default | |
| else: | |
| data = zone_data[zone] | |
| # Simplified forecast based on BECF | |
| runup = 1.0 * (data['becf'] ** 0.5) * 2 | |
| return { | |
| "forecast_id": str(uuid.uuid4()), | |
| "zone": zone, | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "runup_m": runup, | |
| "confidence_interval": [runup * 0.88, runup * 1.12], | |
| "lead_time_min": 67, | |
| "parameters_used": parameters or {}, | |
| "zone_data": zone_data.get(zone, {}), | |
| "method": "physical_scaling" | |
| } | |
| async def ensemble_forecast( | |
| zone: str = Query(..., description="Coastal zone name"), | |
| n_samples: int = Query(100, ge=10, le=1000, description="Number of ensemble samples") | |
| ): | |
| """Generate ensemble forecast with uncertainty quantification""" | |
| import numpy as np | |
| # Generate ensemble | |
| base_runup = 5.0 | |
| uncertainties = np.random.normal(0, 0.5, n_samples) | |
| ensemble = base_runup + uncertainties | |
| return { | |
| "forecast_id": str(uuid.uuid4()), | |
| "zone": zone, | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "ensemble_statistics": { | |
| "mean": float(np.mean(ensemble)), | |
| "median": float(np.median(ensemble)), | |
| "std": float(np.std(ensemble)), | |
| "p10": float(np.percentile(ensemble, 10)), | |
| "p90": float(np.percentile(ensemble, 90)), | |
| "min": float(np.min(ensemble)), | |
| "max": float(np.max(ensemble)), | |
| "n_samples": n_samples | |
| }, | |
| "ensemble": ensemble.tolist()[:10] # sample first 10 | |
| } | |
| async def get_zone_forecast_history( | |
| zone_name: str = Path(...), | |
| days: int = Query(7, ge=1, le=30, description="Number of days of history") | |
| ): | |
| """Get forecast history for a zone""" | |
| # Placeholder history | |
| import numpy as np | |
| from datetime import datetime, timedelta | |
| history = [] | |
| for i in range(days): | |
| date = datetime.utcnow() - timedelta(days=i) | |
| history.append({ | |
| "date": date.isoformat(), | |
| "forecast_runup": 5.0 + np.random.normal(0, 0.3), | |
| "observed_runup": None # would be filled if observed | |
| }) | |
| return { | |
| "zone": zone_name, | |
| "history": history | |
| } | |
| async def validate_forecast( | |
| forecast_id: str = Query(..., description="Forecast ID"), | |
| observed_runup: float = Query(..., description="Observed run-up height [m]") | |
| ): | |
| """Validate a forecast against observation""" | |
| # Placeholder validation | |
| error = abs(5.0 - observed_runup) / observed_runup * 100 | |
| return { | |
| "forecast_id": forecast_id, | |
| "observed_runup": observed_runup, | |
| "forecast_runup": 5.0, | |
| "error_percent": error, | |
| "within_15_percent": error < 15, | |
| "within_30_percent": error < 30, | |
| "bias": 5.0 - observed_runup | |
| } | |
| async def get_forecast_scenarios(): | |
| """Get pre-computed forecast scenarios""" | |
| return [ | |
| { | |
| "id": "tohoku_2011", | |
| "name": "Tōhoku 2011", | |
| "description": "2011 Tōhoku earthquake and tsunami", | |
| "source": "Japan Trench", | |
| "magnitude": 9.0, | |
| "runup_m": 40.5 | |
| }, | |
| { | |
| "id": "indian_ocean_2004", | |
| "name": "Indian Ocean 2004", | |
| "description": "2004 Sumatra-Andaman earthquake and tsunami", | |
| "source": "Sumatra", | |
| "magnitude": 9.1, | |
| "runup_m": 30.0 | |
| }, | |
| { | |
| "id": "hokkaido_1993", | |
| "name": "Hokkaido 1993", | |
| "description": "1993 Hokkaido Nansei-Oki earthquake", | |
| "source": "Sea of Japan", | |
| "magnitude": 7.8, | |
| "runup_m": 31.0 | |
| } | |
| ] | |