Consistency fixes across notebooks 08, 14, and 15 to align wet-season
definitions and Floodscan event classification. Investigated the 2025
trigger threshold methodology. Created two new notebooks:
17_threshold_selection.ipynb for the Benue grid search and
18_trigger_summary_performance.ipynb for end-to-end trigger
performance evaluation.
08_trigger_events.ipynb)The Google GRRR reforecast zarr is static and covers 1980–2023, but the reforecast data for 2023 ends in July — before the Aug–Oct flood season peak. Treating 2023 as a complete year would misclassify it as a non-event.
Fix: added a dynamic filter
(_grrr_rf_complete_years) that excludes any year where the
maximum valid_time month is below October. This makes 2023
a NaN in the trigger matrix’s google column
rather than a spurious 0.
_grrr_rf_complete_years = (
df_grrr_rf
.assign(year=..., month=...)
.groupby("year")["month"]
.max()
.pipe(lambda s: s[s >= 10].index)
)15_trigger_performance.ipynb)Notebook 15 was independently recomputing Floodscan annual max and RP thresholds using a seasonal filter (Aug–Nov), diverging from notebook 08’s all-months computation. This caused different event year classifications between notebooks.
Fix: replaced the local Floodscan computation with a
direct load of the trigger matrix parquet produced by notebook 08
({state}_trigger_matrix.parquet). The fs_3yr,
fs_4yr, fs_5yr columns are now the single
source of truth across all performance notebooks.
trigger_matrix_blob = f"ds-aa-nga-flooding/processed/trigger_matrix/{STATE.lower()}_trigger_matrix.parquet"
df_trig = stratus.load_parquet_from_blob(trigger_matrix_blob)
all_fs_years = set(df_trig["year"])
fs_event_years = {rp: set(df_trig[df_trig[f"fs_{rp}yr"] == 1]["year"]) for rp in RP_LEVELS}14_forecast_performance.ipynb)The final “Activation probability & FAR” plot was computing FAR against GloFAS reanalysis events, mixing reforecast performance with reanalysis ground truth.
Fix: replaced the single FAR line with three lines
showing FAR vs Floodscan 3/4/5-year RP event years (loaded from the
trigger matrix). Removed the light blue action window shading from this
panel, which was added by shade_action_windows(ax).
Investigated how the current Adamawa thresholds (GloFAS: 3,132 m³/s;
Google: 1,195 m³/s) were derived, for reference when setting up the
Benue trigger. Key findings from
exploration/2025/combined_gf_grrr_reanalysis.ipynb:
The 2025 metrics code (grrr_comparison.ipynb) used
tpr (detection rate), ppv (precision), and
f1 — accuracy and FAR were not computed in 2025.
17_threshold_selection.ipynb
— Benue threshold grid searchGrid search notebook for selecting GloFAS and Google GRRR thresholds
for the Benue (Makurdi) trigger. Currently glofas_thresh
and google_thresh are None in
STATE_CONFIG["Benue"].
Approach: - Loads GloFAS reanalysis (Makurdi), Google GRRR reanalysis (Makurdi HYBAS), Floodscan pixels for Benue state - Floodscan flood years computed from all-months annual max (consistent with notebook 08) - Wet-season (Aug–Nov) annual max for both models, inner-joined on common years - Grid search over all (GloFAS rank, Google rank) pairs; rank 0 = never trigger; OR trigger logic - Outputs: performance heatmaps (POD / Precision / F1) per Floodscan RP level, implied combined RP heatmap, threshold selection cells, year-by-year table, performance summary
Usage: run heatmaps, set
SELECTED_GF_RANK and SELECTED_GOOGLE_RANK,
then update STATE_CONFIG["Benue"] in
src/constants.py.
18_trigger_summary_performance.ipynb
— End-to-end trigger evaluationEvaluates GloFAS trigger performance (accuracy, detection rate, FAR,
precision, F1) for both the action and readiness triggers as configured
in STATE_CONFIG, against all Floodscan RP levels.
Key design: - Reanalysis as
leadtime=0: GloFAS reanalysis daily discharge is prepended to
the reforecast as leadtime=0. A year activates if any
signal at leadtime ≤ cutoff exceeds the threshold — covering both
real-time observations and short-range forecasts in a single
cumulative-max framework. - Consistent denominator:
evaluation restricted to reforecast years (2003–2022) so all years have
both reanalysis and forecast signal. - Readiness trigger is skipped if
glofas_leadtime_readiness is None; the
notebook asserts action leadtime and threshold are set. - Outputs:
per-trigger summary table, year-by-year activation table with
TP/FP/FN/TN classification, metric-vs-leadtime plot for all leadtimes
0–16.
| Notebook | Purpose |
|---|---|
08_trigger_events.ipynb |
Trigger matrix — Floodscan flood year flags and model trigger columns (canonical source of truth) |
13_model_performance.ipynb |
Annual peak correlation and precision/recall for GloFAS and Google reanalysis vs Floodscan |
14_forecast_performance.ipynb |
Skill metrics and exceedance detection for GloFAS and Google reforecasts |
15_trigger_performance.ipynb |
GloFAS reforecast trigger performance (accuracy/POD/FAR/precision/F1) vs leadtime, evaluated against trigger matrix event years |
17_threshold_selection.ipynb |
Benue threshold grid search — OR trigger performance heatmaps over (GloFAS rank, Google rank) pairs |
18_trigger_summary_performance.ipynb |
Summary trigger performance at configured action/readiness leadtimes, with reanalysis as leadtime=0 |
glofas_thresh and google_thresh for Benue
are None in STATE_CONFIG. Run
17_threshold_selection.ipynb and update
src/constants.py to unblock notebooks 16 and 18 for
Benue.
glofas_leadtime_readiness and
google_leadtime_readiness are None for both
Adamawa and Benue. These need to be defined based on the operational AA
framework timeline before notebook 18 can evaluate readiness trigger
performance.
Different notebooks use different wet-season month filters:
| Notebook | Wet months | Purpose |
|---|---|---|
08_trigger_events.ipynb |
All months (no filter before annual max) | Floodscan event classification |
13_model_performance.ipynb |
Aug–Dec [8,9,10,11,12] | Daily correlation and annual max |
14_forecast_performance.ipynb |
Aug–Dec [8,9,10,11,12] | Reforecast exceedance detection |
15_trigger_performance.ipynb |
Aug–Nov [8,9,10,11] | Reforecast cumulative max |
17_threshold_selection.ipynb |
Aug–Nov [8,9,10,11] | Reanalysis annual max for threshold grid |
18_trigger_summary_performance.ipynb |
Aug–Nov [8,9,10,11] | Combined reanalysis+reforecast annual max |
This is intentional (Floodscan uses all months to catch tail events; model evaluation filters to the core flood season) but worth documenting explicitly in a shared constants cell if the notebooks are later consolidated.