Scientific stabilization of the IQA core and of the trophic state
indices. IQA and IET values change for some inputs; see
inst/audit/IQA_AUDITORIA.md and
inst/audit/REGRESSAO_0_10_0_0_11_0.csv for the full
before/after comparison.
This release also includes: - a breaking change: the
classification argument of iqa() was removed
(see “Calculation engines and comparison”); - a new IGAM engine,
iqa(method = "IGAM"), which is a documented reproduction
and is not endorsed by IGAM; - compare_iqa().
CETESB (2023) Appendix D gives the IQA sub-indices only as graphical
curves (Figure 1). The package’s piecewise equations come from the
CETESB spreadsheet as transcribed by CPRH (PNMA II) and by von Sperling
(2007, p. 255; reproduced by IBEAS 2015). Weights, fixed out-of-range
values, unit conversions and the classification match the official text
exactly; where the two secondary transcriptions disagree, the choice
follows the official curve. An independent re-implementation agrees with
iqa() to 1e-14 on 3000 inputs, and the published IBEAS/von
Sperling worked example (IQA = 81) is reproduced.
.qi_cetesb_ph(), 8.5 < pH <= 9:
10^(-1.1507 pH) replaced by exp(-1.1507 pH).
The old form gave qi ~ 0.0002 at pH 8.6. Example: wq_demo
point FBS-BRH-300 on 2023-05-24 moves from 15.58 (Pessima) to 82.55
(Otima)..qi_cetesb_ph(), 9 < pH <= 10:
50 - 32 (pH - 9) replaced by 288 - 27 pH
(removes the 45 -> 50 jump at pH 9; Figure 1 has no jump there). CPRH
prints 228 - 27 pH (an evident typo: it would give qi <
0), while von Sperling via IBEAS gives the old form. Effect on the IQA:
at most 0.9 point. Maintainer decision pending..qi_cetesb_dbo(), 5 < DBO <= 15 mg/L, and
.qi_cetesb_nt(), 10 < NT <= 60 mg/L:
log10() replaced by natural log(), removing
the jumps at 5/15 and 10/60 mg/L. IQA drops by up to ~9 points (DBO) and
~15 points (NT) in these ranges. Figure 1 confirms the corrected values
(e.g. BOD 10 mg/L: ~30, was 73). Note: spreadsheets that follow the von
Sperling (2007) transcription with log10 (e.g. IBEAS 2015)
give higher IQA values in these ranges.Cs: cubic coefficient 0.00005898
corrected to 0.00005896 (CPRH; von Sperling via IBEAS). Effect below
0.02% of Cs..qi_cetesb_temperatura(): delta T < -5 C now gives
NA (qi is “undefined” per Figure 1); it returned 93.
temperature_method = "delta"/"reference" now
warns that the package’s delta-T curve does not match the CETESB curve;
these modes are experimental and flagged in
attr(, "iqa_nonstandard"). The default (qi = 94: CPRH and
IBEAS “constant of 94 adopted by CETESB”; consistent with the source’s
q^w = 1.58) is unchanged.iqa() now assigns IQA_status from the
unrounded IQA; rounding to two decimals is display only (e.g. 79.004 is
Otima although shown as 79.00).iet_lamparelli(): now uses the Lamparelli (2004)
equations given by CETESB (Appendix D 2023, p. 10), different for rivers
and reservoirs, with total phosphorus and chlorophyll-a in ug/L. Until
v0.10.0 it used 10 + 10 log10(x) for both environments,
which classified almost any sample as ultraoligotrophic (e.g. TP = 137
ug/L in a river gave 1.4 instead of 59.5). Results now reproduce the
class limits of Tables 5 and 6. Secchi depth is returned as an auxiliary
component and no longer enters IET_Lamp, as CETESB does not
use transparency.iet_carlson(): natural logarithm instead of
log10 (Carlson 1977 defines TSI = 10 (6 - log2 SD); the
14.41/14.42/9.81 coefficients only hold with ln). Example: TP = 48 ug/L
now gives 60 (was 28.4).generate_analysis(): the dominant IQA class now uses
the CETESB scale of classify_iqa() instead of a private
25/50/70/90 scale, and the text reports how many samples are partial IQA
estimates.plot_map_quality(): auto-detection now recognizes
IET_Lamp, the column returned by
iet_lamparelli() (it only looked for
IET_Lamparelli, so Lamparelli output was never detected;
the corresponding test was silently skipped).Inf) now become
NA with a warning instead of being silently truncated to 0
(which gave the best possible qi).iqa_methods() lists the IQA calculation engines and
their validation status.iqa(df, method = "IGAM"): an engine independent of
the CETESB one, giving a documented computational reproduction of the
IGAM (Minas Gerais) IQA. It is not endorsed by IGAM.
nitrate_unit (“N” or “NO3”) is required with
nitrate;p_total requires phosphorus_basis, while
fosfato_total (PO4) is used as is;microbial_type must choose one;allow_partial, pesos and the CETESB
temperature options raise an error.system.file("methodology", "IGAM_VALIDATION.md", package = "tikatuwq").iqa_methods(): IGAM is available = TRUE
and reference_validated = TRUE.
reference_validated is now documented as reproducing values
published by the reference institution, within the scope stated
in limitation. It is not endorsement or validation in every
basin.compare_iqa() now compares CETESB and IGAM on paired
samples.iqa_components(method = "IGAM") points to
iqa(df, method = "IGAM", details = TRUE).nitrate_unit in iqa(), used
only by IGAM.cloreto (chloride, mg/L).compare_iqa(): runs each engine on the same rows,
keeps row identity (id_cols), reports eligibility and
reasons per method, and computes paired statistics (mean/median
difference, MAE, RMSE, correlations with >= 3 pairs) only on rows
valid for all methods. Class differences are reported as a transition
table, not as label agreement. Unavailable methods make all rows
ineligible instead of failing.iqa() no longer has a
classification argument (it existed in 0.10.0 with
"cetesb"/"legacy"). The scale follows
method; passing classification or
scheme is an error that points to
classify_iqa(iqa(df)$IQA, classification = ...). Positional
calls from 0.10.0 with the classification as third argument
(iqa(df, "CETESB", "legacy")) now fail with the same
migration message, because the third argument is now
altitude_m. classify_iqa() is unchanged. New
attributes iqa_calculation_method and
iqa_method_version.iqa_methods() reports implemented,
documented, reference_validated,
available and limitation for each engine.fosfato_total (total phosphate as
PO4), distinct from p_ortofosfato and
p_total.method = "ANA" (see
inst/audit/ANA_VS_CETESB.md);
classify_iqa(classification = "ana") stays.nsfwqi_validation.na_rm = FALSE, a component without a column now
gives NA, as documented (it was silently dropped with
renormalized weights). All 20 wq_demo rows (no nitrate, no
total solids) change from a value to NA in strict mode;
partial (na_rm = TRUE) values are unchanged
(inst/audit/REGRESSAO_NSFWQI_0_11_0.csv).classify_iqa() now uses classification
(same name as in iqa()). scheme still works
but is deprecated (warning); giving both with different values is an
error. iqa() also accepts scheme via
... with the same rules."igam" (25/50/70/90) and
"ana". "ana" uses the 19/36/51/79 cuts shown
on the current ANA portal and is an alias of "cetesb".
classification never changes the numeric IQA.classify_iqa() returns NA (with a warning)
for values outside [0, 100]; previously they were classified as the
lowest/highest class.iqa() now forwards delta_temperature (it
was silently ignored). temperature_method = "delta" without
a delta, or "reference" without
temperature_reference, is now an error instead of silently
using qi = 94.pesos: must be a named, finite, non-negative vector of
known parameter names. Unknown names (e.g. tds) were
silently ignored before and are now an error. With
details = TRUE, the wi_* and
term_* columns hold the effective
(renormalized) weights, so prod(qi^wi) reproduces the
IQA.allow_partial = TRUE: partial rows are listed in
attr(, "iqa_partial_rows") and, with
details = TRUE, in the new
IQA_partial/missing_params columns. This is a
package estimate, not an institutional rule.altitude_m accepts one value per row; values outside
-500..9000 m are an error.na_rm in iqa() is deprecated in favour of
allow_partial. Unknown arguments passed through
... now produce a warning.iqa() output, including
for empty input and the legacy routes:
iqa_method_reference, iqa_weights,
iqa_custom_weights, iqa_allow_partial,
iqa_partial_rows, iqa_nonstandard.
iqa_complete now reports whether every computed row was
complete (it used to echo !allow_partial).inst/audit/IQA_AUDITORIA.md.?iqa: method vs classification, missing
data, invalid values.?wq_demo now states that the dataset has TDS but not
total solids, so its IQA values are partial estimates (8 parameters),
not CETESB IQA values, and that it is not an independent benchmark.inst/audit/REGRESSAO_CETESB_POS_API.csv) and IGAM tests on
synthetic samples, whose expected values come from an independent
implementation.R CMD check --as-cran: 0 errors and 0 warnings on
Windows (local, and win-builder R-devel and R-release), Linux (Ubuntu)
and macOS (R-release, Apple silicon). win-builder reports 1 note: the
place name “Minas Gerais” in DESCRIPTION is flagged as a possible
misspelling.288 - 27 pH, which is continuous and follows the
curve; the alternative is 50 - 32 (pH - 9). The effect is
at most 0.9 IQA points, with no class change in the tests. Decision
pending.temperature_method = "delta"/"reference"): it
has no traceable source and stays experimental, with a warning. The
default (qi = 94) is not affected.iqa() now implements the official validated continuous
piecewise polynomial/exponential equations from CETESB/INEMA rather than
discrete/interpolated approximation tables.solidos_totais (Total Solids /
Resíduo Total, weight 0.08). TDS (tds) is no longer
accepted silently as a synonym for Total Solids; providing
tds in strict CETESB mode throws an explicit, informative
error.phosphorus_basis = "P"), matching the calibration
basis of the CETESB sub-index curve.temperatura) is used exclusively to compute DO saturation
percentage (accounting for altitude via altitude_m), while
temperature change \(\Delta T\)
(delta_temperatura) is an independent component defaulting
to \(Q_i = 94\) (operational hypothesis
of thermal equilibrium).coliformes_termotolerantes. E. coli inputs are converted
using the CETESB factor \(1.25\times\)
via microbial_type = "e_coli".iqa()
with method = "CETESB" requires all 9 components. Partial
calculation now requires explicit allow_partial = TRUE and
flags missing components in metadata.classify_iqa() updated to official CETESB
categories: Péssima (\(\le 19\)), Ruim
(\(19\text{--}36\)), Regular (\(36\text{--}51\)), Boa (\(51\text{--}79\)), Ótima (\(79\text{--}100\)).iqa_components() and
iqa(..., details = TRUE): Comprehensive audit layer
returning raw values, transformed values, \(Q_i\), \(W_i\), and \(Q_i^{W_i}\) for each parameter.censor_policy = c("limit", "half_limit", "preserve", "zero", "na")).iqa() now defaults to the correct weighted
geometric mean (method = "CETESB") as specified by
CETESB and the original NSF WQI (Brown et al., 1970). The previous
arithmetic mean behaviour is preserved via
method = "NSF_approx". Existing code using
iqa() without specifying method will produce
different (more accurate) IQA values. (#P0)mk_seasonal(): seasonal Mann-Kendall trend test
(Hirsch, Slack & Smith, 1982). Splits the time series by season
(monthly or wet/dry via assign_season()), computes S and
VAR(S) per season, aggregates, and returns Z, p-value, Kendall tau, and
Sen’s slope (units/year) per group. Removes the seasonal bias that
inflates false positives in standard Mann-Kendall tests applied to
tropical rivers. (#P6)plot_map_quality(): interactive Leaflet map coloring
sampling sites by IQA, IET (Carlson or Lamparelli), or NSF WQI value.
Uses the standard classification palettes for each index and shows class
and value in the popup. Extends plot_map() with index-aware
choropleth logic. (#P12)balnear_check(): classifies sampling sites for
primary-contact recreation (swimming) under CONAMA Resolution 274/2000
(Excelente, Muito Boa, Satisfatória, Imprópria) based on the 80% rule
over the last 5 collections. Supports thermotolerant coliforms and E.
coli; flags sites with insufficient samples. (#P16)conama_freq_check(): implements the legal frequency
rule of CONAMA 357/2005 Art. 15 — conformity assessed as ≥80% of samples
within limits, requiring at least 6 samples per year. Returns a tibble
with per-point, per-year, per-parameter compliance status. (#P1)assign_season(): adds a hydrological season column
("chuvoso" / "seco") to a data frame, based on
regional Brazilian calendars (Sudeste, Nordeste, Norte, Sul,
Centro-Oeste, Bahia) or a custom month vector. (#P3)compare_seasons(): compares a water quality parameter
between wet and dry seasons using Wilcoxon, t-test, or Kruskal-Wallis;
returns descriptive statistics, test results, and optionally a
ggplot boxplot. (#P3)plot_iet(): bar chart (vertical or horizontal) for the
Trophic State Index with color-coded trophic classes, supporting both
Carlson (1977) and Lamparelli (2004) classification schemes. (#P4)compute_load(): computes pollutant load as
concentration × flow × unit factor; supports kg/day, t/day, kg/year, and
g/s outputs. (#P7)exceedance_prob(): estimates empirical exceedance
probability with Wilson confidence interval, by group. (#P8)wq_pca(): PCA wrapper around
stats::prcomp() with automatic column selection, biplot,
screeplot, and loadings plot as ggplot attributes.
(#P15)nsfwqi(): updated to use weighted geometric mean
(consistent with CETESB IQA fix), adds add_status and
locale arguments, removes prototype language. (#P5)inst/extdata/conama_limits.csv expanded from ~38 to
~116 rows, adding nitrogen species (NO3, NO2, NH3 with pH-conditional
limits), inorganic ions (fluorides, chlorides, sulfates), organic
pollutants (phenols, surfactants), and 14 heavy metals / trace elements
for Classes 1–3. (#P2)R/testando.R: replaced empty file with documented
placeholder comment.R/wq_buranhem.R: removed duplicate
@docType tag that caused a R CMD check
WARNING.DESCRIPTION: version bumped to 0.9.0;
tools added to Imports.test-iqa-geometric.R,
test-conama_freq.R, test-seasonal.R,
test-load_exceedance.R, test-plot_iet.R,
test-wq_pca.R).plot_map() to use internal
dataset wq_demo instead of external file reference. All
examples and tests now comply with CRAN policies (no local file
dependencies, write only to tempdir). No API changes.render_report()
now copies the template to a temporary directory before rendering to
comply with CRAN filesystem policies. All intermediate files generated
during rendering are written only to output_dir (default
tempdir()), never to the package installation directory.
Tests for render_report() are now skipped on CRAN
(skip_on_cran()) and use
withr::local_tempdir() for proper cleanup.wq_demo example dataset is now a subset of real data (from
BURANHEM river monitoring, 4 points, years 2020–2024, 20 rows). Includes
extra columns: rio, lat, and
lon.R/data_wq_demo.R,
inst/extdata/wq_demo_README.txt, vignettes, README) updated to reflect
the change.iet_carlson() e iet_lamparelli()
agora aceitam data.frame com .keep_ids.p_total (mg/L) → tp (µg/L).iqa() mais robusto: alias temp para
temperatura, numificação segura e reponderação com
na_rm=TRUE..keep_ids.Changes in this version: - Fixed incoming NOTE detected in pre-tests:
- Removed non-standard fields (DOI, Citation)
from DESCRIPTION. - Updated inst/CITATION to use the modern
bibentry() format instead of the deprecated
citEntry(). - Minor internal documentation updates (no API
or functional changes).
citation("tikatuwq")).param_analysis() and
param_analysis_multi():
test-param_analysis.R,
test-param_analysis_multi.R).plot_trend() and
plot_map() (controlled messages).generate_analysis()
(docs matched to code).README-pt.md, now using absolute
HTTPS URL.plot_trend():
ggplot object ready for plotting.plot_trend() with practical
examples.plot_map() — interactive map of sampling points
using Leaflet (optional dependency via Suggests).if (interactive()) /
\donttest{} to avoid network calls on CRAN.skip_on_cran() and
skip_if_not_installed("leaflet") guards for map tests.\u escapes.htmltools from
Imports.inst/WORDLIST).@return for all exported functions.conama_limits() now accepts
class argument for filtering.