flood¶
Flood susceptibility and event-risk mapping. Entry point: FloodRiskUseCase.
Use case¶
use_case ¶
FloodRiskUseCase ¶
Bases: BaseUseCase
Entry point for the flood risk domain.
Minimal config (all optional — defaults match the Niger flood notebook example):
{ "aoi_geojson": {"type": "Polygon", "coordinates": [...]}, "gee_project": "your-gee-project-id", "model_type": "ensemble", # "rf" | "xgboost" | "ensemble" "output_dir": "outputs", "prefix": "flood_2022_2023", "flood_event": "Niger River flood pulse Oct 2022-Jan 2023", # Main analysis period "start_date": "2022-01-01", "end_date": "2023-01-31", # Flood event windows "pre_flood_start": "2022-05-01", "pre_flood_end": "2022-07-31", "post_flood_start": "2022-10-01", "post_flood_end": "2023-01-31", # Rainfall windows "rain_7d_start": "2022-08-18", "rain_7d_end": "2022-08-25", "rain_30d_start": "2022-08-01", "rain_30d_end": "2022-08-31", # Sentinel-2 MNDWI window "mndwi_start": "2022-10-01", "mndwi_end": "2023-01-31", # JRC flood label window "flood_label_start":"2021-01-01", "flood_label_end":"2021-12-31", # Sampling "n_pixels": 3000, "scale": 90, }
Source code in flood/use_case.py
fetch_data ¶
Authenticate GEE and parse the AOI geometry (see _fetch_from_dict).
Source code in flood/use_case.py
preprocess ¶
Build the feature stack and sample flooded/dry pixels (see _preprocess_raw).
run_model ¶
Train models, export the risk COG, and package an AnalysisOutput.
Source code in flood/use_case.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
run ¶
Single AOI analysis — full pipeline in one call.
Source code in flood/use_case.py
run_date_ranges ¶
Not supported — flood is single-area only. See UseCaseInfo.single_area_only.
Source code in flood/use_case.py
run_multi_regions ¶
Not supported — flood is single-area only. See UseCaseInfo.single_area_only.
Source code in flood/use_case.py
Features¶
features ¶
fetch_terrain ¶
Download SRTM elevation from GEE. Returns Dataset with variable 'elevation' and (lat, lon) coords.
Source code in flood/features.py
fetch_twi ¶
Compute Topographic Wetness Index from HydroSHEDS flow accumulation + SRTM slope. Returns Dataset with variables 'twi' and 'flow_acc_log'.
Source code in flood/features.py
fetch_sar_change ¶
fetch_sar_change(aoi: Geometry, pre_start: str, pre_end: str, flood_start: str, flood_end: str, scale: int = 90) -> xr.Dataset
Compute Sentinel-1 VV backscatter change (pre − flood). Positive values indicate a backscatter drop → open water / flood signal. Returns Dataset with variable 'vv_change'.
Source code in flood/features.py
fetch_rainfall ¶
fetch_rainfall(aoi: Geometry, start_7d: str, end_7d: str, start_30d: str, end_30d: str, scale: int = 500) -> xr.Dataset
Download CHIRPS cumulative rainfall for two windows. Returns Dataset with variables 'rainfall_7d' and 'rainfall_30d'.
Source code in flood/features.py
fetch_landcover ¶
Download ESA WorldCover 2021 land cover. Returns Dataset with variable 'Map' (raw class values 10–95).
Source code in flood/features.py
fetch_dist_river ¶
Compute Euclidean distance to permanent water (JRC occurrence ≥ 70 %). Returns Dataset with variable 'dist_river' in metres.
Source code in flood/features.py
fetch_mndwi ¶
Compute Sentinel-2 MNDWI = (Green − SWIR1) / (Green + SWIR1). Returns Dataset with variable 'mndwi'.
Source code in flood/features.py
build_feature_datasets ¶
Download all feature bands from GEE in parallel. The seven fetch calls are independent HTTP requests; they run concurrently via DaskEngine.run_io_parallel (ThreadPoolExecutor) sharing the GEE session. The dict is keyed by band group name and consumed by both sample_training_data and cog_export.export_flood_cog.
Source code in flood/features.py
build_gee_feature_stack ¶
Assemble the 10-band GEE image used for stratified sampling. Static (event-independent) and dynamic (event-specific) bands are built concurrently in background threads, then selected into FEATURE_COLS order.
Source code in flood/features.py
sample_training_data ¶
sample_training_data(aoi: Geometry, config: dict, n_pixels: int = 5000, scale: int = 90, seed: int = 42) -> pd.DataFrame
Build the 10-band feature stack and derive JRC flood labels concurrently in background threads, then sample n_pixels flooded + n_pixels non-flooded pixels.
Static features (elevation, TWI, dist_river, landcover, coords), dynamic features (vv_change, rainfall, mndwi), and the JRC label image are all fetched in parallel — no external feature_stack argument required.
1 = seasonal flood water not part of the permanent baseline
0 = all other land
Returns a DataFrame with columns = FEATURE_COLS + ['is_flooded'].
Source code in flood/features.py
align_datasets ¶
align_datasets(datasets: dict[str, Dataset], ref_key: str = 'terrain', method_continuous: InterpOptions = 'linear', method_categorical: InterpOptions = 'nearest') -> dict[str, xr.Dataset]
Interpolate all datasets onto the reference grid (terrain at 90 m by default). Landcover is treated as categorical and uses nearest-neighbour interpolation. population_count is passed through entirely unchanged, at its own native ~100 m resolution — it is never interpolated onto this reference grid. Summing population within a risk zone requires the opposite: upsampling the (categorical) classification onto population's native grid — see core.population.population_exposure, which cog_export.py uses for this instead of relying on align_datasets. Interpolating population here would silently corrupt totals (verified against live GEE data — see core.population.fetch_population_count's docstring).
Each dataset is chunked before interpolation so that xarray produces Dask-backed lazy arrays; dask.compute() then materialises them all in a single parallel scheduler pass.
Source code in flood/features.py
Model¶
model ¶
FloodModel ¶
Orchestrates the full ML pipeline for a single flood event. Always trains both RF and XGBoost. config['model_type'] selects which probabilities drive the primary stats, risk map, and COG export: "rf" — Random Forest "xgboost" — XGBoost "ensemble" — mean of RF + XGBoost (default) Trained models are stored on self.rf / self.xgb so the use case can pass them directly to cog_export.export_flood_cog.
Source code in flood/model.py
predict ¶
Parameters¶
df : DataFrame with columns = FEATURE_COLS + ['is_flooded'] config : optional dict; reads config['model_type'] (default 'ensemble')
Returns¶
dict with keys: stats, charts
Source code in flood/model.py
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | |
classify_flood_risk ¶
Map flood probability array to 4-class string labels.
Source code in flood/model.py
train_rf ¶
train_rf(X_train: ndarray, y_train: ndarray, cv_folds: int = 5) -> tuple[RandomForestClassifier, dict]
Fit a balanced Random Forest and report CV F1. Returns (model, metadata).
Source code in flood/model.py
train_xgb ¶
train_xgb(X_train: ndarray, y_train: ndarray, X_val: ndarray, y_val: ndarray, cv_folds: int = 5) -> tuple[Booster, dict]
Fit XGBoost binary flood classifier via the low-level Booster API with scale_pos_weight and eval-set logging. Returns (model, metadata).
Uses xgboost.train() rather than the XGBClassifier sklearn wrapper because the wrapper's fit() rejects a y whose sorted unique values aren't exactly [0, 1] — an AOI/time window where every sampled pixel is flooded (or none are) is a legitimate data state, not invalid input, and would otherwise crash training.
Source code in flood/model.py
positive_class_proba ¶
Return P(y=1) from a binary sklearn classifier's predict_proba output.
predict_proba only has one column when the classifier saw a single class during training (e.g. every sampled pixel in this AOI/time window was flooded, or none were) — proba[:, 1] would then raise IndexError. Falls back to reading clf.classes_ to know whether that lone column represents class 0 or class 1.
Source code in flood/model.py
find_best_threshold ¶
Return (threshold, best_f1) that maximises F1 on the precision-recall curve.
Source code in flood/model.py
evaluate_models ¶
Evaluate RF, XGBoost, and their ensemble on the held-out test set. Thresholds are maximised per-model via the precision-recall curve.
Source code in flood/model.py
compute_shap_importance ¶
TreeExplainer SHAP values for XGBoost, sorted by descending mean |SHAP|. XGBoost is always used for SHAP regardless of model_type — it provides the most interpretable tree-based explanations.
Source code in flood/model.py
compute_uncertainty ¶
Epistemic uncertainty from RF–XGBoost probability spread. Pixels with spread > 0.20 are flagged for field validation. Always computed regardless of model_type so the UI can display it.
Source code in flood/model.py
build_flood_charts ¶
build_flood_charts(eval_result: dict, shap_payload: dict, uncertainty_payload: dict, model_type: str = 'ensemble') -> dict
Assemble frontend-ready chart payloads.
Risk distribution is derived from the selected model_type's probabilities. model_performance always includes all three models for comparison.
Source code in flood/model.py
COG export¶
cog_export ¶
flood_raster_distribution ¶
Read an already-exported flood-risk COG and tally pixel counts/percentages per risk class (Very High/High/Medium/Low), skipping nodata (<= 0) pixels.
Source code in flood/cog_export.py
export_flood_cog ¶
export_flood_cog(rf_model: RandomForestClassifier, xgb_model: Booster, datasets: dict[str, Dataset], output_dir: str, prefix: str, model_type: str = 'ensemble', aoi_geojson: dict | None = None) -> FloodCogResult
Build the full-AOI feature matrix from in-memory xarray Datasets, run inference with the selected model, classify into 4 risk classes, and write a Cloud Optimised GeoTIFF.
Source code in flood/cog_export.py
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | |