Skip to contents

Fish-habitat convenience wrapper. Classifies segments in a segmented stream network for one or more species into a fixed output schema of accessible / spawning / rearing / lake_rearing / wetland_rearing booleans keyed by species_code. Produces long-format output: one row per segment x species.

Usage

frs_habitat_classify(
  conn,
  table,
  to,
  species,
  params = NULL,
  params_fresh = NULL,
  params_method = NULL,
  gate = TRUE,
  label_block = "blocked",
  barrier_overrides = NULL,
  overwrite = TRUE,
  verbose = TRUE
)

Arguments

conn

A DBI::DBIConnection object (from frs_db_conn()).

table

Character. Schema-qualified segmented streams table (from frs_network_segment()).

to

Character. Schema-qualified output table for habitat classifications (e.g. "fresh.streams_habitat").

species

Character vector. Species codes to classify (e.g. c("CO", "BT")).

params

Named list from frs_params(). Default reads from bundled CSV.

params_fresh

Data frame from parameters_fresh.csv. Default reads from bundled CSV.

params_method

Data frame with columns watershed_group_code and model ("cw" or "mad"), as in bcfishpass parameters_habitat_method.csv. Picks the habitat size model per watershed group: channel width (cw) or mean annual discharge (mad, which needs a mad_m3s column on table, as joined by frs_network_segment()). Watershed groups missing from it use cw. A table spanning groups on both models is classified per row on watershed_group_code. Default reads the bundled CSV (all cw). See frs_habitat_predicates() for how mad differs. Discharge coverage is incomplete: segments with NULL mad_m3s fail size thresholds in a mad group.

gate

Logical. If TRUE (default), breaks restrict classification — segments upstream of a blocking break are marked inaccessible. If FALSE, all segments are classified regardless of breaks (raw habitat potential).

label_block

Character vector. Labels that always block access. Default "blocked". Gradient labels (gradient_NNNN, the canonical 4-digit basis-point format like gradient_1500 for 15%, or the legacy gradient_N like gradient_15) are always threshold-aware regardless of this parameter. Set to c("blocked", "potential") for conservative analysis.

barrier_overrides

Character or NULL. Schema-qualified table of per-species barrier overrides (a "skip list") with columns blue_line_key, downstream_route_measure, species_code. Prepared by link::lnk_barrier_overrides() or equivalent. When provided and gate = TRUE, any blocking break whose position + species matches a row in this table is ignored during access gating — observations or habitat confirmations upstream have overridden the barrier for that species. Default NULL (no overrides; every blocking break restricts access).

overwrite

Logical. If TRUE, replace existing rows for these species in the output table. Default TRUE. The <to>_near_river table (below) is rebuilt for the table's groups whatever overwrite says.

verbose

Logical. Print progress. Default TRUE.

Value

conn invisibly, for pipe chaining.

Details

For non-fish domains — thermal refugia, riparian connectivity, sediment-transport models, any classification that doesn't fit the fixed output schema above — compose frs_classify() directly on your own output table. frs_classify() is pipeable, takes any label column name, and has no assumptions about what's being modelled.

Requires a segmented streams table (from frs_network_segment()) with id_segment, gradient, channel width, and ltree columns, plus a breaks table ({streams_table}_breaks) for accessibility checks.

When a spawn or rear rule of any of species has a near_river pair (its own mapping, or one it inherits from the thresholds CSV; see frs_habitat_predicates()), classify first runs frs_near_river() on table into <to>_near_river, one walk for every distinct (measure, threshold, distance_max) the rules ask for under the size models applied, and each rule reads its own pair's rows. Each pair needs its measure's column on table (mad_m3s, channel_width or stream_order) under either model; once a classified species has a pair, that check runs for every group, cw included. Species with no params_fresh row are not classified and walk nothing. The table is kept after classify, so a caller can re-test the predicates against it, and its walk sees only table: a river beyond the group's outlet is not found.

Examples

if (FALSE) { # \dontrun{
conn <- frs_db_conn()

# Assumes fresh.streams built by frs_network_segment() with
# gradient barriers labeled "gradient_1500", "gradient_2000",
# "gradient_2500" (15%, 20%, 25% — see frs_network_segment()).

# Classify CO, BT, ST — each gets species-specific accessibility.
# CO (15% access) is blocked by gradient_1500, gradient_2000,
# gradient_2500. BT (25% access) is only blocked by gradient_2500.
# Result: BT has ~2x the accessible habitat of CO on the same network.
frs_habitat_classify(conn,
  table = "fresh.streams",
  to = "fresh.streams_habitat",
  species = c("CO", "BT", "ST"))

# Query results — one table, all species, no geometry. Group by the
# watershed group too: the table accumulates one job per group, so a
# total over the whole table is not one job's result.
DBI::dbGetQuery(conn, "
  SELECT watershed_group_code, species_code,
         count(*) FILTER (WHERE accessible) as accessible,
         count(*) FILTER (WHERE spawning) as spawning,
         count(*) FILTER (WHERE rearing) as rearing
  FROM fresh.streams_habitat
  GROUP BY watershed_group_code, species_code")

# Join geometry back for mapping. `id_segment` is unique only WITHIN a
# watershed group, so the key is (id_segment, watershed_group_code) and
# both tables carry it — joining on id_segment alone multiplies rows by
# the number of groups sharing a value (fresh#218).
DBI::dbExecute(conn, "
  CREATE OR REPLACE VIEW fresh.streams_co_vw AS
  SELECT s.*, h.accessible, h.spawning, h.rearing, h.lake_rearing, h.wetland_rearing
  FROM fresh.streams s
  JOIN fresh.streams_habitat h
    ON s.id_segment = h.id_segment
   AND s.watershed_group_code = h.watershed_group_code
  WHERE h.species_code = 'CO'")

# Re-running is safe — existing rows for these species are replaced.
# Run more WSGs later and both tables accumulate.

DBI::dbDisconnect(conn)
} # }