fix(hype): score the calibration objective on the calibration period - #393
Merged
Merged
Conversation
calculate_metrics read config.optimization.calibration_period, but the field lives on the domain section (CALIBRATION_PERIOD) — OptimizationConfig has no such attribute. The AttributeError was caught and passed over, so calib_period stayed None, the filtering block was skipped, and no warning was emitted. Every HYPE calibration therefore scored the entire overlapping record, evaluation period included. Two consequences: the optimizer trained on held-out data, and the score it reported covered a different window than the Calib_* metrics written at final evaluation. On the P3 Bow-at-Banff ensemble all 14 HYPE runs disagreed with their final evaluation by 3e-3 to 5.9e-2 — every algorithm, not just gradient-based ones. Resolve through the canonical CALIBRATION_PERIOD key, exactly as _calculate_multi_gauge_metrics in this same class already does, with a typed-config fallback. When no period resolves, warn instead of silently scoring everything — the silence is what hid this. Verified on Bow-at-Banff: HYPE/abc goes from best 0.8247 vs Calib_KGE 0.8196 (5.1e-3) to best 0.8325 vs 0.8325 (2.0e-6). Its held-out Eval_KGE drops from 0.805 to 0.550, which is the point — the evaluation period was previously part of what the optimizer trained on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 29, 2026
DarriEy
pushed a commit
that referenced
this pull request
Jul 30, 2026
…d area fixes 468 runs, 196 rows changed. 137 are on the corrected basis — regenerated after the catchment-area fix landed at 2026-07-28T18:03 — and 77 predate it. The corrected rows carry the five fixes from this cycle: the shared calibration window (#392), HYPE reading its period from a field that does not exist (#393), catchment area resolved from two different shapefiles (#394), point-domain GRU_area written in square degrees (#396), and the seven model-package leakage fixes now on PyPI. Every affected model's calibration objective now agrees with its own final evaluation. Before this cycle the two disagreed by up to 0.35 KGE; across 118 verified runs the worst residual is 5.8e-05 and most sit near 1e-06: HBV 17/17 2.6e-07 HYPE 15/15 3.9e-06 FUSE 15/15 1.4e-06 SACSMA 17/17 5.9e-06 TOPMODEL 17/17 4.2e-06 HECHMS 17/17 5.8e-05 SUMMA 3/15 0.0e+00 The 77 pre-fix rows are identifiable by run_completed < 2026-07-28T18:03 and are dominated by SUMMA (32), which needs ~4.8 h per config and could not be regenerated before this machine was returned. GR (21), GSFLOW (8), JFUSE (6) and RAVEN (4) were outside this cycle's scope. Re-running any of them refreshes the rows in place, as the collector is designed for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DarriEy
added a commit
that referenced
this pull request
Jul 30, 2026
…d area fixes (#397) * repro(macos_p3repro): refresh metrics after the calibration-window and area fixes 468 runs, 196 rows changed. 137 are on the corrected basis — regenerated after the catchment-area fix landed at 2026-07-28T18:03 — and 77 predate it. The corrected rows carry the five fixes from this cycle: the shared calibration window (#392), HYPE reading its period from a field that does not exist (#393), catchment area resolved from two different shapefiles (#394), point-domain GRU_area written in square degrees (#396), and the seven model-package leakage fixes now on PyPI. Every affected model's calibration objective now agrees with its own final evaluation. Before this cycle the two disagreed by up to 0.35 KGE; across 118 verified runs the worst residual is 5.8e-05 and most sit near 1e-06: HBV 17/17 2.6e-07 HYPE 15/15 3.9e-06 FUSE 15/15 1.4e-06 SACSMA 17/17 5.9e-06 TOPMODEL 17/17 4.2e-06 HECHMS 17/17 5.8e-05 SUMMA 3/15 0.0e+00 The 77 pre-fix rows are identifiable by run_completed < 2026-07-28T18:03 and are dominated by SUMMA (32), which needs ~4.8 h per config and could not be regenerated before this machine was returned. GR (21), GSFLOW (8), JFUSE (6) and RAVEN (4) were outside this cycle's scope. Re-running any of them refreshes the rows in place, as the collector is designed for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * repro(macos_p3repro): final collection before the machine was returned Refreshes 7 rows completed after the previous collection. The corrected / pre-fix split is unchanged at 137 / 77. This is the last collection from this box: the reproduction environment was torn down while SUMMA was still working through its re-run. SUMMA's cma-es config was ~40% through generation 20 of 50 and did not complete, so 32 SUMMA rows remain on the pre-fix basis, identifiable as before by run_completed < 2026-07-28T18:03Z. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * repro(macos_p3repro): add the last runs before the machine was returned 469 runs. Adds gr4j, gsflow and a re-run of rhessys, plus the benchmark config that finished during the final window. The rhessys row is the end-to-end confirmation of the basin-area fix: it now reports best_score 0.851883 against Calib_KGE 0.851883 (0.00e+00), where before the fix the same run reported 0.851883 against 0.835738 (1.61e-02) — the same simulation measured against the worldfile's stale 2248.0606 km2 rather than the delineation's 2207.5038 km2. Corrected / pre-fix now 138 / 77. The 77 remain identifiable by run_completed < 2026-07-28T18:03Z and are dominated by SUMMA (32), which needs ~4.8 h per config; its cma-es run reached generation 40 of 50 before the machine went back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: DarriEy <darri.eythorsson@ucalgary.ca> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
HYPEWorker.calculate_metricsrestricted scoring to the calibration period like this:calibration_periodlives on the domain section (CALIBRATION_PERIOD) —OptimizationConfighas no such field. So theAttributeErrorfired on every call, was caught and passed over,calib_periodstayedNone, the filter was skipped, and nothing was logged.Every HYPE calibration therefore scored the entire overlapping record, evaluation period included.
Two consequences — the same pair recently fixed across the JAX model packages, reached by a different route:
Calib_*metrics written at final evaluation.On the P3 Bow-at-Banff calibration ensemble, all 14 HYPE runs disagreed with their own final evaluation, by 3e-3 to 5.9e-2 — across every algorithm, not just the gradient-based ones. That breadth is what distinguishes this from the gradient-path bugs.
Fix
Resolve through the canonical
CALIBRATION_PERIODkey, exactly as_calculate_multi_gauge_metricsin this same class already does (line 637), with a typed-config fallback.When no period resolves, warn instead of silently scoring everything. The silence is what hid this for so long: a
try/except AttributeError: passaround a config read gives identical behaviour whether the key is absent, misspelled, or moved.Verification
HYPE/abcon Bow-at-Banff, before and after:The residual now matches the other models (HBV 5.4e-07, TOPMODEL 3.6e-09, FUSE 9.6e-07).
The
Eval_KGEdrop from 0.805 to 0.550 is the point, not a regression. The evaluation period was previously part of what the optimizer trained on, so held-out performance was overstated. Any previously published HYPE evaluation-period number is affected.This is 1 of 15 HYPE configs; the remaining 14 are re-running and I'll follow up if any disagrees.
Related
Companion to the calibration-window work in #392 and the seven model-package PRs (jHBV, jTOPMODEL, jSAC-SMA, jXAJ, jHEC-HMS, jFUSE, cFUSE), all merged.
🤖 Generated with Claude Code