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:
classification argument of iqa() was removed
(see "Calculation engines and comparison");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:
DOI, Citation) from DESCRIPTION.inst/CITATION to use the modern bibentry() format instead of the deprecated citEntry().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.