--- title: "Get Started with the OptirrigCORE package" output: rmarkdown::html_vignette: css: styles/vignette.css vignette: > %\VignetteIndexEntry{Get Started with the OptirrigCORE package} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE, file = 'styles/setup.R'} rm(list = ls()) gc() ``` ## Introduction ### The Optirrig model in a nutshell Optirrig is a one-dimensional conceptual model that ties together thermal-time crop development, soil–plant water balance, and management rules to reproduce irrigated systems. It tracks plant status (LAI, biomass, yield), soil water reserves (RU), and nitrogen demand while applying irrigation rules that can be user-defined or phenology-driven. ### What is the OptirrigCORE package? OptirrigCORE is the R interface that wraps the Optirrig engine and makes the workflow reproducible: - Data prep: import or generate crop, soil, climate, irrigation, and nitrogen descriptions. - Configuration: build consistent parameter tables and configuration files. - Execution: run single scenarios or big batches from one command. - Analysis: output objects plug straight into ggplot2 and tidy pipelines. - Reproducibility: YAML + CSV inputs keep everything versionable. Use OptirrigCORE for research, teaching exercises, rapid prototyping of decision rules, or operational campaign planning. The default assets get you started fast, and every component can be swapped for custom data whenever you need it. ## Let’s Get Started! This vignette walks you through a minimal OptirrigCORE workflow. You will learn how to: 1. Install OptirrigCORE (and `remotes` if missing). 2. Import climate and optional irrigation data. 3. Build a parameter object that describes your configuration(s). 4. Call `run_model()` and capture the outputs. 5. Plot LAI, biomass, yield, soil water, and irrigation. ### Prerequisites - R >= 4.1 plus `remotes`. - Write access to a directory that will store configs, inputs, and outputs. - (Optional) A clone of the repository if you plan to edit templates locally. ## Step 1 : Install the OptirrigCORE Package To install OptirrigCORE from the INRAE GitLab repository: ```{r 00-pkg_install, eval=FALSE} install.packages("remotes") remotes::install_git("https://forge.inrae.fr/OptirrigHIVE/OptirrigCORE.git", build_vignettes = TRUE, dependencies = TRUE) ``` Once installed, load the package: ```{r 00-load_pkg} library(OptirrigCORE) ``` ## Step 2 : Load Climate & Irrigation data OptirrigCORE requires daily weather data (rainfall, temperature, radiation, and reference evapotranspiration) to simulate crop growth and soil water balance. In this vignette, we shall use example datasets shipped with the package, representing a maize experiment conducted in 2021 at the Lavalette experimental site (Montpellier, France). Using data() avoids file paths and makes the example fully reproducible. ```{r 00-climate_data} data("MAIZE_21LAVALETTE_clim") str(MAIZE_21LAVALETTE_clim) ``` The climate dataset follows the standard Optirrig input format, with the columns below. In practice the model expects a daily time step and a date column that fully covers your simulation period. | Column Name | Description | |-------------|---------------------------------| | `Date` | Date in "dd/mm/yyyy" format | | `P` | Daily rainfall (mm) | | `T` | Daily temperature (°C) | | `Rg` | Daily global solar radiation (J/cm²) | | `etp` | Daily reference evapotranspiration (mm) | As the model is a thermal-time driven, the `Date` column is essential to assure that the climate data aligns with the simulation period. In fact simulations period need to be fully included in the climate data. Internally, OptirrigCORE derives \code{PAR} as \code{0.5 * Rg}. Both \code{Rg} and \code{PAR} are handled in \eqn{J\cdot cm^{-2}\cdot day^{-1}}, while \code{IR} is a dimensionless intercepted fraction and biomass outputs (\code{B}, \code{Bp}) are expressed in \eqn{t\cdot ha^{-1}}. If your `Date` column is stored as text, it’s fine: OptirrigCORE will parse common formats (including `"dd/mm/yyyy"`). Still, it’s a good habit to verify it once: As an optional step, you can also provide an irrigation input. The model can simulate irrigation using either simple decision rules (e.g., water-stress thresholds, water-turns, quotas, etc ...) or a predefined calendar. In this ex post example, we use the observed irrigation calendar from the 2021 experiment. ```{r 00-irrigation_data} data("MAIZE_21LAVALETTE_irrig") str(MAIZE_21LAVALETTE_irrig) ``` ## Step 3 — Describe the simulation configuration Now that climate (and optionally irrigation) data are loaded, the next step is to describe *what* you want to simulate: crop, soil, dates, and a few key options. OptirrigCORE accepts several input styles (CSV files, `data.frame`s, or lists). For a single scenario, the simplest and most explicit approach is to build a flat named list directly in R. You can provide climate/irrigation either as in-memory tables (as we do here) or as paths to files. In this vignette we’ll keep it minimal: - one crop (`"maize"`) and one soil profile (`"Lavalette"` in this example); - a start/end window that is fully included in the climate data; - an observed irrigation calendar. ### Which crops and soils are available? OptirrigCORE ships with a set of pre-configured crops and soils that can be used directly, without any additional setup. When you specify a crop name (`crop`) or a soil code/profile (`soil`) in your input object, OptirrigCORE automatically loads the corresponding parameter set behind the scenes. 👉 You do not need to worry about the underlying parameterization: the name simply acts as a key pointing to a consistent, ready-to-use configuration. Importantly, these presets are not restrictive: even when using built-in crops or soils, you can override or add any parameter you want at simulation setup time to explore alternative assumptions or management options. **Available crops :** The table below lists the crops currently available in the installed version of the package. The value to use in the crop argument corresponds directly to the crop name shown. |cultures | Calibration Status | |:--------------| -------------------| | maize | need | | beetroot | done | | potato | need | | soybean | need | | wheat | need | For example, setting crop = "maize" automatically selects the parameter set describing maize phenology, growth, and water demand. **Available soils :** Similarly, OptirrigCORE includes several standard soil profiles. Each soil is identified by a short code that reflects its dominant texture. |sols | Description | |:-------------| ----------------| |C | Clay | |CL | Clay Loam | |L | Loam | |LSa | Loamy Sand | |Sa | Sand | |SaC | Sandy Clay | |SaCL | Sandy Clay Loam | |SaL | Sandy Loam | |SiC | Silty Clay | |SiCL | Silty Clay Loam | |SiL | Silty Loam | For instance, using soil = "CL" automatically selects a clay loam soil profile with its associated hydraulic properties. 💡 Tip These built-in crops and soils are ideal for getting started and exploring the model. Advanced users can later introduce custom parameterizations if needed. At minimum, a scenario need to include: | Parameter | Description | | ----------------- | ----------------------------------------------------------------------------- | | **run_id** | Unique scenario name | | **crop** | Crop identifier available in the internal library (e.g., `maize`, `beetroot`) | | **soil** | Soil identifier from the bundled database or a custom soil (e.g., `CL`, `SaC`)| | **date_start** | Simulation start date (string "dd/mm/yyyy") | | **date_end** | Simulation end date (string "dd/mm/yyyy") | | **date_sowing** | Sowing date start (string "dd/mm/yyyy") | | **date_harvest** | Harvest date end (string "dd/mm/yyyy") | | **zmax** | Maximum rooting depth (m) | | **ratio_R_init** | Initial relative soil water reserve (0–1) | | **climate** | Climate input (path or `data.frame`) | | **irrigation** | Optional irrigation input (path or `data.frame`) | | **irrig_mod** | 0 = rainfed/calendar, 1 = rule-driven irrigation | Therefore, several methods exist to prepare simulation scenarios and use them with `run_model()`. The function can accept either a path to a CSV file, a `data.frame`, or a `list`, provided that the objects already exist in the R environment and follow the expected input format. *path:* a CSV file where each row corresponds to a distinct simulation scenario. *data.frame:* each row of the data frame corresponds to a distinct simulation scenario. *list:* either a flat named list describing one scenario, or a named list of scenarios for batch runs. For a first run, a flat list is the most direct option, as shown below: ```{r 00-create_list} # Example: flat list (all parameters at the same level) input <- list( run_id = "Run_1", crop = "maize", soil = "CL", climate = MAIZE_21LAVALETTE_clim, irrigation = MAIZE_21LAVALETTE_irrig, fertilisation = NA, date_sowing = "20/04/2021", date_harvest = "06/09/2021", date_start = "01/04/2021", date_end = "06/09/2021", irrig_mod = 0, zmax = 1.2, ratio_R_init = 0.7, irrig_strategy_start = "25/04/2021", irrig_strategy_end = "01/08/2021" ) str(input) ``` For batch runs, you can also pass a named list of scenario objects or a parameter table with one row per simulation. If you’re unsure which parameters exist (or want to see defaults), these help pages are the quickest entry point: https://optirrighive.pages-forge.inrae.fr/OptirrigCORE/dev/articles/v00_params_overview.html For more details on `run_model()` and `plot()`, check the docs: ```{r 00-help_pages, eval = FALSE} ?run_model ?plot ``` ## Step 4 — Run the simulation `run_model()` can take a path to a parameter CSV, a `data.frame`, or a `list`. Here we pass the in-memory object created as a simple list (one scenario). The returned object is a named list with one element per scenario (`run_id`), each containing time series (states/fluxes) and summary variables that you can plot or post-process. ```{r 00-runModel} outputs <- run_model( input, options = list(log = FALSE, force = TRUE, return_outputs = TRUE, save = FALSE) ) str(outputs) ``` ✅ Tip: for batch runs, you can either add more rows to a parameter table or pass a named list of scenario objects in a single call. ## Step 5 — Visualize the outputs Simulation results are regular R objects, so any plotting stack works. The chunk below builds a simple `ggplot2` dashboard showing leaf area, biomass, yield, soil water reserve, and irrigation. ```{r 00-plotModel, fig.width=15, fig.height=10} library(ggplot2) library(patchwork) df <- as.data.frame(outputs[[1]]) df$Scenario <- names(outputs)[1] b_max <- max(df$Bp, na.rm = TRUE) y_max <- max(df$Yp, na.rm = TRUE) df$Biomass_rel <- if (b_max > 0) 100 * df$B / b_max else NA_real_ df$Biomass_pot_rel <- if (b_max > 0) 100 * df$Bp / b_max else NA_real_ df$Yield_rel <- if (y_max > 0) 100 * df$Y / y_max else NA_real_ df$Yield_pot_rel <- if (y_max > 0) 100 * df$Yp / y_max else NA_real_ df$RU_rel <- if ("RU_daily_perc" %in% names(df) && !all(is.na(df$RU_daily_perc))) { df$RU_daily_perc } else { df$RU } df$CumDose <- cumsum(pmax(df$I1, 0)) dose_scale <- if (max(df$CumDose, na.rm = TRUE) > 0 && max(df$I1, na.rm = TRUE) > 0) { max(df$I1, na.rm = TRUE) / max(df$CumDose, na.rm = TRUE) } else { 1 } base_theme <- theme_minimal(base_size = 11) + theme( legend.position = "top", panel.grid.minor = element_blank() ) p_lai <- ggplot(df, aes(Date)) + geom_line(aes(y = LAI, colour = "Observed"), linewidth = 0.8) + geom_line(aes(y = LAIp, colour = "Potential"), linewidth = 0.7, linetype = 2) + scale_colour_manual(values = c("Observed" = "#245b69", "Potential" = "#333333")) + labs(title = "Leaf Area Index", y = "LAI", x = NULL, colour = NULL) + base_theme p_biomass <- ggplot(df, aes(Date, Biomass_rel)) + geom_line(colour = "#245b69", linewidth = 0.8) + geom_line(aes(y = Biomass_pot_rel), colour = "#333333", linewidth = 0.7, linetype = 2) + labs(title = "Biomass (relative to max potential)", y = "% of max potential", x = NULL) + base_theme p_ru <- ggplot(df, aes(Date, RU_rel)) + geom_line(colour = "#111111", linewidth = 0.8) + labs(title = "Useful Water Reserve (%)", y = "RU (%)", x = NULL) + base_theme p_yield <- ggplot(df, aes(Date, Yield_rel)) + geom_line(colour = "#245b69", linewidth = 0.8) + geom_line(aes(y = Yield_pot_rel), colour = "#333333", linewidth = 0.7, linetype = 2) + labs(title = "Yield (relative to max potential)", y = "% of max potential", x = NULL) + base_theme p_irrig <- ggplot(df, aes(Date)) + geom_point(aes(y = I1), colour = "#245b69", size = 1.8, alpha = 0.8) + geom_line(aes(y = CumDose * dose_scale), colour = "#111111", linewidth = 0.8) + scale_y_continuous( name = "Irrigation (mm)", sec.axis = sec_axis(~ . / dose_scale, name = "Cumulative dose (mm)") ) + labs(title = "Irrigation & Cumulative Dose", x = "Date") + base_theme p_lai / ((p_biomass | p_ru) / (p_yield | p_irrig)) ``` ## Wrap-up With less than thirty lines of code you installed OptirrigCORE, described a scenario, ran the model, and visualized the main state variables. - OptirrigCORE keeps simulations reproducible thanks to formatted inputs. - Switching crops, soils, or irrigation strategies is as easy as editing a row. - Outputs are standard R objects that can be plug into ggplot2 and tidy workflows. Where to go next? 1. Add new scenario rows and try rule-driven irrigation (`irrig_mod = 1`). 2. Swap the soil for another profile from `inst/config.soil.*`. 3. Read the "Evaluation of Irrigation Strategies" vignette for advanced automation ideas.