Create a new simulation object, the "sim" object. This object is implemented
using an environment
where all objects and functions are placed.
Since environments in R
are pass by reference, "putting" objects in
the sim object does no actual copy.
The simList
also stores all parameters, and other important simulation
information, such as times, paths, modules, and module load order.
See more details below.
simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL ) # S4 method for list,list,list,list,list,data.frame,data.frame,character simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL ) # S4 method for ANY,ANY,ANY,character,ANY,ANY,ANY,ANY simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL ) # S4 method for ANY,ANY,character,ANY,ANY,ANY,ANY,ANY simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL ) # S4 method for ANY,ANY,ANY,ANY,ANY,ANY,ANY,ANY simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL )
times | A named list of numeric simulation start and end times
(e.g., |
---|---|
params | A list of lists of the form |
modules | A named list of character strings specifying the names of modules to be loaded
for the simulation.
Note: the module name should correspond to the R source file from which the module is loaded.
Example: a module named "caribou" will be sourced form the file |
objects | (optional) A vector of object names (naming objects
that are in the calling environment of
the |
paths | An optional named list with up to 4 named elements,
|
inputs | A |
outputs | A See |
loadOrder | An optional list of module names specifying the order in which to load the modules. If not specified, the module load order will be determined automatically. |
notOlderThan | A time, as in from |
A simList
simulation object, pre-initialized from values
specified in the arguments supplied.
simInit
function does the following:What | Details | Argument(s) to use |
fills simList slots | places the arguments times ,
params , modules , paths into equivalently named
simList slots | times ,
params , modules , paths |
sources all module files | places all function definitions in the
simList , specifically, into a sub-environment of the main
simList environment: e.g., sim$<moduleName>$function1
(see section on Scoping) | modules |
copies objects | from the global environment to the
simList environment | objects |
loads objects | from disk into the simList | inputs |
schedule object loading/copying | Objects can be loaded into the
simList at any time during a simulation | inputs |
schedule object saving | Objects can be saved to disk at any arbitrary
time during the simulation. If specified here, this will be in addition
to any saving due code inside a module (i.e., a module may manually
run write.table(...) | outputs |
schedules "init" events | from all modules (see events ) | automatic |
assesses module dependencies | via the inputs and outputs identified in their
metadata. This gives the order of the .inputObjects and init
events. This can be overridden by loadOrder . | automatic |
determines time unit | takes time units of modules and how they fit together | times or automatic |
runs .inputObjects functions | from every module in the module order as determined above | automatic |
params
can only contain updates to any parameters that are defined in
the metadata of modules. Take the example of a module named, Fire
, which
has a parameter named .plotInitialTime
. In the metadata of that module,
it says TRUE
. Here we can override that default with:
list(Fire=list(.plotInitialTime=NA))
, effectively turning off plotting.
Since this is a list of lists, one can override the module defaults for multiple
parameters from multiple modules all at once, with say:
list(Fire = list(.plotInitialTime = NA, .plotInterval = 2),
caribouModule = list(N = 1000))
.
We implement a discrete event simulation in a more modular fashion so it is easier to add modules to the simulation. We use S4 classes and methods, and fast lists to manage the event queue.
paths
specifies the location of the module source files,
the data input files, and the saving output files. If no paths are specified
the defaults are as follows:
cachePath
: getOption("reproducible.cachePath")
;
inputPath
: getOption("spades.modulePath")
;
modulePath
: getOption("spades.inputPath")
;
inputPath
: getOption("spades.outputPath")
.
Since the objects in the simList
are passed-by-reference, it is useful
to create a copy of the initialized simList
object prior to running
the simulation (e.g., mySimOut <- spades(Copy(mySim))
).
This ensures you retain access to the original objects, which would otherwise
be overwritten/modified during the simulation.
The user can opt to run a simpler simInit
call without inputs, outputs, and times.
These can be added later with the accessor methods (See example).
These are not required for initializing the simulation via simInit
.
All of modules
, paths
, params
, and objects
are needed
for successful initialization.
The simInit
function will attempt to find usage of sim$xxx
or sim[['xxx']]
on either side of the assignment (<-
) operator.
It will compare these to the module metadata, specifically inputObjects
for cases where
objects or "gotten" from the simList
and outputObjects
for cases where objects are
assigned to the simList.
It will also attempt to find potential, common function name conflicts with things like
scale
and stack
(both in base and raster), and
Plot
(in quickPlot and some modules).
This code checking is young and may get false positives and false negatives,
i.e., miss things.
It also takes computational time, which may be undesirable in operational code.
To turn off checking (i.e., if there are too many false positives and negatives), set
options(spades.moduleCodeChecks = FALSE)
.
Using caching with SpaDES
is vital when building re-usable and reproducible content.
Please see the vignette dedicated to this topic.
Matloff, N. (2011). The Art of R Programming (ch. 7.8.3). San Francisco, CA: No Starch Press, Inc.. Retrieved from https://nostarch.com/artofr.htm
Alex Chubaty and Eliot McIntire
if (FALSE) { mySim <- simInit( times = list(start = 0.0, end = 2.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), paths = list(modulePath = system.file("sampleModules", package = "SpaDES.core")) ) spades(mySim) # shows plotting # Change more parameters, removing plotting mySim <- simInit( times = list(start = 0.0, end = 2.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned"), fireSpread = list(.plotInitialTime = NA) ), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), paths = list(modulePath = system.file("sampleModules", package = "SpaDES.core")) ) outSim <- spades(mySim) # A little more complicated with inputs and outputs if (require(rgdal)) { mapPath <- system.file("maps", package = "quickPlot") mySim <- simInit( times = list(start = 0.0, end = 2.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), paths = list(modulePath = system.file("sampleModules", package = "SpaDES.core"), outputPath = tempdir()), inputs = data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "raster", package = "raster", loadTime = 1, stringsAsFactors = FALSE), outputs = data.frame( expand.grid(objectName = c("caribou","landscape"), saveTime = 1:2, stringsAsFactors = FALSE)) ) # Use accessors for inputs, outputs mySim2 <- simInit( times = list(current = 0, start = 0.0, end = 2.0, timeunit = "year"), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), params = list(.globals = list(stackName = "landscape", burnStats = "nPixelsBurned")), paths = list( modulePath = system.file("sampleModules", package = "SpaDES.core"), outputPath = tempdir() ) ) # add by accessor is equivalent inputs(mySim2) <- data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "raster", package = "raster", loadTime = 1, stringsAsFactors = FALSE) outputs(mySim2) <- data.frame( expand.grid(objectName = c("caribou", "landscape"), saveTime = 1:2, stringsAsFactors = FALSE)) all.equal(mySim, mySim2) # TRUE # Use accessors for times -- does not work as desired because times are # adjusted to the input timeunit during simInit mySim2 <- simInit( params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), paths = list(modulePath = system.file("sampleModules", package = "SpaDES.core"), outputPath = tempdir()), inputs = data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "raster", package = "raster", loadTime = 1, stringsAsFactors = FALSE), outputs = data.frame( expand.grid(objectName = c("caribou","landscape"), saveTime = 1:2, eventPriority = c(0,10), # eventPriority 0 may give "initial" conditions stringsAsFactors = FALSE)) ) # add times by accessor fails all.equal test because "year" was not # declared during module loading, so month became the default times(mySim2) <- list(current = 0, start = 0.0, end = 2.0, timeunit = "year") all.equal(mySim, mySim2) # fails because time units are all different, so # several parameters that have time units in # "months" because they were loaded that way params(mySim)$fireSpread$.plotInitialTime params(mySim2)$fireSpread$.plotInitialTime events(mySim) # load event is at time 1 year events(mySim2) # load event is at time 1 month, reported in years because of # update to times above } }