Each of the models in shadia
can be run under variable passage scenarios to understand how combinations of upstream and downstream dam passage influence population characteristics such as abundance. This can be done using fixed values for individual model sets, or by sampling passage values from pre-defined sets. The latter is generally easier to do because it reduces the number of simulations that must be organized and executed.
Begin by loading libraries and setting up number of virtual cores (ncpus
) when initializing a socket cluster with snowfall
:
# Load R packages
library(snowfall)
library(rlecuyer)
library(shadia)
# Initialize snowfall
sfInit(parallel=TRUE, cpus=7, type="SOCK")
R Version: R version 3.6.3 (2020-02-29)
Then, define a wrapper function that can be called in parallel using sfLapply()
. Here, we specify output_years = "last"
because we are interested in comparing population size in the final year of simulation among varying upstream and downstream passage efficiencies that we randomly sample from vectors of pre-defined values. These passage efficiencies must either be defined within the wrapper
function or passed to snowfall
as data.
wrapper <- function(x) {
# Randomly sampling passage efficiencies
# Upstream passage through dams
upstream_p <- seq(0, 1, .1)
upstreamx <- sample(upstream_p, 1, replace = TRUE)
# Adult downstream survival through dams
downstream_p <- c(0.90, 0.95, 1.00)
downstreamx <- sample(downstream_p, 1, replace = TRUE)
# Juvenile downstream survival through dams
downstream_juvp <- c(0.90, 0.95, 1.00)
downstream_juvx <- sample(downstream_juvp, 1, replace = TRUE)
# Run the model with desired settings or
# a random set of conditions
res1 <- mohawkHudsonRiverModel(
species = 'shad',
pMohawk = 0,
nYears = 20,
n_adults = rnorm(1, 1e4, 100),
timing = rep(1, 26),
upstream = list(
federal = upstreamx,
C01 = 1, C02 = 1, C03 = 1, C04 = 1, C05 = 1, C06 = 1,
E02 = 1, E03 = 1, E04 = 1, E05 = 1, E06 = 1,
E07 = 1, E08 = 1, E09 = 1, E10 = 1, E11 = 1, E12 = 1,
E13 = 1, E14 = 1, E15 = 1, E16 = 1, E17 = 1, E18 = 1,
E19 = 1, E20 = 1
),
downstream = list(
federal = downstreamx,
C01 = 1, C02 = 1, C03 = 1, C04 = 1, C05 = 1, C06 = 1,
E02 = 1, E03 = 1, E04 = 1, E05 = 1, E06 = 1,
E07 = 1, E08 = 1, E09 = 1, E10 = 1, E11 = 1, E12 = 1,
E13 = 1, E14 = 1, E15 = 1, E16 = 1, E17 = 1, E18 = 1,
E19 = 1, E20 = 1
),
downstream_juv = list(
federal = downstream_juvx,
C01 = 1, C02 = 1, C03 = 1, C04 = 1, C05 = 1, C06 = 1,
E02 = 1, E03 = 1, E04 = 1, E05 = 1, E06 = 1,
E07 = 1, E08 = 1, E09 = 1, E10 = 1, E11 = 1, E12 = 1,
E13 = 1, E14 = 1, E15 = 1, E16 = 1, E17 = 1, E18 = 1,
E19 = 1, E20 = 1
),
lockMortality = 0,
inRiverF = 0,
commercialF = 0,
bycatchF = 0,
indirect = 1,
latent = 1,
watershed = TRUE,
k_method = 'cumulative',
sensitivity = FALSE,
spatially_explicit_output = FALSE,
output_years = "last",
output_p_repeat = FALSE
)
# Define the output list
retlist <- list(
sim = res1)
return(retlist)
}
Load libraries on cluster and define desired number of iterations. Note that niterations <- 200
is used to obtain a minimal output necessary to generate a plot here for brevity. A larger simulation with 1,000 - 2,000 runs may take 20-40 minutes on a modern laptop depending on hardware, number of years simulated, and passage efficiencies (due influence on number of fish used on time to run individual-based model components).
# Load packages on workers
sfLibrary(shadia)
Library shadia loaded.
sfLibrary(rlecuyer)
Library rlecuyer loaded.
# Number of iterations
niterations <- 200
Run the simulation in parallel using sfLapply()
. This may take a few minutes on a laptop with 8 cores.
# Distribute pre-defined wrapper function
# to workers using sfLapply()
result <- sfLapply(1:niterations, wrapper)
# Stop snowfall
sfStop()
Extract the results and compile into a dataframe:
# Extract results list from output list
out <- lapply(result, function(x) x[[c('sim')]])
# Extract user inputs and population metrics
# res <- lapply(out, function(x) x[[c('res')]])
resdf <- do.call(rbind, out)
Summarize and plot abundance by various passage combinations:
# Summary
library(tidyverse)
plotter <- resdf %>%
group_by(downstream_juv, downstream, upstream) %>%
summarize(
pop=mean(populationSize),
lci=CI(populationSize)[1],
uci=CI(populationSize)[2]
)
# Labels for facets
plotter$downstream_juv <- paste0("Juvenile downstream = ",
plotter$downstream_juv)
# Plot
ggplot(plotter,
aes(x = upstream,
y = pop,
color = factor(downstream),
fill = factor(downstream))) +
geom_ribbon(
aes(x = upstream, ymin = lci, ymax = uci, color = NULL), alpha = 0.10) +
geom_line() +
facet_wrap(~ downstream_juv) +
scale_x_continuous(limits = c(0, 1), expand = c(0, 0)) +
xlab("Upstream passage per day") +
ylab("Millions of spawners") +
labs(color = "Adult downstream survival",
fill = "Adult downstream survival") +
scale_y_continuous(breaks = seq(0,10e7,.5e6),
labels = format(seq(0, 100, .5), digits=2)) +
theme_bw() +
theme(
panel.spacing = unit(.05, units = "npc"),
panel.grid = element_blank(),
legend.position = "top",
legend.box = "horizontal",
legend.margin = margin(unit(.5, units = "npc")),
axis.text = element_text(color = "black"),
axis.title.x = element_text(vjust = -1),
axis.title.y = element_text(vjust = 3),
strip.background = element_blank(),
strip.text = element_text(size = 8)
)
This work is licensed under a Creative Commons 4.0 International License.