Given one or more simList objects, run a series of spades calls
in a structured, organized way. Methods are available to deal with outputs,
such as as.data.table.simLists() which can pull out simple to complex
values from every resulting simList or object saved by outputs
in every simList run. This uses future internally, allowing
for various backends and parallelism.
One or more simList objects. Additional named arguments are
passed through to SpaDES.core::spades() (see Controlling events below).
The number of replicates to run of the same simList.
See details and examples. To minimize memory overhead, currently,
this must be length 1, i.e., all ... simList objects will
receive the same number of replicates.
Logical. If TRUE, then the envir(sim) of each simList in the return list is emptied. This is to reduce RAM load of large return object. Default FALSE.
A character vector of the paths passed to simInit,
indicating which should create a new, unique path, as a sub-path to the original
paths. Currently only "outputPath" is honoured. Pass character(0) (or
NULL) to disable this nesting entirely, e.g. when the caller (such as
experiment()) has already set each simList's outputPath.
Logical. Passed to spades. This will be passed with the simList
name and replicate number, allowing each replicate and each simList to be
seen as a non-cached call to spades.
Passed to SpaDES.core::spades().
Optional character string. If provided, it will be passed
to each worker and run as googledrive::drive_auth(drive_auth_account) to allow
a specific user account for googledrive
If used, this will use
Sys.sleep(cumsum(c(0, rnorm(nbrOfWorkers() - 1, mean = meanStaggerIntervalInSecs,
sd = meanStaggerIntervalInSecs/10)))) and distribute these delays to the workers.
Invisibly returns a simLists object. This class
extends the environment class and contains simList objects.
This function was moved here from the now-unmaintained SpaDES.experiment
package. See also the file-queue based experiment_family (e.g.
experimentFuture()) for a different, script-oriented approach.
This function, because of its class formalism, allows for methods to be used. For example,
as.data.table.simLists() allows user to pull out specific objects (in
the simList objects or on disk saved in outputPath(sim)).
The outputPath is changed so that every simulation puts outputs in a
sub-directory of the original outputPath of each simList (unless
createUniquePaths is character(0)/NULL).
A simLists object can be made manually, if, say, many manual spades calls
have already been run. See example, via new("simLists")
Any named argument in ... that is not consumed by experiment2 is passed
straight to SpaDES.core::spades(). In particular, spades()'s events
argument is honoured, so
experiment2(sim1, sim2, events = list(...)) restricts the events that run
for every simulation. Note this applies the same events specification to
all simLists / replicates. For per-scenario control of events, use the
file-queue experiment_family with an events column in df (see
experiment_family).
if (FALSE) { # \dontrun{
if (require("ggplot2", quietly = TRUE) &&
require("NLMR", quietly = TRUE) &&
require("RColorBrewer", quietly = TRUE)) {
library(SpaDES.core)
library(SpaDES.project)
tmpdir <- file.path(tempdir(), "examples")
# Make 3 simLists -- set up scenarios
endTime <- 2
# Example of changing parameter values
# Make 3 simLists with some differences between them
mySim <- lapply(c(10, 20, 30), function(nFires) {
simInit(
times = list(start = 0.0, end = endTime, timeunit = "year"),
params = list(
.globals = list(stackName = "landscape", burnStats = "nPixelsBurned"),
# Turn off interactive plotting
fireSpread = list(.plotInitialTime = NA, spreadprob = c(0.2), nFires = c(10)),
caribouMovement = list(.plotInitialTime = NA),
randomLandscapes = list(.plotInitialTime = NA, .useCache = "init")
),
modules = list("randomLandscapes", "fireSpread", "caribouMovement"),
paths = list(modulePath = system.file("sampleModules", package = "SpaDES.core"),
outputPath = tmpdir),
# Save final state of landscape and caribou
outputs = data.frame(
objectName = c(rep("landscape", endTime), "caribou", "caribou"),
saveTimes = c(seq_len(endTime), unique(c(ceiling(endTime / 2), endTime))),
stringsAsFactors = FALSE
)
)
})
planTypes <- c("sequential") # try others! ?future::plan
sims <- experiment2(sim1 = mySim[[1]], sim2 = mySim[[2]], sim3 = mySim[[3]],
replicates = 3)
# Try pulling out values from simulation experiments
# 2 variables
df1 <- as.data.table(sims, vals = c("nPixelsBurned", NCaribou = quote(length(caribou$x1))))
# Now use objects that were saved to disk at different times during spades call
df1 <- as.data.table(sims,
vals = c("nPixelsBurned", NCaribou = quote(length(caribou$x1))),
objectsFromOutputs = list(nPixelsBurned = NA, NCaribou = "caribou"))
# now calculate 4 different values, some from data saved at different times
# Define new function -- this calculates perimeter to area ratio
fn <- quote({
landscape$Fires[landscape$Fires[] == 0] <- NA;
a <- boundaries(landscape$Fires, type = "inner");
a[landscape$Fires[] > 0 & a[] == 1] <- landscape$Fires[landscape$Fires[] > 0 & a[] == 1];
peri <- table(a[]);
area <- table(landscape$Fires[]);
keep <- match(names(area),names(peri));
mean(peri[keep]/area)
})
df1 <- as.data.table(sims,
vals = c("nPixelsBurned",
perimToArea = fn,
meanFireSize = quote(mean(table(landscape$Fires[])[-1])),
caribouPerHaFire = quote({
NROW(caribou) /
mean(table(landscape$Fires[])[-1])
})),
objectsFromOutputs = list(NA, c("landscape"), c("landscape"),
c("landscape", "caribou")),
objectsFromSim = "nPixelsBurned")
if (interactive()) {
# with an unevaluated string
library(ggplot2)
p <- lapply(unique(df1$vals), function(var) {
ggplot(df1[vals == var,],
aes(x = saveTime, y = value, group = simList, color = simList)) +
stat_summary(geom = "point", fun.y = mean) +
stat_summary(geom = "line", fun.y = mean) +
stat_summary(geom = "errorbar", fun.data = mean_se, width = 0.2) +
ylab(var)
})
# Arrange all 4 -- could use gridExtra::grid.arrange -- easier
pushViewport(viewport(layout = grid.layout(2, 2)))
vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p[[1]], vp = vplayout(1, 1))
print(p[[2]], vp = vplayout(1, 2))
print(p[[3]], vp = vplayout(2, 1))
print(p[[4]], vp = vplayout(2, 2))
}
}
} # }