These instructions describe how to build, run, and analyze an example water use scenario. The scenario describes the effects of allowing an existing parcel of irrigated land to be reclassified as “non-irrigated”; that is, what happens when you voluntarily allow an irrigated parcel to go idle. Model boundary conditions are modified in the archived calibrated model to best represent this scenario.

Startup an R session. Set the working directory to the local wrv-training repository, that is the “wrv-training” folder, by typing the following command in your R console and making sure to change the file path to the correct location:

setwd("C:/Users/jfisher/Repos/wrv-training")

Load the wrv, inlmisc, raster, rgdal, and leaflet packages into your current R environment, using

packages <- c("wrv", "inlmisc", "raster", "rgdal", "leaflet")
lapply(packages, library, character.only = TRUE)

Draw a map the idled land parcel (about 600 acres, or better yet 2.4-square kilometers) and the 2002 land status by pasting the following commands into your R console.

crs <- CRS("+init=epsg:4326")
irr <- spTransform(irr.lands[["2002"]], crs)
irr$Status <- factor(irr$Status, levels = c(levels(irr$Status), "idled"))
idx <- c(980, 981, 993, 1002, 1005, 1007, 1044, 1049, 1052,
         1059, 1061, 1065, 1066, 1067, 1073, 1074, 1076)
irr$Status[idx] <- "idled"
ll <- colMeans(coordinates(irr[idx, ]))
ext <- spTransform(alluvium.extent, crs)
irr <- crop(irr, extent(ext))
Pal <- colorFactor(c("#1B9E77", "#7570B3", "#D95F02"), irr$Status)
map <- CreateWebMap("Topo")
map <- setView(map, lng = ll[1], lat = ll[2], zoom = 12)
map <- addPolygons(map, data = irr, stroke = FALSE, fillOpacity = 0.6,
                   color = Pal(irr$Status))
map <- addPolylines(map, data = ext, weight = 3, color = "#000000")
map <- addLegend(map, pal = Pal, values = irr$Status, opacity = 0.6)
map

File Changes

Changes to unprocessed-data files include:

  • Irrigated lands (“extdata/irr/irr.lands.<YYYY>.zip”)—changed parcel status to “non-irrigated”.

  • Evapotranspiration (ET)(“extdata/et/et.<YYYYMM>.tif”)—reduced ET within the parcel and set equal to the monthly precipitation during the irrigation season (April–October).

  • Combined surface-water irrigation diversions (“extdata/div/comb.sw.irr.csv”)–removed diversions associated with wells in parcel.

  • Groundwater points of diversion (“extdata/div/pod.gw.csv”)—removed diversions for wells in parcel.

  • Well sites (“extdata/div/pod.wells.zip”)—removed sites located in parcel.

Files that did not need to be modified for this scenario, but may want to be considered for modification in similar types of scenarios include:

  • Surface water diversions (“div.sw.csv”)—we assumed surface water associated with the idled parcel is now delivered to other “junior” users within the same canal service area.

  • Groundwater diversions (“div.gw.csv”)—if there had been “measured” groundwater diversions associated with the parcel, those would need to be removed.

Code Chunks

Most of the R code that we need for building, running, and analyzing the model scenario is contained within the appendix files. Rather than rewrite all the relevant code here, we will instead use the ReadCodeChunks function in the inlmisc package to read code chunks embedded within an appendix source file into our R session. Read appendix C and D code chunks using the following commands:

file <- system.file("doc", "sir20165080_AppendixC.R", package = "wrv")
app.c.chunks <- ReadCodeChunks(file)
file <- system.file("doc", "sir20165080_AppendixD.R", package = "wrv")
app.d.chunks <- ReadCodeChunks(file)

Each of the relevant code chunks is labeled with a unique name. For example, the following command retrieves the code chunk named “write_modflow_input” in appendix D:

chunk <- app.d.chunks[["write_modflow_input"]]
print(chunk)
[1] "## ----write_modflow_input-------------------------------------------------"     
[2] "id <- \"wrv_mfusg\"  # model run identifier"                                     
[3] "dir.run <- \"model/model1\""                                                     
[4] "WriteModflowInput(rs.model, rech, well, trib, misc, river, drain, id, dir.run,"  
[5] "                  is.convertible = FALSE, tr.stress.periods = tr.stress.periods,"
[6] "                  ntime.steps = ntime.steps, verbose = FALSE)"                   

Create Modified Datasets

Every time we create a modified dataset it masks its wrv-package version. The R script for creating the modified datasets is primarily based on code chunks in appendix C. Run (that is, parse and evaluate) the code chunk named “setup” in appendix C using the following command:

eval(parse(text = app.c.chunks[["setup"]]))

Specify the folder in your working directory that contains the modified unprocessed-data files (“extdata”) and place them in a temporary directory as uncompressed files using

folder <- "extdata"
files <- list.files(folder, full.names = TRUE, recursive = TRUE)
dirs <- file.path(tempdir(), unique(dirname(files)))
sapply(dirs, function(i) dir.create(i, recursive = TRUE))
file.copy(files, file.path(tempdir(), files))
dir.in <- file.path(tempdir(), "extdata")
files <- list.files(dir.in, pattern = "*.zip$", full.names = TRUE, recursive = TRUE)
for (i in files) unzip(i, exdir = dirname(i))

Create a folder in your working directory where modified R-data files will be written.

dir.out <- "data"
dir.create(dir.out, showWarnings = FALSE)

Run the initial commands for specifying the unit conversions, coordinate reference system (CRS), and common spatial/temporal grid.

chunk.names <- c("unit_conversions", "crs", "spatial", "high_res_spatial", "temporal")
eval(parse(text = unlist(app.c.chunks[chunk.names])))

Level 1 data

These are processing instructions for creating level 1 modified datasets.

Combined surface-water irrigation diversions (comb.sw.irr)

Read combined surface-water irrigation diversions data and write its external representation as an R object in “data/comb.sw.irr.rda”.

eval(parse(text = app.c.chunks[["comb_sw_irr_1"]]))

Points of diversion for groundwater (pod.gw)

Read points of diversion for groundwater data and write its external representation as an R object in “data/pod.gw.csv.rda”.

eval(parse(text = app.c.chunks[["pod_gw_1"]]))

Well completions (pod.wells)

Read well completions data and write its external representation as an R object in “data/pod.wells.rda”.

eval(parse(text = unlist(app.c.chunks[c("pod_wells_1", "pod_wells_2")])))

Irrigation lands (irr.lands)

Read irrigated and semi-irrigated lands data and write its external representation as an R object in “data/irr.lands.rda”.

eval(parse(text = app.c.chunks[["irr_lands_1"]]))

Evapotranspiration (et)

Read evapotranspiration (ET) data and write its external representation as an R object in “data/et.rda”. Note that unprocessed ET raster files (“.tif”) are required for every month in the simulation, not just months with modified values.

eval(parse(text = unlist(app.c.chunks[c("et_1", "et_2")])))

Level 2 data

These are processing instructions for creating level 2 modified datasets. Recall that level 2 datasets are dependent on level 1 data.

Monthly irrigation entity components (entity.components)

Write an external representation of monthly irrigation entity components as an R object in “data/entitiy.components.rda”.

eval(parse(text = unlist(app.c.chunks[paste0("entity_components_", 1:3)])))

Rasterized monthly irrigation entities (rs.entities)

Write an external representation of monthly irrigation entities as an R object in “data/rs.entities.rda”

eval(parse(text = app.c.chunks[["rs_entities_1"]]))

Rasterized monthly recharge on non-irrigated lands (rs.rech.non.irr)

Write an external representation of monthly recharge on non-irrigated lands as an R object in “data/rs.rech.non.irr.rda”.

eval(parse(text = app.c.chunks[["rs_rech_non_irr_1"]]))

Model Processing

Let’s start model processing with a clean R environment. Remove all objects created during the previous instructions and reload our modified datasets.

rm(list = ls()[!ls() %in% "app.d.chunks"])
files <- list.files("data", pattern = "*.rda$", full.names = TRUE)
lapply(files, load, envir = .GlobalEnv)

Copy calibrated files

Copy all the calibrated model files from the “archive” folder to a new folder named “model” in our working directory.

dir.create("model", showWarnings = FALSE)
files <- list.files("archive", full.names = TRUE)
file.copy(files, "model", overwrite = TRUE)

Specify the identifier for the model run.

id <- "wrv_mfusg"

Load R objects from the “model/model.rda” file into your R environment, these objects include d.in.mv.ave, misc, reduction, rs, ss.stress.periods, tr.stress.periods, and trib. A description of each R object is given in the help documentation of the UpdateWaterBudget function in the wrv package.

load("model/model.rda")

The rs object in the appendix D code is named rs.model; use the following command to address this issue:

rs.model <- rs

Recalculate Specified Flows

Recalculate the specified-flow boundary conditions using our modified datasets—this results in a new MODFLOW Well file (“model/wrv_mfusg.wel”) and quality assurance tables (“model/qa-*.csv”). Note that all modified datasets need to be passed as arguments in the UpdateWaterBudget function.

UpdateWaterBudget("model", id, qa.tables = "english", pod.wells = pod.wells,
                  comb.sw.irr = comb.sw.irr, et = et,  pod.gw = pod.gw,
                  entity.components = entity.components, rs.entities = rs.entities)

Run MODFLOW

Run MODFLOW-USG using model scenario conditions.

wd <- setwd("model")
system2(file.path(getwd(), "RunModflow.bat"), stdout = FALSE, stderr = FALSE)
setwd(wd)

Read water budgets

Read water-budget output for the archived calibrated simulation, located in the “archive” folder, and save the results for later use. To do so, run the code chunks named “read_budget_1” and “read_budget_2” in appendix D using the following commands:

dir.run <- "archive"  # code below is dependent on this object
eval(parse(text = unlist(app.d.chunks[paste0("read_budget_", 1:2)])))

And save the average volumetric flow rates to an R object named budget1 using

budget1 <- c("Water-table recharge"             = mean(d.rech$flow.in),
             "Streamflow losses"                = mean(d.river$flow.in),
             "Tributary basin underflow"        = mean(d.trib$flow),
             "Water-table discharge"            = mean(d.rech$flow.out),
             "Streamflow gains"                 = mean(d.river$flow.out),
             "Production well pumping"          = mean(d.well$flow),
             "Stanton Crossing outlet boundary" = mean(d.drain.1$flow),
             "Silver Creek outlet boundary"     = mean(d.drain.2$flow))
budget1 <- setNames(as.integer(abs(budget1)) * 0.296106669, names(budget1))

Next, read the water-budget output for the scenario simulation, located in the “model” folder.

dir.run <- "model"
eval(parse(text = unlist(app.d.chunks[paste0("read_budget_", 1:2)])))

And save the average volumetric flow rates to an R object named budget2 using

budget2 <- c("Water-table recharge"             = mean(d.rech$flow.in),
             "Streamflow losses"                = mean(d.river$flow.in),
             "Tributary basin underflow"        = mean(d.trib$flow),
             "Water-table discharge"            = mean(d.rech$flow.out),
             "Streamflow gains"                 = mean(d.river$flow.out),
             "Production well pumping"          = mean(d.well$flow),
             "Stanton Crossing outlet boundary" = mean(d.drain.1$flow),
             "Silver Creek outlet boundary"     = mean(d.drain.2$flow))
budget2 <- setNames(as.integer(abs(budget2)) * 0.296106669, names(budget2))

Compare water budgets

A comparison between water budgets is made by constructing the following table.

Table: Water budgets for modified and archived simulation, specified as volumetric flow rates average over 1998–2010. [Inflow: water entering the aquifer system. Outflow: water leaving the aquifer system. Component: a water budget component in the groundwater-flow model. Archived Rate: is the mean volumetric flow rate for the archived simulation. Modified Rate: is the mean volumetric flow rate for the modified simulation. Difference: is the archived rate subtracted from the modified rate. Abbreviations: acre-ft/yr, acre-feet per year]

d <- data.frame(rate1 = budget1, rate2 = budget2)
d$direction <- c("**Inflow**", "", "", "**Outflow**", "", "", "", "")
d$component <- names(budget1)
d$diff <- budget2 - budget1
d$pchange <- ((budget2 - budget1) / budget1) * 100
d <- rbind(d[1:3, ], NA, d[4:8, ], NA, NA)
d$component[nrow(d)] <- "**Inflow - Outflow**"
d$rate1[nrow(d)] <- sum(budget1[1:3]) - sum(budget1[5:8])
d$rate2[nrow(d)] <- sum(budget2[1:3]) - sum(budget2[5:8])
rownames(d) <- NULL
d <- d[, c("direction", "component", "rate1", "rate2", "diff", "pchange")]
colnames(d) <- c("", "Component", "Archived rate<br>(acre-ft/yr)",
                 "Scenario rate<br>(acre-ft/yr)", "Difference<br>(arce-ft/yr)",
                 "Percent<br>change")
d[, 3] <- formatC(d[, 3], format = "f", digits = 0, big.mark = ",")
d[, 4] <- formatC(d[, 4], format = "f", digits = 0, big.mark = ",")
d[, 5] <- formatC(d[, 5], format = "f", digits = 0, big.mark = ",")
d[, 6] <- formatC(d[, 6], format = "f", digits = 1, big.mark = ",")
d[, 1:2][is.na(d[, 1:2])]  <- ""
d[, 3:6][d[, 3:6] == "NA"] <- ""
knitr::kable(d, format = "markdown", padding = 0, booktabs = TRUE, digits = 0,
             row.names = FALSE, col.names = colnames(d), align = "llrrrr")
Component Archived rate
(acre-ft/yr)
Scenario rate
(acre-ft/yr)
Difference
(arce-ft/yr)
Percent
change
Inflow Water-table recharge 120,511 120,494 -17 -0.0
Streamflow losses 193,018 192,719 -300 -0.2
Tributary basin underflow 18,171 18,171 0 0.0
Outflow Water-table discharge 28,712 28,712 0 0.0
Streamflow gains 241,604 242,256 651 0.3
Production well pumping 50,697 49,749 -948 -1.9
Stanton Crossing outlet boundary 284 284 0 0.0
Silver Creek outlet boundary 9,060 9,060 0 0.0
Inflow - Outflow 30,056 30,036

Read hydraulic heads

Read simulated hydraulic heads for archived simulation, located in “archive” folder, and save results.

Read the simulated hydraulic head (head) output for the archived calibrated model, located in the “archive” folder, and save the results for later use. To do so, run the code chunk named “read_head” in appendix D using the following commands:

dir.run <- "archive"
eval(parse(text = app.d.chunks[["read_head"]]))
head1 <- rs.heads.lay1

Next, read the head output for the scenario simulation, located in the “model” folder.

dir.run <- "model"
eval(parse(text = app.d.chunks[["read_head"]]))
head2 <- rs.heads.lay1

Compare head distributions

Draw a map the simulated water table difference, defined as the archived water table subtracted from the modified water table, during August 16, 2007. Add an observation point located at a longitude and latitude of -114.222664 and 43.383047 decimal degrees, respectively.

ext <- spTransform(alluvium.extent, CRS("+init=epsg:4326"))
r <- head2[["2007-08-16"]] - head1[["2007-08-16"]]
r[] <- round(r[] * 3.28084, digits = 3)
r <- projectRaster(r, crs = CRS("+init=epsg:4326"), method = "ngb")
Pal <- colorNumeric("Spectral", r[], na.color = "transparent")
map <- CreateWebMap("Topo")
ll  <- coordinates(ext)
map <- setView(map, lng = ll[1], lat = ll[2], zoom = 11)
map <- addRasterImage(map, r, colors = Pal, opacity = 0.8)
map <- addPolylines(map, data = ext, weight = 3, color = "#000000")
map <- addLegend(map, pal = Pal, values = r[], opacity = 0.8,
                 title = "Head Diff.<br/>(feet)")
ll <- c(-114.222664, 43.383047)
txt <- sprintf("<b>Longitude:</b> %s<br/><b>Latitude:</b> %s", ll[1], ll[2])
icon <- icons(iconUrl = "markers/marker-blue.png",
              iconWidth = 34, iconHeight = 34, iconAnchorX = 17, iconAnchorY = 34)
map <- addMarkers(map, lng = ll[1], lat = ll[2], popup = txt, icon = icon)
map

Finally, at the observation point, plot the head difference in model layer 1 over time.

pnt <- data.frame(lon = ll[1], lat = ll[2])
coordinates(pnt) <- c("lon", "lat")
proj4string(pnt) <- CRS("+init=epsg:4326")
pnt <- spTransform(pnt, crs(hill.shading))
d <- t(extract(head2, pnt) - extract(head1, pnt))
d <- data.frame(Date = as.Date(rownames(d)), difference = d)
ylab <- paste("Hydraulic head difference, in", c("meters", "feet"))
PlotGraph(d, ylab = ylab, col = "#025D8C", conversion.factor = 3.28084,
          center.date.labels = TRUE, seq.date.by = "year")