Skip to content

Barrier rules as config: compare scenarios of what counts as a barrier at a crossing #341

Open

Description

@NewGraphEnvironment

Problem

What counts as a barrier at a crossing is fixed in code, so a program cannot ask "what if we used our rules instead?" and compare the answers.

Today, <schema>.crossings.barrier_status comes from three sources (R/lnk_crossings_union.R:135-212, R/lnk_pipeline_load.R):

  • the province's PSCIS result (current_barrier_result_code) for assessed crossings;
  • the modelled type, for the rest;
  • the per-row override CSVs.

The human-made barrier set is then barrier_status IN ('BARRIER', 'POTENTIAL'), repeated in four places (R/lnk_barriers_emit.R:85,105,125, R/lnk_barriers_unify.R:200).

link already holds a rule of the right shape that nothing uses: lnk_score() with inst/extdata/thresholds_default.csv (high, outlet_drop, 0.6; high, slope_length, 120).

Goal

Run the existing rules, then ours, and compare. Each rule set is a config bundle, so a scenario is a thin bundle (extends: default) that changes one rule file. Scenarios are compared through the per-crossing totals from #321, and exported side by side with lnk_scenario_export().

Streams break at every crossing whatever its status (R/lnk_pipeline_break.R, crossings_breaks), so a rule change does not re-segment. It moves only the barrier-below marks and the per-crossing totals. Whether that can be a recompute on persisted streams, rather than a full run, is a task below.

Step now: crossing characteristics only

  • One predicate. Consolidate the four barrier_status IN (…) sites into one helper that reads the rule set.
  • A bundle rule table, parameters_barrier_rules.csv, with a dictionary. One dated, sourced row per condition: column, operator, value → status, plus the source table for the column.
    • The bcfishpass bundle's one row is current_barrier_result_code IN (BARRIER, POTENTIAL) → barrier, which reproduces today's behaviour. Show it with a byte-identical run on one WSG.
    • A scenario adds, for example, outlet_drop > 0.6 → barrier.
  • Answers from anywhere. A rule's column can come from any table joined to the crossing by its id: PSCIS assessments (whse_fish.pscis_assessment_svw carries outlet_drop, outlet_pool_depth, culvert_slope, length_or_width, stream_width_ratio, embedment and the province's component scores), our own field assessments, or modelled crossings. Each row records its source.
  • Retire or absorb lnk_thresholds() / thresholds_default.csv, so one table says what a barrier is.
  • The run log records the rule set applied, so each total traces to its rules.
  • Measure whether a rule change can be applied by recompute on persisted streams (wsg_recompute_one.R / lnk_access()), and how long it takes per WSG.
  • Compare two scenarios on the Per-crossing upstream habitat per species, checked against bcfishpass, on frs_aggregate() #321 parity WSGs: the province's result vs an outlet-drop rule. Count the crossings that change class, and the per-crossing km that change.

Target shape (written down, not built)

The rule table is shaped for the general case from the start, so later axes are new columns and rows, not a redesign:

  • species (* today). Passability differs between species, and this feeds the per-species access link already computes.
  • Conditions on segment attributes and time. For example, a 2 m pipe at a June–July discharge of 5 m³/s blocks Chinook. Discharge per segment and month comes from wet (Read discharge from wet in classify and the habitat export, and re-tune BT's MAD range on it #331 wires wet's monthly table into classify). The evaluator takes a per-segment attribute by name, so link does not need to know where it came from.

Where each piece lives:

  • fresh: network traversal and aggregation;
  • link: what a barrier is, meaning the rules and their interpretation;
  • wet: flows and temperature.

Open questions

  • Unassessed crossings. Do they stay on their modelled type? They have no measurements.
  • Which values default starts from, with a source for each: 0.6 m outlet drop, plus slope-length and width-ratio rows.
  • POTENTIAL. Does it stay a status of its own in our rules, or become a set of conditions?

Relates to #321 (step 1: the per-crossing totals these scenarios are compared through) and #331. The lnk_score() / lnk_thresholds() origin is #11 and #3.

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