If you plan to irrigate crops with treated
wastewater (water reuse, or REUT), you need to know
whether the water is safe. ambre answers that question with
QMRA – Quantitative Microbial Risk Assessment –
estimating the health risk of a programme for the reuse of treated
wastewater for exposed populations: field workers, local residents and
consumers of the products.
The benchmark is the World Health Organization target of no
more than 1e-6 DALY per person per year (one micro
disability-adjusted life-year). ambre follows the
multi-barrier idea: pathogens are cut down not only by
the wastewater-treatment plant but also by on-field practices (drip
instead of sprinklers, buffer distances, washing, peeling…), all
modelled from one shared log-reduction database. This article is the
guided tour; the other vignettes go deeper on each piece.
ambre lives on the INRAE forge. Install it once with
remotes:
You do not need your own data to follow along. The package ships four
example input files – ready-made Excel scenarios – that every function
in this tour reads through system.file():
list.files(system.file(package = "ambre"), pattern = "\\.xlsx$")
#> [1] "input_1culture_2pop.xlsx"
#> [2] "input_cas_apprentissage_complet.xlsx"They grow in size from a single crop and population
(input_1culture_1pop.xlsx) to a full learning case of 35
exposed populations (input_cas_apprentissage_complet.xlsx).
We will use the two-row file input_1culture_2pop.xlsx
throughout.
scenario objectEverything in ambre revolves around one table, the
scenario. You build it from an Excel file with
create_scenario():
scenario <- create_scenario(
system.file("input_1culture_2pop.xlsx", package = "ambre")
)
dim(scenario)
#> [1] 2 24Each row is one combination of crop x exposed population x exposure path. The example has two rows, so two situations to assess. Let’s look at the columns that matter most:
dplyr::glimpse(
scenario[, c("CropName", "PopulationName", "PathName",
"CropID", "PopulationID", "PathID", "config")]
)
#> Rows: 2
#> Columns: 7
#> $ CropName <chr> "Tomato", "Corn seed"
#> $ PopulationName <chr> "Irrigation staff", "Maintenance staff"
#> $ PathName <chr> "Ingestion of water droplets during maintenance of the …
#> $ CropID <dbl> 6, 1
#> $ PopulationID <dbl> 1, 2
#> $ PathID <dbl> 1, 4
#> $ config <list> [[<spec_tbl_df[3 x 10]>], [<spec_tbl_df[38 x 13]>], [[<…The human-readable names you typed in Excel (CropName,
PopulationName, PathName) are each resolved to
an integer key – CropID, PopulationID,
PathID – that ambre uses to look values up in
its internal database.
The last column, config, is the interesting one: it is a
list-column holding, on every row, a full private copy
of the bundled config_ambre database. As the QMRA pipeline
runs, each step writes its results back into that per-row config, so a
scenario carries both its inputs and its growing outputs in a single
object. You rarely touch config by hand – the run functions
below do it for you.
The fastest way to a result is run_qmra_treatment().
Give it a scenario file and one or more pathogens; it runs the whole
workflow – simulate inflow concentration and exposure volume to
calculate the initial dose, simulate log-reduction from the treatment
scheme to calculate the final dose of exposure, calculate infection and
illness probability, and DALYs – and returns a set of figures.
The function prints a running commentary as it works, so we send that
noise to nowhere with results = "hide" and look at the
pictures afterwards:
library(dplyr)
scenario <- create_scenario(system.file("input_1culture_2pop.xlsx", package = "ambre"))
regulation_reduction <- config_ambre$regulation$regulation_value |> filter(Country == "France") |>
select(-c(Concentration, Country, RegulationID))
regulation_concentration <- config_ambre$regulation$regulation_value |> filter(Country == "France") |>
select(-c(Country, RegulationID, Reduction))
plots <- run_qmra_initial_situation(scenario = scenario,
pathogen = c("Campylobacter jejuni", "Norovirus"),
regulationLog = regulation_reduction,
regulationConcentration = regulation_concentration)What comes back is a named list of five ggplot
objects:
These five steps trace the journey of raw water through to its
effects on health. (This run takes into account only treatment-type
barriers; to also include agricultural practice-type barriers, see
run_qmra_barrier() and the comparative vignette below.)
Print each element to see it. Here is what each one tells you.
Log-reduction – how many log10 units each barrier in the train removes according to pathogen group simulated (Bacteria, Viruses, Protozoa); a taller box means a more effective barrier.
#>
#> $Viruses
DALYs – the disability-adjusted life-years lost per person per year, on a log scale. The red line marks the objective: boxes sitting below it meet the tolerable-risk goal, boxes crossing above it do not. The default value of 1e-6 DALY corresponds to the WHO target.
#>
#> $Norovirus
Each plot is a boxplot for a reason: ambre is a
Monte-Carlo engine that repeats the calculation many
times, so a result is a range of plausible values, not a single
number. Reading that spread is the subject of its own vignette.
Regulation matrix
The outcome of an exposure scenario can be assessed in terms of regulatory compliance with regard to: - Log‑reduction (the decrease in pathogen concentration expressed in log10 units: regulation_matrix_log()
| Crop name | Target water class | Bacteria | Viruses |
|---|---|---|---|
| Tomato | B | 12 | 8 |
| Corn seed | D | 12 | 8 |
| Crop name | Target water class | Campylobacter jejuni | Norovirus |
|---|---|---|---|
| Corn seed | D | 0 | 100 |
| Tomato | B | 0 | 100 |
The background color indicates whether the reduction results are sufficient in relation to the regulations (green: complies with or falls below regulatory requirements; red: fails to meet regulatory requirements)
Other figures can be generated :
Inflow pathogen concentration
The plot_inflow() function generates a violin plot
showing the distribution of pathogen inflow concentrations simulated in
a scenario. Each violin represents the variability of the inflow
concentration for one pathogen, while colors distinguish pathogen
groups.
scenario_with_inflow <- inflow_concentration(scenario = scenario,
pathogenName = c("Campylobacter jejuni", "Norovirus"))
#> Simulated pathogen: Campylobacter jejuni
#> Create 1000 random distribution(s): uniform (n: 60, min: 100.000000, max: 5000.000000)
#> Simulated pathogen: Norovirus
#> Create 1000 random distribution(s): uniform (n: 60, min: 0.000000, max: 1000000.000000)
#> Providing inflow events ... ok. (0.00 secs)
#> Providing inflow paras ... ok. (0.00 secs)
#> Simulated pathogen: Campylobacter jejuni
#> Create 1000 random distribution(s): uniform (n: 48, min: 100.000000, max: 5000.000000)
#> Simulated pathogen: Norovirus
#> Create 1000 random distribution(s): uniform (n: 48, min: 0.000000, max: 1000000.000000)
#> Providing inflow events ... ok. (0.00 secs)
#> Providing inflow paras ... ok. (0.00 secs)
plot_inflow(scenario_with_inflow)A violin plot combines the features of a boxplot and a kernel density plot to visualize the distribution of simulated values.
Because the y-axis is displayed on a log₁₀ scale, equal vertical distances correspond to multiplicative (rather than additive) differences in concentration. This scaling is particularly useful for microbial concentrations, which often span several orders of magnitude.
When interpreting the figure, wider violins indicate a higher probability of observing concentrations within a given range, while taller violins indicate a broader overall variability in simulated inflow concentrations.
Volume of exposure
The plot_volumes() function generates boxplots of the
exposure volumes simulated for each combination of exposed population
and exposure pathway. The plots are faceted by crop, making it possible
to compare exposure volumes across crops, populations, and transmission
pathways.
scenario_volume <-
scenario_with_inflow |>
mutate(
volume = map(
.x = config,
.f = ~ simulate_exposure(config = .x)
)
)
#> Simulated exposure: volume per event
#> Distribution set from 'triangle' to 'uniform' because 'min' equals 'max'
#> Create 1000 random distribution(s): uniform (n: 60, min: 0.001000, max: 0.001000)
#> Simulated exposure: volume per event
#> Distribution set from 'triangle' to 'uniform' because 'min' equals 'max'
#> Create 1000 random distribution(s): uniform (n: 48, min: 0.001000, max: 0.001000)
plot_volumes(scenario_volume)
Each boxplot summarizes the distribution of simulated exposure
volumes:
Comparing boxplots allows users to assess differences in the typical exposure volume, the variability of simulated events, and the presence of extreme values among populations, crops, and exposure pathways.
Probability of infection
The plot_infection_probability() function generates
boxplots of the simulated annual probability of infection for each
pathogen. Separate plots are produced for each pathogen, allowing
comparisons of infection probabilities across exposed populations and
crops.
scenario_dose_ini <- initial_dose_calculation(scenario_volume)
scenario_scheme <- update_treatment_scheme(scenario_dose_ini)
scenario_with_logreduc_and_co <- scenario_scheme |>
mutate( log_reduction = map(config, simulate_treatment))
#> Create 1000 random distribution(s): uniform (n: 60, min: 1.000000, max: 2.000000)
#> Create 1000 random distribution(s): uniform (n: 60, min: 1.000000, max: 2.000000)
#> Create 1000 random distribution(s): uniform (n: 60, min: 1.000000, max: 3.000000)
#> Create 1000 random distribution(s): uniform (n: 60, min: 1.000000, max: 2.000000)
#> Create 1000 random distribution(s): uniform (n: 60, min: 5.000000, max: 7.000000)
#> Create 1000 random distribution(s): uniform (n: 60, min: 2.000000, max: 4.000000)
#> Simulated treatment: Q.1 - Activated Sludge for Bacteria
#> Simulated treatment: Q.1 - Activated Sludge for Viruses
#> Simulated treatment: Q.2 - Maturation Pond for Bacteria
#> Simulated treatment: Q.2 - Maturation Pond for Viruses
#> Simulated treatment: Q.6 - Chlorination for Bacteria
#> Simulated treatment: Q.6 - Chlorination for Viruses
#> Simulated treatment: Q.1 - Activated Sludge for Bacteria
#> Simulated treatment: Q.1 - Activated Sludge for Viruses
#> Simulated treatment: Q.2 - Maturation Pond for Bacteria
#> Simulated treatment: Q.2 - Maturation Pond for Viruses
#> Simulated treatment: Q.6 - Chlorination for Bacteria
#> Simulated treatment: Q.6 - Chlorination for Viruses
#> Create 1000 random distribution(s): uniform (n: 48, min: 1.000000, max: 2.000000)
#> Create 1000 random distribution(s): uniform (n: 48, min: 1.000000, max: 2.000000)
#> Create 1000 random distribution(s): uniform (n: 48, min: 1.000000, max: 3.000000)
#> Create 1000 random distribution(s): uniform (n: 48, min: 1.000000, max: 2.000000)
#> Create 1000 random distribution(s): uniform (n: 48, min: 5.000000, max: 7.000000)
#> Create 1000 random distribution(s): uniform (n: 48, min: 2.000000, max: 4.000000)
#> Simulated treatment: Q.1 - Activated Sludge for Bacteria
#> Simulated treatment: Q.1 - Activated Sludge for Viruses
#> Simulated treatment: Q.2 - Maturation Pond for Bacteria
#> Simulated treatment: Q.2 - Maturation Pond for Viruses
#> Simulated treatment: Q.6 - Chlorination for Bacteria
#> Simulated treatment: Q.6 - Chlorination for Viruses
#> Simulated treatment: Q.1 - Activated Sludge for Bacteria
#> Simulated treatment: Q.1 - Activated Sludge for Viruses
#> Simulated treatment: Q.2 - Maturation Pond for Bacteria
#> Simulated treatment: Q.2 - Maturation Pond for Viruses
#> Simulated treatment: Q.6 - Chlorination for Bacteria
#> Simulated treatment: Q.6 - Chlorination for Viruses
scenario_final_dose_and_co_test <- final_dose_calculation(scenario_with_logreduc_and_co)
scenario_inf_proba_and_co <- infection_probability_calculation(scenario_final_dose_and_co_test)
scenario_illness_proba_and_co <- illness_probability_calculation(scenario_inf_proba_and_co)
scenario_dalys_and_co <- dalys_calculation(scenario_illness_proba_and_co)
scenario_risk_total_and_co <-get_risk_total(scenario_dalys_and_co)
plot_infection_probability(scenario_risk_total_and_co)
#> $`Campylobacter jejuni`#>
#> $Norovirus
Each boxplot summarizes the distribution of simulated annual infection probabilities. Comparing boxplots allows users to identify differences in both the magnitude and the variability of annual infection probabilities among exposed populations and crops for each pathogen simulated.
You now have the mental map. From here, pick the thread you need –
open any of these articles with vignette(), or browse them
on the package website:
vignette("b-treatment-vs-multibarrier", package = "ambre")
– treatment plant only versus adding on-field barriers, side by
side.vignette("c-input-file", package = "ambre") – how to
write your own Excel scenario, and the allowed crops, populations, paths
and barriers.vignette("d-interpreting-risk", package = "ambre") –
reading results against the WHO 1e-6 DALY target and the EU 2020/741
framing.vignette("g-monte-carlo-engine", package = "ambre") –
why every result is a range, and how the repeat x event simulation
works.vignette("e-economic-analysis", package = "ambre") –
putting a cost on a reuse scenario alongside its risk.vignette("h-config-ambre", package = "ambre") – a tour
of the bundled config_ambre database that powers every
calculation.vignette("f-what-if-exposure", package = "ambre") –
calibrating exposure volume and frequency to test “what if”
questions.