Appends LMF rows to a long-format water quality dataframe. LMF is a source-detection index estimating what fraction of a sample's chemistry can be attributed to the leachate end-member under a two-component mixing model. See the file-level header for full methodological detail.
Usage
add_lmf(
df,
leachate_data = NULL,
reference_data = NULL,
lmf_analyte_uuid = NA_character_,
calibration_window_years = 5,
min_leachate_total_n = NULL,
min_leachate_total_n_units = NULL,
rsd_default = 0.05,
min_ref_samples = 10,
min_leachate_samples = 10,
max_sigma_lsi = 10,
max_chi2_per_df = Inf,
informativeness_threshold = 0.2,
min_high_info_ions = 3L,
robust_iterations = 3L,
robust_threshold_k = 2.5,
verbose = FALSE
)Arguments
- df
Long-format dataframe. Required columns:
sample_id,site_id,analyte,value,detected,datetime.- leachate_data
Optional long-format dataframe in the same structure as
dfproviding leachate end-member chemistry. Required columns:sample_id,analyte,value,detected. When supplied, all samples are used to build the leachate end-member regardless of date and regardless of total-N content (the total-N quality filter is bypassed — supply curated data). Samples missing the required LMF panel analytes are silently dropped.NULL(default) uses the standard leachate feature detection logic (requires dashboard infrastructure:feature_df(),data_df()).- reference_data
Optional long-format dataframe in the same structure as
dfproviding reference site chemistry for end-member calibration. Required columns:sample_id,analyte,value,detected. When supplied, all samples are used to build the reference end-member regardless of date; the calibration window is ignored. The same end-member is applied globally to all features.NULL(default) uses the standard per-feature matched reference site logic (requires dashboard infrastructure:feature_sfc(),data_df()).- lmf_analyte_uuid
UUID assigned to LMF rows in the
uuid.analytecolumn of the output. Set to a fixed UUID if integrating with a data system that tracks analytes by UUID. DefaultNA_character_.- calibration_window_years
Number of years of calibration data to use. Window is centred on the input data's date range and shifted backwards if future data are unavailable. Default
5.- min_leachate_total_n
Minimum total N (sum of NH4-N + NO3-N + NO2-N) for a leachate sample to qualify for end-member calibration. Excludes non-representative samples (dilution events, treatment upsets). Total N is used rather than NH4-N alone because aerated leachate features may have nitrified NH4 to NO3. Numeric or
unitsobject; bare numeric requiresmin_leachate_total_n_units. DefaultNULL→ 20 mg/L.- min_leachate_total_n_units
Character unit string for
min_leachate_total_nwhen it is bare numeric, e.g."mg/L". Ignored whenmin_leachate_total_nis aunitsobject orNULL.- rsd_default
Default relative analytical uncertainty, applied as
sigma_meas = rsd_default * |x|with a floor atrsd_default * |R|. Default0.05(5% RSD).- min_ref_samples
Minimum reference samples required in the calibration window. Features matched to a reference site with fewer samples are skipped silently. Default
10.- min_leachate_samples
Minimum valid leachate samples required for end-member construction. The function stops with an informative error if not met. Default
10.- max_sigma_lsi
Maximum permitted
sigma_lmfin percentage points (uncertainty on the mixing fraction estimate). Samples above this threshold returnNAwith reason code"insufficient_precision". Default10(i.e., ±10 percentage points).- max_chi2_per_df
Maximum permitted chi-squared per degree of freedom (computed on the original inverse-variance weights, before robust reweighting). Retained as a diagnostic output in all cases. Default
Inf(no hard gate — the robust reweighting handles outlier ions directly, making a hard chi2 gate redundant for most samples).- informativeness_threshold
Threshold on
sigma_R / |L - R|for classifying ions as high-information. Computed once from calibration data, not per-sample. Lower values are more stringent. Default0.20.- min_high_info_ions
Minimum number of high-information ions that must be measured in a sample for LMF to be computed. Samples below this threshold return
NAwith reason code"insufficient_high_info_ions". Default3L.- robust_iterations
Number of Huber M-estimator reweighting passes. In each pass, ions whose studentized residuals exceed
robust_threshold_kare downweighted proportionally. Three iterations is sufficient for convergence in practice. Set to0Lto disable robust reweighting entirely. Default3L.- robust_threshold_k
Huber threshold in standard-deviation units on studentized residuals (
r_i / sqrt(var_f_i)). Ions with|sr_i| > khave their estimation weight reduced by a factor ofk / |sr_i|. Smaller values downweight more aggressively;k = 2.5is close to the conventional Huber constant. Default2.5.- verbose
If
TRUE, prints an ion informativeness table viacli::cli_inform()showing each ion's score and high/low classification. Useful when tuninginformativeness_threshold. DefaultFALSE.
Value
The input df with LMF rows appended. Each LMF row carries
value (the robust LMF estimate as a percentage, 0 = pure reference,
100 = pure leachate), name.analyte = "LMF", uuid.feature
(from the input), lmf_naive (the non-robust estimate for
comparison), lmf_reason (NA on success, reason code on
failure), n_ions_used, n_ions_downweighted (count of ions
whose weight was reduced by robust reweighting), n_high_info_downweighted
(count of downweighted ions that were high-information tracers; a robust
estimate carried by the low-information majority against sensitive
tracers signals a mis-attributed source, not a transformation artifact),
sigma_lmf, and chi2_per_df (diagnostic; computed on original
weights). Columns present in df but not produced by the LMF
computation are NA in the appended rows.
References
Christophersen N, Hooper RP (1992) Water Resources Research 28(1):99-107. Christensen JB et al. (2001) Applied Geochemistry 16(7-8):659-718. Kjeldsen P et al. (2002) Crit Rev Environ Sci Technol 32(4).
Examples
# \donttest{
# Quantify each downstream sample's leachate-mixing fraction from its
# major-ion signature, calibrated against the leachate and reference
# end-members in the bundled demo data.
demo <- leachate_demo()
out <- add_lmf(
df = subset(demo, site_id == "downstream"),
leachate_data = subset(demo, site_id == "leachate"),
reference_data = subset(demo, site_id == "reference")
)
subset(out, analyte == "LMF", c("sample_id", "value"))
#> # A tibble: 6 × 2
#> sample_id value
#> <chr> <dbl>
#> 1 DS-01 14.9
#> 2 DS-02 14.7
#> 3 DS-03 14.7
#> 4 DS-04 15.1
#> 5 DS-05 14.6
#> 6 DS-06 14.9
# }