From 2717a170cf824ea3dc1221bf9b5e0e174f6da21f Mon Sep 17 00:00:00 2001 From: Julian Gonzalez Date: Thu, 4 Jun 2026 11:23:59 -0600 Subject: [PATCH] Finished DLS-114 RMD file using rfaR This is a comprehensive step through process that goes through developing the stage frequency curves by using the Example Dam data from the DLS 114 class as well as displaying how rfaR computes everything through rfa_simulate. This activity shows the R use case for a hydrologic engineer who desires R plots to visualize hydrograph builds, stage frequency curves, and volume frequency curves with a knack for R programming. What isn't shown in this markdown file is the ability to use R packages to do statistical checks of the RFA process and utilize what is out there, namely fields packages or geospatial packages to add more context to our RFA models. Furthermore, it shows how intelligent this R implementation and how RMC is the best in the biz. --- rfaR_Testing_DLS114.Rmd | 812 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 812 insertions(+) create mode 100644 rfaR_Testing_DLS114.Rmd diff --git a/rfaR_Testing_DLS114.Rmd b/rfaR_Testing_DLS114.Rmd new file mode 100644 index 0000000..7af317b --- /dev/null +++ b/rfaR_Testing_DLS114.Rmd @@ -0,0 +1,812 @@ +--- +title: "rfaR DLS-114 RFA Exercise Tutorial" +output: + html_notebook: + toc: true + toc_depth: 2 +--- + +```{r setup, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.width = 8, + fig.height = 5, + warning = FALSE, + message = FALSE +) + +set.seed(20260603) +``` + +```{r packages} +library(tidyverse) +library(lubridate) +library(scales) + +# Prefer the local package source while developing this notebook. This avoids +# accidentally using an older installed rfaR where function arguments differ. +if (requireNamespace("devtools", quietly = TRUE) && file.exists("DESCRIPTION")) { + devtools::load_all(".") +} else { + library(rfaR) +} + +theme_set(theme_bw()) +``` + +```{r helpers} +sample_flow_frequency <- function(bestfit_params, + dist = "LP3", + expected_only = TRUE, + Nbin = NULL, + Mevent = NULL) { + sampler_args <- names(formals(flow_frequency_sampler)) + call_args <- list() + + if ("bestfit_params" %in% sampler_args) { + call_args$bestfit_params <- bestfit_params + } else { + call_args[[1]] <- bestfit_params + } + + if ("dist" %in% sampler_args) call_args$dist <- dist + if ("ExpectedOnly" %in% sampler_args) call_args$ExpectedOnly <- expected_only + if ("Nbin" %in% sampler_args && !is.null(Nbin)) call_args$Nbin <- Nbin + if ("Mevent" %in% sampler_args && !is.null(Mevent)) call_args$Mevent <- Mevent + + do.call(flow_frequency_sampler, call_args) +} +``` + +# Purpose + +This notebook translates the DLS-114 RMC-RFA exercises into a reproducible +`rfaR` workflow. The original exercises are organized around four major RMC-RFA +software tasks: + +```{r exercise-crosswalk} +tibble::tribble( + ~exercise, ~rfa_process, ~rfaR_equivalent, + "E2.3", "Enter input data: discharge gage, inflow hydrographs, stage gage, volume-frequency curve", "Inspect bundled data and prepare hydrographs / VFC parameters", + "E2.8", "Compute analyses: flood seasonality, reservoir starting stage duration, empirical frequency curve", "Sample flood months, sample starting stages, compare empirical stages", + "E2.16", "Build reservoir models and run expected-only simulations", "Route hydrographs with Modified Puls and compare stage-frequency curves", + "E2.24", "Run sensitivity analyses and full uncertainty simulation", "Compare model, duration, ERL, seasonality, starting-stage, and uncertainty choices" +) +``` + +The example data in this package use John Martin Dam (JMD), while the DLS-114 +exercise files use "Example Dam." The process is the same: build input data, +compute supporting analyses, route scaled hydrographs, and interpret the +stage-frequency result. + +# Example Dam Exercise Files + +The DLS-114 exercise files also contain completed RMC-RFA project databases. +Those `.rfa.sqlite` files store the same objects shown in the RMC-RFA interface: +input data, analyses, reservoir models, simulations, and stage-frequency +results. + +To make this notebook easy to run without sqlite packages, selected Example Dam +objects have been extracted to CSV files under `inst/extdata/example_dam`. + +```{r example-dam-paths} +example_dam_dir <- file.path("inst", "extdata", "example_dam") +can_read_example_dam <- dir.exists(example_dam_dir) + +example_dam_files <- tibble( + file = list.files(example_dam_dir, pattern = "[.]csv$", full.names = FALSE) +) + +example_dam_files +``` + +## Example Dam Project Inventory + +This inventory mirrors the four DLS-114 exercises: + +- E2.3 input data live in the `2.*` tables. +- E2.8 analyses live in the `3.*` tables. +- E2.16 reservoir models live in the `4.*` tables. +- E2.16 and E2.24 simulations/results live in the `5.*` tables. + +```{r example-dam-inventory} +if (can_read_example_dam) { + example_input_inventory <- read_csv( + file.path(example_dam_dir, "input_inventory.csv"), + show_col_types = FALSE + ) + + example_analysis_inventory <- read_csv( + file.path(example_dam_dir, "analysis_inventory.csv"), + show_col_types = FALSE + ) + + example_reservoir_inventory <- read_csv( + file.path(example_dam_dir, "reservoir_inventory.csv"), + show_col_types = FALSE + ) + + example_simulation_inventory <- read_csv( + file.path(example_dam_dir, "simulation_inventory.csv"), + show_col_types = FALSE + ) + + list( + input_data = example_input_inventory, + analyses = example_analysis_inventory, + reservoir_models = example_reservoir_inventory, + simulations = example_simulation_inventory + ) +} +``` + +## Example Dam rfaR-Style Objects + +The completed sqlite project can be used to reconstruct the objects that a +native `rfaR` workflow expects. + +```{r example-dam-objects} +if (can_read_example_dam) { + example_por_inflow <- read_csv( + file.path(example_dam_dir, "por_inflow.csv"), + show_col_types = FALSE + ) |> + transmute( + timestep = Ordinate, + date = Data_Date, + time = Data_Time, + flow_cfs = Value + ) + + example_stage <- read_csv( + file.path(example_dam_dir, "stage_gage.csv"), + show_col_types = FALSE + ) |> + transmute( + timestep = Ordinate, + date = Data_Date, + time = Data_Time, + stage_ft = Value + ) + + example_vfc_parameters <- read_csv( + file.path(example_dam_dir, "vfc_parameters.csv"), + show_col_types = FALSE + ) |> + transmute( + mean_log = Mean, + sd_log = StDev, + skew_log = Skew, + erl = EYR, + duration = Duration + ) + + example_resmodel_full_capacity <- read_csv( + file.path(example_dam_dir, "resmodel_full_capacity.csv"), + show_col_types = FALSE + ) |> + transmute( + elev_ft = Stage, + stor_acft = Storage, + outflow_cfs = Discharge + ) + + example_resmodel_no_outlet_works <- read_csv( + file.path(example_dam_dir, "resmodel_no_outlet_works.csv"), + show_col_types = FALSE + ) |> + transmute( + elev_ft = Stage, + stor_acft = Storage, + outflow_cfs = Discharge + ) + + list( + inflow = head(example_por_inflow), + stage = head(example_stage), + vfc_parameters = example_vfc_parameters, + full_capacity_reservoir_model = head(example_resmodel_full_capacity), + no_outlet_works_reservoir_model = head(example_resmodel_no_outlet_works) + ) +} +``` + +## Example Dam Hydrograph Setup + +The 4-day hydrograph shapes from the RMC-RFA project can be passed through +`hydrograph_setup()` after renaming the sqlite fields to the format expected by +the helper. + +```{r example-dam-hydrographs} +if (can_read_example_dam) { + example_hydro_apr2008 <- read_csv( + file.path(example_dam_dir, "hydro_apr2008.csv"), + col_types = cols(.default = col_character()), + show_col_types = FALSE + ) |> + as.data.frame() + + example_hydro_apr2017 <- read_csv( + file.path(example_dam_dir, "hydro_apr2017.csv"), + col_types = cols(.default = col_character()), + show_col_types = FALSE + ) |> + as.data.frame() + + example_hydro_dec2015 <- read_csv( + file.path(example_dam_dir, "hydro_dec2015.csv"), + col_types = cols(.default = col_character()), + show_col_types = FALSE + ) |> + as.data.frame() + + example_hydrographs <- hydrograph_setup( + example_hydro_apr2008, + example_hydro_apr2017, + example_hydro_dec2015, + critical_duration = 4, + routing_days = 6 + ) + + tibble( + hydrograph_id = seq_along(example_hydrographs), + rows = map_int(example_hydrographs, nrow), + observed_critical_volume = map_dbl(example_hydrographs, ~ attr(.x, "obs_vol")) + ) +} +``` + +## Example Dam RFA Results + +The completed project stores stage-frequency results from the RMC-RFA software. +These curves are useful for checking that the R workflow is representing the +same exercise process. + +```{r example-dam-stage-frequency} +if (can_read_example_dam) { + example_full_capacity_sf <- read_csv( + file.path(example_dam_dir, "stage_frequency_full_capacity.csv"), + show_col_types = FALSE + ) |> + mutate(simulation = "Full Capacity") + + example_no_outlet_sf <- read_csv( + file.path(example_dam_dir, "stage_frequency_no_outlet_works.csv"), + show_col_types = FALSE + ) |> + mutate(simulation = "No Outlet Works") + + example_stage_frequency <- bind_rows( + example_full_capacity_sf, + example_no_outlet_sf + ) |> + mutate(Z_var = qnorm(1 - Probability)) + + ggplot(example_stage_frequency, aes(x = Z_var, y = Expected, color = simulation)) + + geom_line(linewidth = 0.9) + + scale_x_continuous( + breaks = qnorm(1 - c(9.9e-1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6)), + labels = c(9.9e-1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6) + ) + + scale_y_continuous(labels = comma) + + labs( + title = "Example Dam RMC-RFA Expected Stage-Frequency Curves", + x = "AEP", + y = "Stage (ft)", + color = "Simulation" + ) +} +``` + +# E2.3: RFA Input Data + +Exercise 2.3 focuses on entering the four core RMC-RFA input objects: + +- Systematic inflow record. +- Inflow hydrograph shapes. +- Stage gage record. +- Volume-frequency curve from RMC-BestFit. + +In `rfaR`, these same concepts are represented by package datasets. + +```{r inspect-input-data} +input_inventory <- tibble::tribble( + ~rfa_object, ~jmd_dataset, ~role, + "Discharge Gage", "jmd_por_inflow", "Period-of-record inflow data", + "Inflow Hydrographs", "jmd_hydro_*", "Candidate flood hydrograph shapes", + "Stage Gage", "jmd_wy1980_stage", "Historical reservoir starting stages", + "Volume Frequency Curve", "jmd_bf_parameter_sets / jmd_vfc", "BestFit LP3 parameters and tabular VFC", + "Reservoir Model", "jmd_resmodel", "Stage-storage-discharge relationship" +) + +input_inventory +``` + +```{r preview-inputs} +head(jmd_por_inflow) +head(jmd_wy1980_stage) +head(jmd_bf_parameter_sets) +jmd_seasonality +head(jmd_resmodel) +``` + +## Discharge Gage + +The discharge gage is the period-of-record inflow series. In RMC-RFA, it is +entered as a dated time series. In R, first convert the date and time columns +into a real datetime field. + +```{r discharge-gage} +jmd_inflow_record <- jmd_por_inflow |> + mutate( + datetime = mdy_hm(paste(date, time)), + flow_cfs = as.numeric(flow_cfs) + ) + +ggplot(jmd_inflow_record, aes(x = datetime, y = flow_cfs)) + + geom_line(linewidth = 0.3, color = "#3B4992FF") + + scale_y_continuous(labels = comma) + + labs( + title = "JMD Period-of-Record Inflow", + x = "Date", + y = "Flow (cfs)" + ) +``` + +## Inflow Hydrographs + +Exercise 2.3 asks users to enter several flood hydrograph shapes. `rfaR` uses +`hydrograph_setup()` to standardize copied RMC-RFA-style hydrographs and attach +the observed critical-duration volume used for later scaling. + +```{r hydrograph-setup} +critical_duration_days <- 2 +routing_duration_days <- 10 + +jmd_hydrographs <- hydrograph_setup( + jmd_hydro_apr1999, + jmd_hydro_jun1921, + jmd_hydro_jun1965, + jmd_hydro_may1955, + jmd_hydro_pmf, + jmd_hydro_sdf, + critical_duration = critical_duration_days, + routing_days = routing_duration_days +) + +tibble( + hydrograph_id = seq_along(jmd_hydrographs), + rows = map_int(jmd_hydrographs, nrow), + observed_critical_volume = map_dbl(jmd_hydrographs, ~ attr(.x, "obs_vol")) +) +``` + +```{r plot-hydrograph-shapes} +map2_dfr(jmd_hydrographs, seq_along(jmd_hydrographs), function(hydro, id) { + hydro |> + transmute( + hydrograph_id = factor(id), + hour, + inflow + ) +}) |> + ggplot(aes(x = hour, y = inflow, color = hydrograph_id)) + + geom_line(linewidth = 0.7) + + scale_y_continuous(labels = comma) + + labs( + title = "Candidate Hydrograph Shapes", + x = "Hour", + y = "Inflow (cfs)", + color = "Hydrograph" + ) +``` + +## Stage Gage + +The stage gage provides the historical reservoir stages used to sample +antecedent starting pool conditions. + +```{r stage-gage} +jmd_stage_record <- jmd_wy1980_stage |> + mutate( + stage_date = as.Date(date), + stage_date = if_else( + is.na(stage_date), + as.Date(mdy(as.character(date))), + stage_date + ), + month = month(stage_date) + ) |> + filter(!is.na(month), !is.na(stage_ft)) + +ggplot(jmd_stage_record, aes(x = stage_date, y = stage_ft)) + + geom_line(linewidth = 0.3, color = "#008280FF") + + scale_y_continuous(labels = comma) + + labs( + title = "JMD Stage Gage", + x = "Date", + y = "Stage (ft-NAVD88)" + ) +``` + +## Volume-Frequency Curve + +The DLS-114 exercise uses BestFit LP3 parameters and asks users to compute / +compare RMC-RFA volume-frequency results. In `rfaR`, the LP3 parameter sets feed +the volume-frequency sampler. + +```{r vfc-parameters} +jmd_bf_parameter_sets |> + pivot_longer(everything(), names_to = "parameter", values_to = "value") |> + ggplot(aes(x = value)) + + geom_density(fill = "gray80", color = "gray25") + + facet_wrap(vars(parameter), scales = "free") + + labs( + title = "BestFit LP3 Parameter Sets", + x = "Parameter value", + y = "Density" + ) +``` + +```{r vfc-sample} +q_samp <- sample_flow_frequency( + bestfit_params = jmd_bf_parameter_sets, + dist = "LP3", + expected_only = TRUE +) + +q_samp_df <- tibble(sampled_volume = q_samp$flow[, 1]) + +ggplot(q_samp_df, aes(x = sampled_volume)) + + geom_histogram(bins = 80, fill = "lightblue2", color = "gray25") + + scale_x_log10(labels = comma) + + labs( + title = "Expected-Only Stratified Volume Sample", + x = "Sampled inflow volume", + y = "Count" + ) +``` + +# E2.8: RFA Analyses + +Exercise 2.8 computes the analyses that support simulation: + +- Flood seasonality. +- Reservoir starting stage duration. +- Empirical frequency curve. +- Optional alternate seasonality based on stage information. + +## Flood Seasonality + +Flood seasonality controls the probability that a simulated flood occurs in each +month. + +```{r flood-seasonality} +seasonality_df <- jmd_seasonality |> + mutate(month_abbr = factor(month.abb[month], levels = month.abb)) + +ggplot(seasonality_df, aes(x = month_abbr, y = relative_frequency)) + + geom_col(fill = "#3B4992FF", color = "gray25") + + scale_y_continuous(labels = percent) + + labs( + title = "Flood Seasonality", + x = "Month", + y = "Relative frequency" + ) +``` + +```{r sample-flood-months} +n_tutorial_samples <- 10000 + +sampled_months <- sample( + 1:12, + size = n_tutorial_samples, + replace = TRUE, + prob = jmd_seasonality$relative_frequency +) + +tibble(sampled_month = sampled_months) |> + count(sampled_month) |> + mutate( + month_abbr = factor(month.abb[sampled_month], levels = month.abb), + sampled_relative_frequency = n / sum(n) + ) |> + ggplot(aes(x = month_abbr, y = sampled_relative_frequency)) + + geom_col(fill = "#008B45FF", color = "gray25") + + scale_y_continuous(labels = percent) + + labs( + title = "Sampled Flood Months", + x = "Month", + y = "Sampled relative frequency" + ) +``` + +## Reservoir Starting Stage Duration + +Reservoir starting stage duration curves are used with the sampled flood month +to sample an antecedent pool stage. + +```{r starting-stage-sampling} +sampled_stages <- map_dbl(sampled_months, function(sample_month) { + month_stages <- jmd_stage_record$stage_ft[jmd_stage_record$month == sample_month] + + if (length(month_stages) == 0) { + return(NA_real_) + } + + sample( + month_stages, + size = 1, + replace = TRUE + ) +}) + +stage_samples <- tibble( + sampled_month = sampled_months, + month_abbr = factor(month.abb[sampled_months], levels = month.abb), + sampled_stage_ft = sampled_stages +) + +stage_samples |> + group_by(month_abbr) |> + summarize( + n = n(), + q25 = quantile(sampled_stage_ft, 0.25, na.rm = TRUE), + median = median(sampled_stage_ft, na.rm = TRUE), + q75 = quantile(sampled_stage_ft, 0.75, na.rm = TRUE), + .groups = "drop" + ) +``` + +```{r plot-starting-stage-samples} +ggplot(stage_samples, aes(x = sampled_stage_ft, fill = month_abbr)) + + geom_histogram(binwidth = 5, color = "gray30") + + facet_wrap(vars(month_abbr), scales = "free_y") + + coord_cartesian(xlim = c(3780, 3870)) + + theme(legend.position = "none") + + labs( + title = "Sampled Starting Stage By Flood Month", + x = "Starting stage (ft-NAVD88)", + y = "Count" + ) +``` + +## Empirical Frequency Curve + +The empirical frequency curve is used as an observed-data check against the +simulated stage-frequency curve. + +```{r empirical-frequency} +jmd_empirical_plot <- jmd_empirical_stage_wy1980_pt |> + mutate(Z_var = qnorm(1 - plot_posit)) + +ggplot(jmd_empirical_plot, aes(x = Z_var, y = stage_ft)) + + geom_point(size = 1.8, alpha = 0.75, color = "#1B1919FF") + + scale_x_continuous(labels = label_number()) + + scale_y_continuous(labels = comma) + + labs( + title = "Empirical Stage-Frequency Points", + x = "Standard normal variate", + y = "Stage (ft-NAVD88)" + ) +``` + +# E2.16: Reservoir Model And Expected Simulation + +Exercise 2.16 moves from analyses to reservoir modeling and expected-only +simulation. In RMC-RFA, the user compares "Full Capacity Releases" and "No +Outlet Works" reservoir models. In `rfaR`, the core computational step is +Modified Puls routing through a stage-storage-discharge table. + +```{r reservoir-model} +head(jmd_resmodel) + +jmd_resmodel_plot <- as.data.frame(jmd_resmodel[, 1:3]) +names(jmd_resmodel_plot) <- c("elev_ft", "stor_acft", "outflow_cfs") + +ggplot(jmd_resmodel_plot, aes(x = elev_ft)) + + geom_line(aes(y = outflow_cfs, color = "Outflow (cfs)"), linewidth = 0.8) + + scale_y_continuous(labels = comma) + + labs( + title = "Reservoir Rating Curve", + x = "Stage (ft-NAVD88)", + y = "Outflow (cfs)", + color = NULL + ) +``` + +## Route One Event + +This is the smallest end-to-end event simulation: choose a volume, scale a +hydrograph, select a starting stage, and route. + +```{r scale-and-route-one-event} +example_hydrograph <- jmd_hydrographs[[1]] +example_observed_volume <- attr(example_hydrograph, "obs_vol") +example_sampled_volume <- median(q_samp_df$sampled_volume) +example_starting_stage <- median(stage_samples$sampled_stage_ft) + +scaled_hydrograph <- scale_hydrograph( + hydrograph_shape = example_hydrograph[, c("hour", "inflow")], + observed_volume = example_observed_volume, + sampled_volume = example_sampled_volume +) + +scaled_routing <- mod_puls_routing( + resmodel_df = jmd_resmodel, + inflow_df = scaled_hydrograph, + initial_elev = example_starting_stage, + full_results = TRUE +) + +scaled_routing |> + summarize( + peak_stage_ft = max(elevation_ft), + peak_outflow_cfs = max(outflow_cfs) + ) +``` + +```{r plot-scaled-routing} +scaled_routing |> + pivot_longer(c(inflow_cfs, outflow_cfs), names_to = "series", values_to = "flow_cfs") |> + ggplot(aes(x = time_hr, y = flow_cfs, color = series)) + + geom_line(linewidth = 0.8) + + scale_y_continuous(labels = comma) + + labs( + title = "Scaled Hydrograph Routing", + x = "Time (hr)", + y = "Flow (cfs)", + color = NULL + ) +``` + +## Expected Stage-Frequency Curve + +The full expected simulation can be slow. For a teaching notebook, use the +packaged expected-only result to focus on plotting and interpretation. + +```{r expected-stage-frequency-plot} +aep_breaks <- c( + 9.9e-1, 9e-1, 5e-1, 1e-1, 1e-2, 1e-3, + 1e-4, 1e-5, 1e-6, 1e-7, 1e-8 +) + +minor_aep_breaks <- unlist(lapply(2:9, function(i) i * 10^-(1:8))) + +jmd_rfa_plot <- jmd_rfa_expected |> + mutate(Z_var = qnorm(1 - AEP)) + +critical_elevs <- tibble( + name = c("Upper PMF", "Top of Dam", "Flood Control Pool"), + elev_ft = c(3893.8, 3881.8, 3871.8), + label = paste(name, "=", elev_ft) +) + +ggplot() + + geom_line( + data = jmd_rfa_plot, + aes(x = Z_var, y = Expected, color = "Expected RFA curve"), + linewidth = 0.9 + ) + + geom_point( + data = jmd_empirical_plot, + aes(x = Z_var, y = stage_ft, shape = "Observed stages"), + size = 1.6, + alpha = 0.7 + ) + + geom_hline(data = critical_elevs, aes(yintercept = elev_ft), linewidth = 0.4) + + geom_text( + data = critical_elevs, + aes(x = qnorm(1 - 0.99), y = elev_ft, label = label), + size = 2.8, + hjust = 0, + vjust = -0.5 + ) + + scale_color_manual(values = c("Expected RFA curve" = "#3B4992FF")) + + scale_shape_manual(values = c("Observed stages" = 16)) + + scale_x_continuous( + breaks = qnorm(1 - aep_breaks), + minor_breaks = qnorm(1 - minor_aep_breaks), + labels = aep_breaks + ) + + scale_y_continuous( + breaks = seq(3700, 3910, 10), + minor_breaks = seq(3700, 3910, 5), + labels = comma + ) + + coord_cartesian( + xlim = c(qnorm(1 - 0.99), qnorm(1 - 1e-8)), + ylim = c(3800, 3900) + ) + + labs( + title = "JMD Expected-Only Stage-Frequency Curve", + x = "AEP", + y = "Stage (ft-NAVD88)", + color = NULL, + shape = NULL + ) + + theme( + legend.position = "bottom", + axis.text.x = element_text(angle = 30, hjust = 1) + ) +``` + +# E2.24: Sensitivity And Full Uncertainty + +Exercise 2.24 asks users to evaluate how much the final stage-frequency curve +changes when important modeling decisions change. + +```{r sensitivity-crosswalk} +tibble::tribble( + ~sensitivity, ~rfa_question, ~rfaR_way_to_test, + "Reservoir model", "Full capacity versus no outlet works", "Route the same scaled hydrographs through alternate stage-storage-discharge tables", + "Critical inflow duration", "4-day versus 5-day setup", "Change hydrograph set, critical duration, routing duration, and VFC duration", + "Effective record length", "ERL 80 versus 150 versus 500", "Change BestFit parameter sets / VFC uncertainty inputs before sampling", + "Flood seasonality", "Flow-threshold seasonality versus stage-informed seasonality", "Change monthly sampling probabilities", + "Starting stage duration", "Alternate antecedent pool sampling assumptions", "Change stage record or monthly duration curves used for sampling", + "Full uncertainty", "Expected, median, and 90 percent interval", "Run `rfaR(..., expected_only = FALSE)` when runtime is acceptable" +) +``` + +## Simple Sensitivity Pattern + +The reusable pattern is: + +1. Change one input assumption. +2. Re-run the same simulation workflow. +3. Compare the stage-frequency curve at decision elevations such as top of dam. + +The following toy sensitivity changes only the starting stage used for one +routed event. It is not a replacement for a full RFA sensitivity run, but it +shows the mechanics. + +```{r starting-stage-sensitivity} +starting_stage_sensitivity <- quantile( + stage_samples$sampled_stage_ft, + probs = c(0.05, 0.50, 0.95) +) + +map_dfr(names(starting_stage_sensitivity), function(label) { + route <- mod_puls_routing( + resmodel_df = jmd_resmodel, + inflow_df = scaled_hydrograph, + initial_elev = unname(starting_stage_sensitivity[label]), + full_results = TRUE + ) + + route |> + summarize( + starting_stage_case = label, + initial_elev = unname(starting_stage_sensitivity[label]), + peak_stage_ft = max(elevation_ft), + peak_outflow_cfs = max(outflow_cfs) + ) +}) +``` + +## Optional Full Simulation + +The package-level full simulation is intentionally left unevaluated here because +it can take a long time. Run it when you are ready to test runtime and outputs. +This is through the Quick Start tab in the README on GitHub but be wary on the +Full uncertainty because the computation time takes a while depending on the Nbins +and events_per_bin hyperparameter choices. + + +You can plot `jmd_expected$stage_frequency`, `jmd_median$stage_frequency`, or +`jmd_full_uncertainty$stage_frequency` using the same AEP plotting setup shown +in the E2.16 section. + +# Takeaways + +The DLS-114 exercises are best represented in R Markdown as a process map: + +1. E2.3 builds the model inputs. +2. E2.8 computes seasonality, starting stage, and empirical checks. +3. E2.16 routes through the reservoir model and creates an expected + stage-frequency curve. +4. E2.24 varies key assumptions to understand sensitivity and uncertainty. + +Keep tutorial chunks small, set seeds, avoid hard-coded output paths, and use +stored package results for expensive full-run comparisons.