Skip to content

Habitat eligibility rules format for multi-rule species (Path 1) #113

@NewGraphEnvironment

Description

@NewGraphEnvironment

Problem

Habitat eligibility (which segments qualify as spawning/rearing per species) varies by species in ways the current parameters_habitat_thresholds.csv (fresh 0.11.0) can't elegantly express. Each "special case" tempts a one-off code path. We want one mechanism that handles every species without code changes.

bcfishpass v0.5.0 special cases that don't fit one CSV row

Each species spawn/rear can require multiple rules combined with OR. The CSV format with spawn_edge_types / rear_edge_types columns assumes a single rule per habitat type.

Species Habitat Rules in bcfishpass v0.5.0
BT spawn (edge_types: stream,canal AND gradient/cw thresholds) OR (waterbody_type=R AND gradient/cw thresholds)
CO spawn same OR pattern with R rivers
CO rear (stream,canal AND gradient/cw thresholds) OR (edge_type IN 1050,1150 with NO threshold checks)
SK rear waterbody_type=L AND area_ha >= 200 (lake-only, no stream rearing at all)
BT rear any edge type connected to spawning (post-cluster, but no edge filter at classify time)

The pattern: a species' habitat-type qualifies on ANY of N rules. Each rule is a (segment predicate, attribute thresholds) pair.

Proposed Solution: Path 1 — Hybrid CSV + rules YAML

Keep parameters_habitat_thresholds.csv for the 80% case (species with one simple rule). Add an optional rules file for species that need multiple rules.

CSV stays unchanged for simple species

BT, CH, ST, WCT, RB, GR, CT, DV — each can be expressed as a single rule from the existing CSV columns.

New file: parameters_habitat_rules.yaml (or .json)

# Special-case species. Listed species REPLACE their CSV row.
# Species not listed here use the CSV row as-is.

SK:
  spawn:
    - edge_types: [stream, canal]
      gradient: [0, 0.0249]
      channel_width: [2, 9999]
      mad: [0.175, 9999]
  rear:
    - waterbody_type: L
      lake_ha_min: 200
      channel_width: [1.5, 9999]
      # no gradient — lake-only

CO:
  spawn:
    - edge_types: [stream, canal]
      gradient: [0, 0.0549]
      channel_width: [2, 9999]
      mad: [0.164, 9999]
    - waterbody_type: R         # double-line rivers
      gradient: [0, 0.0549]
      channel_width: [2, 9999]
      mad: [0.164, 9999]
  rear:
    - edge_types: [stream, canal]
      gradient: [0, 0.0549]
      channel_width: [1.5, 9999]
      mad: [0.03, 40]
    - edge_types_explicit: [1050, 1150]   # wetland-flow streams, no thresholds

Rule format

Each rule is a list of optional predicates joined by AND. Multiple rules per habitat type are joined by OR.

Predicate Type Maps to SQL
edge_types list of fresh categories edge_type IN (...) via frs_edge_types(category)
edge_types_explicit list of integer codes edge_type IN (...) direct codes
waterbody_type character (L, R, W) waterbody_key IN (SELECT ... WHERE waterbody_type = '...')
lake_ha_min numeric additional filter on lake join
gradient [min, max] s.gradient BETWEEN ... AND ...
channel_width [min, max] s.channel_width BETWEEN ... AND ...
mad [min, max] requires mad_m3s on streams (currently missing)

frs_habitat_classify() changes

Add rules parameter (default NULL). When provided:

  1. For each species, check if rules file has an entry. If yes, use rules instead of CSV row. If no, use CSV row as today.
  2. Build spawn_cond / rear_cond SQL by joining rule predicates with AND, then joining rules with OR.
  3. Lake / waterbody joins added as needed per rule.

frs_habitat() changes

Pass rules arg through to frs_habitat_classify().

What does NOT change

  • parameters_habitat_thresholds.csv schema and format
  • parameters_fresh.csv schema and format
  • frs_classify(), frs_aggregate(), frs_network_* (unaffected)
  • Existing examples and tests for species with single-rule habitat

Implementation scope

Changes:

  • R/frs_params.R — load + parse rules file, merge with CSV
  • R/frs_habitat_classify.R — replace single spawn_cond/rear_cond build with rule-list evaluator
  • R/frs_habitat.R — pass rules arg through

New file:

  • inst/extdata/parameters_habitat_rules.yaml — default rules (or empty/missing — CSV-only behavior)

Test approach

Use ADMS sub-basin 100.190442.999098.995997.058910.432966:

  1. SK rearing with default (no rules): currently 21.55 km on streams. With rules file specifying SK lake-only: 0 km on streams, lake_rearing filtered to ≥ 200 ha. Matches bcfishpass v0.5.0 (0).
  2. CO rearing with rules adding wetland-flow carve-out: matches bcfishpass v0.5.0.
  3. Species without rules entries (BT, CH): unchanged from CSV behavior.

Relates to

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