spades: Run a spatial discrete event simulation

spadesR Documentation

Run a spatial discrete event simulation

Description

Here, we implement a simulation in a more modular fashion so it's easier to add submodules to the simulation. We use S4 classes and methods, and use data.table instead of data.frame to implement the event queue (because it is much faster).

Usage

spades(
  sim,
  debug = getOption("spades.debug"),
  progress = NA,
  cache,
  .plotInitialTime = NULL,
  .saveInitialTime = NULL,
  notOlderThan = NULL,
  events = NULL,
  .plots = getOption("spades.plots", NULL),
  ...
)

## S4 method for signature 'simList,ANY,ANY,missing'
spades(
  sim,
  debug = getOption("spades.debug"),
  progress = NA,
  cache,
  .plotInitialTime = NULL,
  .saveInitialTime = NULL,
  notOlderThan = NULL,
  events = NULL,
  .plots = getOption("spades.plots", NULL),
  ...
)

## S4 method for signature 'ANY,ANY,ANY,logical'
spades(
  sim,
  debug = getOption("spades.debug"),
  progress = NA,
  cache,
  .plotInitialTime = NULL,
  .saveInitialTime = NULL,
  notOlderThan = NULL,
  events = NULL,
  .plots = getOption("spades.plots", NULL),
  ...
)

Arguments

sim

A simList simulation object, generally produced by simInit.

debug

Optional tools for invoking debugging. Supplying a list will invoke the more powerful logging package. See details. Default is to use the value in getOption("spades.debug").

progress

Logical (TRUE or FALSE show a graphical progress bar), character ("graphical", "text") or numeric indicating the number of update intervals to show in a graphical progress bar.

cache

Logical. If TRUE, then the spades call will be cached. This means that if the call is made again with the same simList, then spades will return the return value from the previous run of that exact same simList. Default FALSE. See Details. See also the vignette on caching for examples.

.plotInitialTime

Numeric. Temporarily override the .plotInitialTime parameter for all modules. See Details.

.saveInitialTime

Numeric. Temporarily override the .plotInitialTime parameter for all modules. See Details.

notOlderThan

Date or time. Passed to reproducible::Cache to update the cache. Default is NULL, meaning don't update the cache. If Sys.time() is provided, then it will force a recache, i.e., remove old value and replace with new value. Ignored if cache is FALSE.

events

A character vector or a named list of character vectors. If specified, the simulations will only do the events indicated here. If a named list, the names must correspond to the modules and the character vectors can be specific events within each of the named modules. With the list form, all unspecified modules will run all their events, including internal spades modules, e.g., save, that get invoked with the outputs argument in simInit. See example.

.plots

Character. Sets the parameter of this name in all modules. See Plots() for possible values. The parameter is intended to slowly take over from .plotInitialTime as a mechanism to turn on or off plotting. For backwards compatibility, if .plotInitialTime is not set in this spades call, but this .plots is used, two things will happen: setting this without "screen" will turn off all plotting; setting this with "screen" will trigger plotting for any modules that use this parameter but will have no effect on other modules. To get plotting, therefore, it may be necessary to also set .plotInitialTime = start(sim).

...

Any. Can be used to make a unique cache identity, such as "replicate = 1". This will be included in the Cache call, so will be unique and thus spades will not use a cached copy as long as anything passed in ... is unique, i.e., not cached previously.

Details

The is the workhorse function in the SpaDES package. It runs simulations by implementing the rules outlined in the simList.

This function gives simple access to two sets of module parameters: .plotInitialTime and with .plotInitialTime. The primary use of these arguments is to temporarily turn off plotting and saving. "Temporary" means that the simList is not changed, so it can be used again with the simList values reinstated. To turn off plotting and saving, use .plotInitialTime = NA or .saveInitialTime = NA. NOTE: if a module did not use .plotInitialTime or .saveInitialTime, then these arguments will not do anything.

Value

Invisibly returns the modified simList object.

Caching with SpaDES

There are numerous ways in which Caching can be used within SpaDES. Please see the vignette https://spades-core.predictiveecology.org/articles/iii-cache.html for many examples. Briefly, functions, events, modules, entire spades calls or experiment calls (see https://github.com/PredictiveEcology/SpaDES.experiment) can be cached and mixtures of all of these will work. For functions, simply wrap the call with Cache, moving the original function name into the first argument of Cache. For events or modules, set the module parameters, .useCache, e.g., simInit(..., parameters = list(myModule = list(.useCache = "init"))). This can be set to an event name, which will cache that event, or a logical, which will cache every event in that module. Event and module caching makes most sense when the event or module only runs once, such as an initialization or data preparation event/module. Caching an entire simulation is actually just a function call to simInitAndSpades, for example. So, simply writing Cache(simInitAndSpades, modules = ...) will effectively cache a whole simulation. Finally for experiments, it is just like a function call: Cache(simInitandExperiment, ...). The final way Caching can be done is in experiment or spades, by setting the cache argument.

If cache is TRUE, this allows for a seamless way to "save" results of a simulation. The user does not have to intentionally do any saving manually. Instead, upon a call to spades in which the simList is identical, the function will simply return the result that would have come if it had been rerun. Use this with caution, as it will return exactly the result from a previous run, even if there is stochasticity internally. Caching is only based on the input simList. See also the vignette on caching for examples.

debug

The most powerful way to use debug is to invoke the logging R package. To invoke this, debug must be a list with up to 3 named elements: console, file, and debug. Each of these list elements must be a list (including empty list() for defaults) with the sub-list elements here:

console level The level, see below, of information shown
file append Logical. If TRUE, the default, then log entries are appended to file, if it exists
file A filename. Defaults to log.txt
level The level, see below, of information shown
debug See possible values below

level can be a number from 0 to 100 or a character string matching one of the values in logging::loglevels. These are hierarchical levels of information passed to the console. Set a lower number for more information and a higher number for less information. Errors in code will be shown if level is set to "ERROR" or 40 or above; warnings in code will be shown if level is set to "WARN" or 30 or above; normal messages in code will be shown if level is set to "INFO" or 20 or above. For consistency with base R messaging, if default level is used, then normal messaging via message will be shown; this means that suppressMessages will work to suppress messaging only when level is set to "INFO" or 20. Some functions in the SpaDES ecosystem may have information at the lower levels, but currently, there are few to none.

debug is specified as a non-list argument to spades or as list(debug = ...), then it can be a logical, a quoted call, a character vector or a numeric scalar (currently 1 or 2) or a list of any of these to get multiple outputs. This will be run at the start of every event. The following options for debug are available. Each of these can also be in a list to get multiple outputs:

TRUE current(sim) will be printed at the start of each event as it runs
a function name (as character string) If a function, then it will be run on the simList, e.g., "time" will run time(sim) at each event.
moduleName (as character string) All calls to that module will be entered interactively
eventName (as character string) All calls that have that event name (in any module) will be entered interactively
⁠c(<moduleName>, <eventName>)⁠ Only the event in that specified module will be entered into.
Any other R expression expressed as a character string or quoted call Will be evaluated with access to the simList as sim. If this is more than one character string, then all will be printed to the screen in their sequence.
A numeric scalar, currently 1 or 2 (maybe others) This will print out alternative forms of event information that users may find useful

If not specified in the function call, the package option spades.debug is used.

If options("spades.browserOnError" = TRUE) (experimental still) if there is an error, it will attempt to open a browser in the event where the error occurred. You can edit, and then press c to continue or Q to quit, plus all other normal interactive browser tools. c will trigger a reparse and events will continue as scheduled, starting with the one just edited. There may be some unexpected consequences if the simList objects had already been changed before the error occurred.

Note

The debug option is primarily intended to facilitate building simulation models by the user. Will print additional outputs informing the user of updates to the values of various simList slot components. See https://github.com/PredictiveEcology/SpaDES/wiki/Debugging for details.

Author(s)

Alex Chubaty and Eliot McIntire

References

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

See Also

SpaDES.core-package(), simInit(), and the caching vignette (very important for reproducibility): https://spades-core.predictiveecology.org/articles/iii-cache.html which uses reproducible::Cache().

Examples


if (requireNamespace("SpaDES.tools", quietly = TRUE) &&
    requireNamespace("NLMR", quietly = TRUE)) {
  # some options are not necessary when not interactive
  opts <- options("spades.moduleCodeChecks" = FALSE, "spades.useRequire" = FALSE)
  if (!interactive()) opts <- append(opts, options("spades.plots" = NA,
                                                   "spades.debug" = FALSE))
  mySim <- simInit(
   times = list(start = 0.0, end = 1.0, timeunit = "year"),
   params = list(
     randomLandscapes = list(nx = 10, ny = 10),
     .globals = list(stackName = "landscape", burnStats = "nPixelsBurned",
                     .plots = NA) # plotting off --> not relevant for example
   ),
   modules = list("randomLandscapes", "fireSpread", "caribouMovement"),
   paths = list(modulePath = getSampleModules(tempdir()))
  )
  spades(mySim)

  # Different debug options (overrides the package option 'spades.debug')
  spades(mySim, debug = TRUE) # Fastest
  spades(mySim, debug = "print(table(sim$landscape$Fires[]))")
  # To get a combination -- use list(debug = list(..., ...))
  spades(mySim, debug = list(debug = list(1, quote(as.data.frame(table(sim$landscape$Fires[]))))))

  # Can turn off plotting at spades call, and inspect the output simList instead
  out <- spades(mySim, .plots = NA)
  completed(out) # shows completed events

  # use cache -- simInit should generally be rerun each time a spades call is made
  #   to guarantee that it is identical. Here, run spades call twice, first
  #   time to establish cache, second time to return cached result
  for (i in 1:2) {
   mySim <- simInit(
     times = list(start = 0.0, end = 1.0, timeunit = "year"),
     params = list(
       randomLandscapes = list(nx = 10, ny = 10),
       .globals = list(stackName = "landscape", burnStats = "nPixelsBurned")
     ),
     modules = list("randomLandscapes", "fireSpread", "caribouMovement"),
     paths = list(modulePath = getSampleModules(tempdir()))
   )
   print(system.time(out <- spades(mySim, cache = TRUE, .plots = NA)))
  }

  # E.g., with only the init events
  outInitsOnly <- spades(mySim, events = "init")

  # or more fine grained control
  outSomeEvents <- spades(mySim, .plots = NA,
          events = list(randomLandscapes = c("init"),
                        fireSpread = c("init", "burn")))

  # with outputs, the save module gets invoked and must be explicitly limited to "init"
  mySim <- simInit(
   times = list(start = 0.0, end = 1.0, timeunit = "year"),
   params = list(
     randomLandscapes = list(nx = 10, ny = 10),
     .globals = list(stackName = "landscape", burnStats = "nPixelsBurned")
   ),
   modules = list("randomLandscapes", "fireSpread", "caribouMovement"),
   outputs = data.frame(objectName = "landscape", saveTime = 0:2),
   paths = list(modulePath = getSampleModules(tempdir()))
  )
  # This will print a message saying that caribouMovement will run its events
  outSomeEvents <- spades(mySim, .plots = NA,
          events = list(randomLandscapes = c("init"),
                        fireSpread = c("init", "burn"),
                        save = "init"))

  options(opts) # reset options
}



PredictiveEcology/SpaDES.core documentation built on Nov. 15, 2023, 5:08 a.m.