Problem
The link comparison pipeline (link/data-raw/compare_bcfishpass.R) hand-writes a fwa_upstream() self-join to reduce gradient barriers to the minimal set needed for access blocking — keeping only the downstream-most barrier on each upstream path. On ADMS this reduces ~27,443 raw barriers to 677.
This is a generic graph operation, not link-specific. It belongs in fresh:
- Pushes the domain boundary correctly — fresh does generic network ops, link does interpretation
- Already paralleled by fresh's existing
fwa_upstream() wrappers
- Currently the only composite op in link's pipeline DAG that isn't a named function call — makes the research doc DAG ambiguous (see
link/research/bcfishpass_comparison.md)
- Every link pipeline variant would otherwise re-implement the same SQL
The operation in plain language: given a point table on an FWA network, drop any point that has another point downstream of it on the same flow path. Result = minimal set of points that define access blocking per reach.
Proposed function
frs_barriers_minimal(
conn,
from, # input table name (schema-qualified OK)
to, # output table name
key_col = "blue_line_key", # configurable for non-FWA networks
measure_col = "downstream_route_measure",
keep_cols = NULL # additional cols to preserve; NULL = all
)
Return: invisible to (for pipeability). Writes a new table at to containing only the downstream-most point per upstream flow path.
Implementation reference: the self-join SQL in link/data-raw/compare_bcfishpass.R — grep for fwa_upstream / non-minimal. Port that pattern into an R function following fresh's frs_* conventions (see frs_break_find, frs_break_apply for signature and doc style).
Abstraction notes
Alternatives considered:
- Keep as inline SQL in link — violates domain boundary (fresh owns graph ops), forces every link pipeline variant to re-implement
- Generalize to
frs_points_minimal — over-abstracts. Gradient barriers are the only current use case. Rename later if falls/crossings need the same reduction
- Add to fwapg as a SQL helper — requires upstream PR + release cycle for something that's a trivial R wrapper
- Name
frs_barriers_minimal vs frs_barriers_reduce — minimal matches bcfishpass terminology already documented in link research doc
Execution checklist
Tests required
- Empty input → empty output
- Single point → single-row output (nothing to remove)
- Two points on same
blue_line_key, different downstream_route_measure → only the downstream one kept
- Two points on different
blue_line_keys (unrelated streams) → both kept
- Branching: point on main stem + point on tributary → both kept (tributary not downstream of main)
- Integration: real WSG gradient barriers → reduction observed (count_before > count_after)
Example must show
- Why — reduce ~27k+ gradient barriers to the ~700 needed for access blocking
- How — one function call with before/after counts printed
- Where it fits — pipes into
frs_break_apply() for segmentation
Not in scope
- Generalizing to arbitrary point types (defer until a second use case appears — falls, crossings, observations)
- Per-species minimal barriers (that's link's barrier overrides logic — different concern)
- Spatial filtering (input table is assumed already filtered)
Cross-refs
- Unlocks:
NewGraphEnvironment/link targets-based pipeline refactor (filing separately)
- Reference SQL:
link/data-raw/compare_bcfishpass.R (the fwa_upstream self-join block)
Versions
- fresh: 0.13.8 (target: 0.14.0)
- link: main (0.1.0)
- bcfishpass: ea3c5d8
- fwapg: Docker (FWA 20240830)
Problem
The link comparison pipeline (
link/data-raw/compare_bcfishpass.R) hand-writes afwa_upstream()self-join to reduce gradient barriers to the minimal set needed for access blocking — keeping only the downstream-most barrier on each upstream path. On ADMS this reduces ~27,443 raw barriers to 677.This is a generic graph operation, not link-specific. It belongs in fresh:
fwa_upstream()wrapperslink/research/bcfishpass_comparison.md)The operation in plain language: given a point table on an FWA network, drop any point that has another point downstream of it on the same flow path. Result = minimal set of points that define access blocking per reach.
Proposed function
Return: invisible
to(for pipeability). Writes a new table attocontaining only the downstream-most point per upstream flow path.Implementation reference: the self-join SQL in
link/data-raw/compare_bcfishpass.R— grep forfwa_upstream/non-minimal. Port that pattern into an R function following fresh'sfrs_*conventions (seefrs_break_find,frs_break_applyfor signature and doc style).Abstraction notes
Alternatives considered:
frs_points_minimal— over-abstracts. Gradient barriers are the only current use case. Rename later if falls/crossings need the same reductionfrs_barriers_minimalvsfrs_barriers_reduce—minimalmatches bcfishpass terminology already documented in link research docExecution checklist
/planning-initonly if scope grows beyond one function (probably unnecessary here)link/data-raw/compare_bcfishpass.Rfrs_*signature style,connfirst arg,toreturntests/testthat/test-frs_barriers_minimal.R\dontrun{}) — show before/after counts on bundled or filtered data/code-checkbefore commitFixes #NNEWS.mdentryTests required
blue_line_key, differentdownstream_route_measure→ only the downstream one keptblue_line_keys(unrelated streams) → both keptExample must show
frs_break_apply()for segmentationNot in scope
Cross-refs
NewGraphEnvironment/linktargets-based pipeline refactor (filing separately)link/data-raw/compare_bcfishpass.R(thefwa_upstreamself-join block)Versions