Compute the Adjusted multi-substance PAF (msPAF) for water quality samples
Source:R/mspaf.R
add_mspaf.RdAppends msPAF rows to a long-format water quality dataframe. msPAF estimates the fraction of aquatic species potentially affected by the combined toxicant mixture, adjusted for local geogenic background via the Added Risk Approach. See the file-level header for full methodological detail.
Usage
add_mspaf(
df,
reference = NULL,
analyte_metadata = NULL,
method = c("multi", "anzecc"),
guideline_dir = getOption("hydroSense.guideline_dir"),
min_analytes = 3,
ref_summary = c("geom_mean", "median", "arith_mean", "p80", "p90", "p95"),
conc_units = NULL,
require_temperature = TRUE,
tau = 90,
tau_units = "day",
window = 365,
window_units = "day",
return = c("summary", "draws"),
interval = 0.9,
central = c("median", "mean")
)Arguments
- df
Long-format monitoring dataframe. Required columns:
sample_id,site_id,analyte,value. Toxicant concentrations must ultimately be in µg/L for SSD lookup; supply them either via aunits.analytecolumn (one unit string per row, e.g."mg/L") or via theconc_unitsargument (applied uniformly to all SSD-eligible rows). Optional but recommended:datetime(propagated to msPAF rows if present),detected(assumedTRUEif absent),imputed(logical; if present,n_analytes_imputedis populated in output). Driver analytes needed for chemistry normalisation (e.g. pH, DOC) should be present as rows indf.- reference
Background reference chemistry for the ARA adjustment. Accepts four forms:
A
reference_modelfromfit_reference_model()— contemporaneous (temporal) ARA; the model predicts what the reference site would show at each target sample's exact moment using hydrology and seasonality.A
prepared_referenceobject fromprepare_reference()— normalisation has already been applied; used directly (static ARA).A raw long-format data frame (same schema as
df) — will be passed toprepare_reference()internally (static ARA).NULL(default) — no ARA adjustment; raw concentrations assessed directly against SSDs.
- analyte_metadata
Data frame of analyte metadata, or
NULLto load the bundledinst/extdata/anzecc_analyte_metadata.csv. Passed toprepare_reference()andderive_ssd_params().- method
SSD method passed to
ssd_hc50()andssd_paf()."multi"(default) fits all 6 BCANZ distributions and model-averages;"anzecc"uses the per-analyte distribution matching the original ANZG derivation.- guideline_dir
Path to the "guideline data" folder containing ANZG XLSX files. Falls back to
getOption("hydroSense.guideline_dir").- min_analytes
Minimum number of analytes with fitted SSDs required to compute msPAF for a sample. Default
3.- ref_summary
Summary statistic for the reference distribution when
referenceis a raw data frame. Passed through toprepare_reference(). Default"geom_mean"— the maximum-likelihood central tendency for log-normal concentrations, and a PICT-consistent estimate of the "typical" exposure the resident community has adapted to. Other options:"median","arith_mean","p80","p90","p95".- conc_units
Character. Unit string (e.g.
"mg/L","ug/L") applied uniformly to all SSD-eligible rows indfwhendfhas nounits.analytecolumn. Ignored whendfalready carriesunits.analyte. Required whendflacksunits.analyteand toxicant concentrations are not already in µg/L.- require_temperature
Logical (default
TRUE). WhenTRUE, any sample that reports anNH3-Nmeasurement must also carry a watertemperaturerow (the ammonia un-ionised-fraction normalisation is undefined without it); a missing temperature is a hard error rather than a silent drop of ammonia. Supply temperature via direct measurement, or derive it withestimate_water_temp()(optionally fed byget_silo_air_temp()). SetFALSEonly for datasets that do not assess ammonia.- tau, tau_units
Exponential-decay half-life for chronic window integration when
referenceis areference_model. Default90days.- window, window_units
Look-back window length for chronic integration. Default
365days.- return
Output mode for draw-carrier input (see
summarise_draws())."summary"(default) collapses posterior draws to a central estimate plus a credible interval (value,value_lower,value_upper,n_draws);"draws"returns the raw per-draw msPAF rows (draw_id 1..N) for external risk models or further composition (e.g. intotime_weighted_aggregate()). For point (non-draw) input both modes return byte-identical output with no interval columns.- interval
Width of the credible interval when
return = "summary". Default0.90(5th/95th percentile bounds).- central
Central-tendency statistic when
return = "summary":"median"(default) or"mean".
Value
The input df with msPAF rows appended. Each msPAF row carries:
value (msPAF as a percentage, 0–100+), detected = TRUE,
analyte = "msPAF", n_analytes_used (integer),
n_analytes_imputed (integer, 0 if imputed column absent),
dominant_analyte (character), and max_paf (numeric).
The result carries two attributes (read them before further dplyr wrangling,
which drops attributes): "analyte_pafs" — the per-analyte PAF breakdown as
a flat tibble (site_id, sample_id, draw_id in draws mode, analyte,
C_adj, PAF, moa_group, ref_source), retrieved with analyte_pafs();
and "ara_summary" — per-(sample × analyte) ARA diagnostics, retrieved with
ara_summary(). (analyte_pafs was formerly a per-row list-column; it is
now a flat attribute — issue #30.)
Tier breaks are not provided by this package — msPAF is a continuous
risk metric and the threshold at which a community is "impacted"
depends on the assessment context. See
vignette("chronic-mspaf-interpretation") for guidance.
Details
The function accepts either per-sample or chronic-integrated chemistry (from
time_weighted_aggregate()). It does not need to know which — the
distinction is entirely in the input data. Similarly, reference may be a
raw long-format chemistry data frame or a pre-built prepare_reference()
object.
Examples
# \donttest{
# Per-sample multi-substance PAF for the impacted site, with local
# background subtracted via the reference site. Uses the bundled SSD data.
demo <- leachate_demo()
ds <- subset(demo, site_id == "downstream")
ref <- subset(demo, site_id == "reference")
out <- add_mspaf(ds, reference = ref)
subset(out, analyte == "msPAF", c("sample_id", "value"))
#> # A tibble: 6 × 2
#> sample_id value
#> <chr> <dbl>
#> 1 DS-01 92.7
#> 2 DS-02 95.1
#> 3 DS-03 96.0
#> 4 DS-04 94.2
#> 5 DS-05 95.8
#> 6 DS-06 95.9
# }