diff --git a/DESCRIPTION b/DESCRIPTION index 46c169c..dc5a0b1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: link Title: Stream Network Habitat Interpretation (Experimental) -Version: 0.41.0 +Version: 0.41.1 Date: 2026-05-27 Authors@R: c( person("Allan", "Irvine", , "airvine@newgraphenvironment.com", diff --git a/NEWS.md b/NEWS.md index 2ee4c7d..b3622f9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# link 0.41.1 + +`data-raw/study_area_run.sh` gains a `--schema=` flag for side-by-side bundle compares. Without the flag, behaviour is unchanged (config's YAML `pipeline$schema` default). With the flag, the driver exports `LNK_SCHEMA` so all per-WSG R scripts (`wsg_run_one.R`, `wsg_recompute_one.R`, `study_area_compare.R`) override `cfg$pipeline$schema` at runtime. The propagation works through SSH to cyphers too (each remote shell exports `LNK_SCHEMA` before its WSG loop). Use case: `--config=default --schema=fresh_default` lets a default-config run land in `fresh_default` without clobbering an earlier `--config=bcfishpass` baseline in `fresh`. Empty `--schema=` value errors loudly rather than silently falling through to the YAML default. Live-validated on ADMS (2.2 min, 11 species habitat tables landed in `fresh_default`, `fresh` untouched). + # link 0.41.0 New exported function `lnk_wsg_resolve()` — the bundle-aware "what WSGs should we model?" resolver ([#207](https://github.com/NewGraphEnvironment/link/issues/207)). Composes the FWA drainage closure (now a fresh primitive: `fresh::frs_wsg_drainage()`, [NewGraphEnvironment/fresh#211](https://github.com/NewGraphEnvironment/fresh/pull/212) / fresh v0.32.0) with the bundle's `wsg_species_presence` filter (link#157). Three call patterns dispatched by `(wsgs, expand)`: province mode (`wsgs = NULL` → all bundle-species WSGs, sorted alphabetically), closure mode (`wsgs = c(...), expand = TRUE` → focal + drainage closure, DS-first preserved), strict mode (`wsgs = c(...), expand = FALSE` → species-filter input verbatim). Validation mirrors `lnk_pipeline_species`; closure mode opens its own DB conn via `lnk_db_conn()` with `on.exit` cleanup; closure + strict modes emit `message()` listing any species-less WSGs dropped from the result (parity with the previous inline diagnostic). New `@family wsg` — pre-stages a `lnk_wsg_*` family for follow-on topology helpers (e.g. cross-host DS-first bucketing). diff --git a/data-raw/study_area_compare.R b/data-raw/study_area_compare.R index c3fa52e..03e4112 100755 --- a/data-raw/study_area_compare.R +++ b/data-raw/study_area_compare.R @@ -28,6 +28,11 @@ suppressPackageStartupMessages({ source("data-raw/wsg_compare.R") cfg <- lnk_config(config) +# LNK_SCHEMA env var (set by study_area_run.sh --schema=) overrides the +# config's YAML default persist schema. Compare must read from the schema +# the run/recompute wrote to. +.lnk_schema_env <- Sys.getenv("LNK_SCHEMA") +if (nzchar(.lnk_schema_env)) cfg$pipeline$schema <- .lnk_schema_env rows <- list() for (w in wsgs) { diff --git a/data-raw/study_area_run.sh b/data-raw/study_area_run.sh index 201d785..e96f371 100755 --- a/data-raw/study_area_run.sh +++ b/data-raw/study_area_run.sh @@ -24,7 +24,7 @@ # --focal= \ # --focal= \ # --focal= \ -# [--config=bcfishpass] [--keep-cyphers] +# [--config=bcfishpass] [--schema=] [--keep-cyphers] # # The number of --focal flags MUST equal 1 (dispatcher) + N cyphers, in # order: first --focal -> dispatcher, the rest -> cyphers in --cy-workspaces @@ -38,12 +38,15 @@ set -euo pipefail # --- args --- CY_WS="" CONFIG="bcfishpass" +SCHEMA_OVERRIDE="" KEEP_CYPHERS=0 FOCAL_ARR=() for arg in "$@"; do case "$arg" in --cy-workspaces=*) CY_WS="${arg#--cy-workspaces=}" ;; --config=*) CONFIG="${arg#--config=}" ;; + --schema=*) SCHEMA_OVERRIDE="${arg#--schema=}" + [ -n "$SCHEMA_OVERRIDE" ] || { echo "FATAL: --schema= requires a non-empty value" >&2; exit 1; } ;; --focal=*) FOCAL_ARR+=("${arg#--focal=}") ;; --keep-cyphers) KEEP_CYPHERS=1 ;; *) echo "unknown arg: $arg" >&2; exit 1 ;; @@ -73,10 +76,18 @@ CYPHER_TF="$HOME/Projects/repo/rtj/env/do/dev/cypher" # cypher_prep does `git fetch origin && git reset --hard origin/$BRANCH`. LINK_BRANCH="$(git -C "$REPO_ROOT" branch --show-current)" -# Resolve persist schema (don't hardcode "fresh"). -SCHEMA=$(cd "$REPO_ROOT" && Rscript -e \ - 'cat(link::lnk_config(commandArgs(TRUE)[1])$pipeline$schema)' "$CONFIG" 2>/dev/null || true) +# Resolve persist schema: --schema= overrides the config's YAML default +# (e.g. for side-by-side bundle compares: --config=default --schema=fresh_default +# keeps the bcfp-config run intact in `fresh`). All R scripts read LNK_SCHEMA +# below and override `cfg$pipeline$schema` if it is non-empty. +if [ -n "$SCHEMA_OVERRIDE" ]; then + SCHEMA="$SCHEMA_OVERRIDE" +else + SCHEMA=$(cd "$REPO_ROOT" && Rscript -e \ + 'cat(link::lnk_config(commandArgs(TRUE)[1])$pipeline$schema)' "$CONFIG" 2>/dev/null || true) +fi [ -n "$SCHEMA" ] || { echo "FATAL: could not resolve persist schema for --config=$CONFIG"; exit 1; } +export LNK_SCHEMA="$SCHEMA" echo "=== study_area_run $TS ===" echo " config: $CONFIG" @@ -208,7 +219,7 @@ LOCAL_PID=$! declare -A CY_PID for WS in "${CY_WS_ARR[@]}"; do IP="${CY_IP[$WS]}"; B_SPACE=$(echo "${CY_BUCKET[$WS]}" | tr ',' ' ') - ssh "cypher@$IP" "cd ~/Projects/repo/link && for w in $B_SPACE; do Rscript data-raw/wsg_run_one.R \$w '$CONFIG' || echo \"[WARN] cy WSG \$w failed\"; done" \ + ssh "cypher@$IP" "cd ~/Projects/repo/link && export LNK_SCHEMA='$SCHEMA' && for w in $B_SPACE; do Rscript data-raw/wsg_run_one.R \$w '$CONFIG' || echo \"[WARN] cy WSG \$w failed\"; done" \ > "$LOG_DIR/${TS}_run_$WS.log" 2>&1 & CY_PID[$WS]=$! done diff --git a/data-raw/wsg_recompute_one.R b/data-raw/wsg_recompute_one.R index d8d8f2f..e42cbf7 100644 --- a/data-raw/wsg_recompute_one.R +++ b/data-raw/wsg_recompute_one.R @@ -43,6 +43,11 @@ DBI::dbExecute(conn, "SET statement_timeout = '600000'") # 10 min / statement DBI::dbExecute(conn, "SET lock_timeout = '60000'") # 1 min on lock waits cfg <- lnk_config(config) +# LNK_SCHEMA env var (set by study_area_run.sh --schema=) overrides the +# config's YAML default persist schema. Recompute must match the schema +# used by the run/consolidate phases. +.lnk_schema_env <- Sys.getenv("LNK_SCHEMA") +if (nzchar(.lnk_schema_env)) cfg$pipeline$schema <- .lnk_schema_env loaded <- lnk_load_overrides(cfg) active <- lnk_pipeline_species(cfg, loaded, wsg) diff --git a/data-raw/wsg_run_one.R b/data-raw/wsg_run_one.R index 0adc8a1..daefa50 100755 --- a/data-raw/wsg_run_one.R +++ b/data-raw/wsg_run_one.R @@ -34,6 +34,12 @@ conn <- lnk_db_conn(dbname = "fwapg", host = "localhost", port = 5432L, on.exit(try(DBI::dbDisconnect(conn), silent = TRUE), add = TRUE) cfg <- lnk_config(config) +# LNK_SCHEMA env var (set by study_area_run.sh --schema=) overrides the +# config's YAML default persist schema — used for side-by-side bundle +# compares so e.g. `--config=default --schema=fresh_default` doesn't +# clobber an earlier `--config=bcfishpass` run sitting in `fresh`. +.lnk_schema_env <- Sys.getenv("LNK_SCHEMA") +if (nzchar(.lnk_schema_env)) cfg$pipeline$schema <- .lnk_schema_env loaded <- lnk_load_overrides(cfg) # Defensive skip (link#157): a WSG with no bundle-species presence can't be