Skip to content

Tune MAD (discharge) thresholds for BT, GR, KO and RB rather than leave them missing #302

Description

@NewGraphEnvironment

If done: a mad watershed group keeps stream habitat for every modelled species, on
discharge windows set from evidence. If never: any group moved to mad loses all
stream spawning and rearing for BT, GR, KO and RB by construction. That is not a finding
about the fish. Only waterbody rules (wetlands, lakes, the 1050/1150 edges) keep them.

Problem

parameters_habitat_thresholds.csv carries spawn_mad_* for CH, CM, CO, PK, SK, ST and
WCT, and rear_mad_* for CH, CO, ST and WCT only (default, default_tuned and
bcfishpass alike). The gap was inherited from bcfishpass example_newgraph. Under
the mad model, fresh writes FALSE in place of the size test for a species with no
range, as bcfishpass does. Since #299, lnk_habitat_validate() names a miss the missing
range alone explains no_mad_threshold. Misses from the same cause also read
width_null (no discharge on the line) or fails_gradient_and_width (gradient fails
too), so that label is a floor on the loss, not a count of it. On ADMS on mad, 27 BT
locations read it against spawning and 8 more read fails_gradient_and_width
(data-raw/logs/habitat_validate_299/). The operator's direction (2026-10-02,
#299 plan gate): tune and add the thresholds, rather than leave them missing in the long
run.

Proposed Solution

  • Measure first. Take the distribution of mad_m3s at BT / GR / KO / RB observation
    locations by stage (pooled DV per species_pooling.csv), alongside accessible
    availability. This is the Research: calibrate CH and BT gradient and channel-width thresholds from observations #284 method with discharge in place of width. As built:
    measured on the 46 discharge-covered fresh_default groups (calibration), not on
    Score the discharge (mad) habitat model against observations, as #284 did for gradient #300's held-out groups, so that the score could stay out-of-sample.
  • Literature and FISS for each species' discharge range, recorded in
    research/habitat_thresholds.md as one verdict per threshold.
  • Land the values in default_tuned (a thin bundle) first, scored out-of-sample with
    lnk_habitat_validate_band(). default stays untouched until a score supports a move.
  • Score before/after with capture and cost (share_*, *_km) and
    lnk_habitat_validate_band(), not with no_mad_threshold. Once a range exists, the
    label cannot fire, so its "after" is 0 whatever the value.

Depends on #299. Relates to #284, #286, #300. As built: the mad scoring harness
#300 needed was built here (operator's call at the plan gate), so #300 can reuse it.

Outcome (2026-10-02, PR #303)

  • Landed in default_tuned (m³/s, maxima open): BT 0.078 spawn and rear, GR 0.96
    spawn / 0.97 rear, RB 0.011 spawn / 0.019 rear, and KO 0.57 spawn, unscored (no
    held-out group). They are inert while every group is on cw; default is untouched.
  • Scoring: a rule fixed before the build (expected-count floor). Every P10 → P05
    loosening was refused on the held-out groups except RB spawning, so the landed values
    are the P10 rungs, not the P05 candidates.
  • Cost before moving any group to mad: at least −33 % BT and −82 % GR stream
    rearing against cw on the held-out groups. Stream size and sampling effort are not
    separated; a size-stratified core is the next tuning.
  • Where it lives: research/habitat_thresholds.md, "MAD (discharge) ranges for BT,
    GR, KO and RB (Tune MAD (discharge) thresholds for BT, GR, KO and RB rather than leave them missing #302)"; archive planning/archive/2026-10-issue-302-mad-thresholds/.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions