--- title: "Eutrophication: a corrected cut-off, and why it matters" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Eutrophication: a corrected cut-off, and why it matters} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(reiod) ``` ## What you need to know **Supply eutrophication in grams PO₄³⁻eq per person per day, exactly as the EIOF database gives it to you. Nothing needs converting.** That is the whole instruction. The rest of this page explains why it needs saying at all, and why **eight values in `eiod_cutoffs` deliberately do not match the currently published methods paper**. ## The eight corrected thresholds ```{r} subset(eiod_cutoffs, value_source != "published", c(demogroup_label, metric, unit, value, value_source)) ``` These are the **Table 3 eutrophication thresholds**. Intake supplied them by email in October 2026. The published PDF prints the same eight cells in **kilograms**; Table 4f and the EIOF food databases use **grams**. Intake confirmed that both tables are intended to be in grams, and corrected Table 3. Every other row in the dataset — all 608 of them — is exactly what the paper prints. ## The quantity did not change, only the unit This is the reassuring part. The corrected values are the printed ones multiplied by 1000: ```{r} corrected <- subset(eiod_cutoffs, value_source != "published") corrected <- corrected[order(corrected$demogroup), ] published_in_pdf <- c(0.0076827204, 0.0119198764, 0.0164158298, 0.0267453228, 0.0074439228, 0.0110398856, 0.0150718438, 0.0215133770) data.frame( group = corrected$demogroup_label, pdf_kg = published_in_pdf, shipped_g = corrected$value, pdf_x1000 = published_in_pdf * 1000, agrees = sprintf("%.10f", corrected$value / 1000) == sprintf("%.10f", published_in_pdf) ) ``` Divide any shipped value by 1000 and you recover the printed figure to the ten decimals the PDF gives. `data-raw/build_data.R` asserts this on every build, so the two can never silently part company. **No classification moves.** Tested across 400,000 simulated gram-scale values, the old behaviour (divide the user's grams by 1000, compare against the PDF's kilograms) and the new one (compare grams directly) agreed everywhere. They can differ only within about one unit in the last place of a cut-off — and there the new path is the more exact of the two, because it no longer divides before comparing. ## What this means for your code ```{r} grp <- eiod_age_sex_group(eiod_demo$age, eiod_demo$sex) eutr_g <- eiod_demo$eutroph_gpo4e # already grams - nothing to convert ``` Both metrics now take the same input, with no conversion and no message: ```{r} table(eiod_absolute_threshold(eutr_g, grp, "eutroph"), useNA = "ifany") ``` ```{r} table(eiod_relative_band(eutr_g, grp, "eutroph"), useNA = "ifany") ``` > **If you wrote a script against an earlier version of this package, remove > any `/1000` you applied to eutrophication.** Between July and October 2026 > `reiod` expected kilograms for the absolute metric and divided for you; it > no longer does. Dividing now would make your results wrong by a factor of a > thousand in the other direction. > > `eiod_check_magnitude()` catches that: a eutrophication column a thousand > times too small is reported as a likely unit error. ## How the problem was found Worth recording, because the same reasoning applies to any reference table that ships without units. The paper states no unit for Tables 4a–4g anywhere. Taken at face value, the Table 4f benchmarks were about **690 times** the Table 3 threshold for the same demographic group — a gap no other indicator came close to. The decisive test was that the ratio between the two tables is **constant across all eight demographic groups**. A methodological difference would vary by group; a unit difference cannot. Comparing that ratio across indicators put eutrophication three orders of magnitude outside the range of the other six: | Indicator | Table 4 P10 ÷ Table 3 threshold | |---|---:| | Pasture land use | 0.026 | | Total land use | 0.285 | | Water use | 0.346 | | Biodiversity loss | 0.548 | | Arable land use | 0.688 | | Greenhouse gas emissions | 1.449 | | **Eutrophication (as published)** | **689.647** | | **Eutrophication ÷ 1000** | **0.690** | Divided by 1000 it falls back among the others, almost exactly on the arable-land value. Supporting evidence came from the EIOF country databases, which report `Eutr. (g PO43-e/kg)` while every other column matches the paper's unit, and from the fact that the kilogram reading implies a 10th-percentile adult diet of 18.4 kg PO₄³⁻eq **per day**. That analysis was put to Intake as a technical note, and the correction above is their reply. ## Checking the current state yourself Every indicator now uses one unit across both tables: ```{r} with(eiod_cutoffs, table(indicator, unit)) ``` And the Table 3 threshold sits in a sensible place within its own reference distribution, for every indicator: ```{r} for (ind in eiod_indicators$indicator) { thr <- as.numeric(eiod_lookup_cutoff(ind, 4, "abs")) p <- vapply(seq(10, 90, 10), function(q) as.numeric(eiod_lookup_cutoff(ind, 4, "rel", q)), numeric(1)) k <- sum(thr >= p) pos <- if (k == 0) "below P10" else if (k == 9) "at/above P90" else sprintf("P%d-P%d", k * 10, (k + 1) * 10) cat(sprintf("%-12s %s\n", ind, pos)) } ``` Eutrophication now sits at P40–P50 with the two land-use indicators — where, before the correction, reading it at face value put it below P10 alongside greenhouse gases. ## See also * `?eiod_cutoffs` — the reference data and the `value_source` column * `?eiod_list_indicators` — the input unit for all seven * `vignette("precision")` — the pre-flight checks