Title: | Core Utilities for Developing and Running Spatially Explicit Discrete Event Models |
---|---|
Description: | Provides the core framework for a discrete event system to implement a complete data-to-decisions, reproducible workflow. The core components facilitate the development of modular pieces, and enable the user to include additional functionality by running user-built modules. Includes conditional scheduling, restart after interruption, packaging of reusable modules, tools for developing arbitrary automated workflows, automated interweaving of modules of different temporal resolution, and tools for visualizing and understanding the within-project dependencies. The suggested package 'NLMR' can be installed from the repository (<https://PredictiveEcology.r-universe.dev>). |
Authors: | Alex M Chubaty [aut] , Eliot J B McIntire [aut, cre] , Yong Luo [ctb], Steve Cumming [ctb], Ceres Barros [ctb] , His Majesty the King in Right of Canada, as represented by the Minister of Natural Resources Canada [cph] |
Maintainer: | Eliot J B McIntire <[email protected]> |
License: | GPL-3 |
Version: | 2.1.5.9002 |
Built: | 2024-12-25 06:15:58 UTC |
Source: | https://github.com/PredictiveEcology/SpaDES.core |
SpaDES.core
packageThis package allows implementation a variety of simulation-type models, with a focus on spatially explicit models. The core simulation components are built upon a discrete event simulation framework that facilitates modularity, and easily enables the user to include additional functionality by running user-built simulation modules. Included are numerous tools to visualize various spatial data formats, as well as non-spatial data. Much work has been done to speed up the core of the DES, with current benchmarking as low as 56 microseconds overhead for each event (including scheduling, sorting event queue, spawning event etc.) or 38 microseconds if there is no sorting (i.e., no sorting occurs under simple conditions). Under most event conditions, therefore, the DES itself will contribute very minimally compared to the content of the events, which may often be milliseconds to many seconds each event.
Bug reports: https://github.com/PredictiveEcology/SpaDES.core/issues
Module repository: https://github.com/PredictiveEcology/SpaDES-modules
Wiki: https://github.com/PredictiveEcology/SpaDES/wiki
SpaDES
)A collection of top-level functions for doing spatial discrete event simulation.
There are two workhorse functions that initialize and run a simulation, and third function for doing multiple spades runs:
simInit() |
Initialize a new simulation |
spades() |
Run a discrete event simulation |
experiment |
In SpaDES.experiment package.
Run multiple spades() calls |
experiment2 |
In SpaDES.experiment package.
Run multiple spades() calls |
Within a module, important simulation functions include:
scheduleEvent() |
Schedule a simulation event |
scheduleConditionalEvent() |
Schedule a conditional simulation event |
removeEvent |
Remove an event from the simulation queue (not yet implemented) |
simList
object classThe principle exported object class is the simList
.
All SpaDES
simulations operate on this object class.
simList() |
The simList class |
simList
methodsCollections of commonly used functions to retrieve or set slots (and their elements)
of a simList()
object are summarized further below.
globals() |
List of global simulation parameters. |
params() |
Nested list of all simulation parameter. |
P() |
Namespaced version of params()
(i.e., do not have to specify module name). |
inputs() |
List of loaded objects used in simulation. (advanced) |
outputs() |
List of objects to save during simulation. (advanced) |
simList
ls() , objects() |
Names of objects referenced by the simulation environment. |
ls.str() |
List the structure of the simList objects. |
objs() |
List of objects referenced by the simulation environment. |
Accessor functions for the paths
slot and its elements.
cachePath() |
Global simulation cache path. |
modulePath() |
Global simulation module path. |
inputPath() |
Global simulation input path. |
outputPath() |
Global simulation output path. |
rasterPath() |
Global simulation temporary raster path. |
paths() |
Global simulation paths (cache, modules, inputs, outputs, rasters). |
Accessor functions for the simtimes
slot and its elements.
time() |
Current simulation time, in units of longest module. |
start() |
Simulation start time, in units of longest module. |
end() |
Simulation end time, in units of longest module. |
times() |
List of all simulation times (current, start, end), in units of longest module.. |
Accessor functions for the events
and completed
slots.
By default, the event lists are shown when the simList
object is printed,
thus most users will not require direct use of these methods.
events() |
Scheduled simulation events (the event queue). (advanced) |
current() |
Currently executing event. (advanced) |
completed() |
Completed simulation events. (advanced) |
elapsedTime() |
The amount of clock time that modules & events use |
Accessor functions for the depends
, modules
, and .loadOrder
slots.
These are included for advanced users.
depends() |
List of simulation module dependencies. (advanced) |
modules() |
List of simulation modules to be loaded. (advanced) |
packages() |
Vector of required R libraries of all modules. (advanced) |
simList
environmentThe simList()
has a slot called .xData
which is an environment.
All objects in the simList
are actually in this environment,
i.e., the simList
is not a list
.
In R, environments use pass-by-reference semantics, which means that copying
a simList
object using normal R assignment operation (e.g., sim2 <- sim1
),
will not copy the objects contained within the .xData
slot.
The two objects (sim1
and sim2
) will share identical objects
within that slot. Sometimes, this not desired, and a true copy is required.
envir() |
Access the environment of the simList directly (advanced) |
copy() |
Deep copy of a simList. (advanced) |
Accessor method | Module | Description |
checkpointFile() |
checkpoint |
Name of the checkpoint file. (advanced) |
checkpointInterval() |
checkpoint |
The simulation checkpoint interval. (advanced) |
progressType() |
.progress |
Type of graphical progress bar used. (advanced) |
progressInterval() |
.progress |
Interval for the progress bar. (advanced) |
Modules are the basic unit of SpaDES
.
These are generally created and stored locally, or are downloaded from remote
repositories, including our
SpaDES-modules
repository on GitHub.
checksums() |
Verify (and optionally write) checksums for a module's data files. |
downloadModule() |
Open all modules nested within a base directory. |
getModuleVersion() |
Get the latest module version # from module repository. |
newModule() |
Create new module from template. |
newModuleDocumentation() |
Create empty documentation for a new module. |
openModules() |
Open all modules nested within a base directory. |
moduleMetadata() |
Shows the module metadata. |
zipModule() |
Zip a module and its associated files. |
Each module requires several items to be defined.
These comprise the metadata for that module (including default parameter
specifications, inputs and outputs), and are currently written at the top of
the module's .R
file.
defineModule() |
Define the module metadata |
defineParameter() |
Specify a parameter's name, value and set a default |
expectsInput() |
Specify an input object's name, class, description, sourceURL and other specifications |
createsOutput() |
Specify an output object's name, class, description and other specifications |
There are also accessors for many of the metadata entries:
timeunit() |
Accesses metadata of same name |
citation() |
Accesses metadata of same name |
documentation() |
Accesses metadata of same name |
reqdPkgs() |
Accesses metadata of same name |
inputObjects() |
Accesses metadata of same name |
outputObjects() |
Accesses metadata of same name |
Once a set of modules have been chosen, the dependency information is automatically
calculated once simInit
is run. There are several functions to assist with dependency
information:
depsEdgeList() |
Build edge list for module dependency graph |
depsGraph() |
Build a module dependency graph using igraph
|
A collection of functions that help with making modules can be found in
the suggested SpaDES.tools
package, and are summarized below.
Spatial contagion is a key phenomenon for spatially explicit simulation models.
Contagion can be modelled using discrete approaches or continuous approaches.
Several SpaDES.tools
functions assist with these:
SpaDES.tools::adj() |
An optimized (i.e., faster) version of terra::adjacent()
|
SpaDES.tools::cir() |
Identify pixels in a circle around a SpatialPoints*() object |
directionFromEachPoint() |
Fast calculation of direction and distance surfaces |
SpaDES.tools::distanceFromEachPoint() |
Fast calculation of distance surfaces |
SpaDES.tools::rings() |
Identify rings around focal cells (e.g., buffers and donuts) |
SpaDES.tools::spokes() |
Identify outward radiating spokes from initial points |
SpaDES.tools::spread() |
Contagious cellular automata |
SpaDES.tools::spread2() |
Contagious cellular automata, different algorithm, more robust |
SpaDES.tools::wrap() |
Create a torus from a grid |
Agents have several methods and functions specific to them:
SpaDES.tools::crw() |
Simple correlated random walk function |
SpaDES.tools::heading() |
Determines the heading between SpatialPoints*
|
quickPlot::makeLines() |
Makes SpatialLines object for, e.g., drawing arrows |
move() |
A meta function that can currently only take "crw" |
specificNumPerPatch() |
Initiate a specific number of agents per patch |
In addition to the vast amount of GIS operations available in R (mostly from
contributed packages such as sf
, terra
, (also sp
, raster
), maps
, maptools
and many others), we provide the following GIS-related functions:
equalExtent() |
Assess whether a list of extents are all equal |
These functions convert between reduced and mapped representations of the same data. This allows compact representation of, e.g., rasters that have many individual pixels that share identical information.
SpaDES.tools::rasterizeReduced() |
Convert reduced representation to full raster. |
Raster*
objectsWe likely will not want the default colours for every map.
Here are several helper functions to add to, set and get colours of Raster*
objects:
setColors() |
Set colours for plotting Raster* objects |
getColors() |
Get colours in a Raster* objects |
divergentColors() |
Create a colour palette with diverging colours around a middle |
It is often useful to build dummy maps with which to build simulation models before all data are available. These dummy maps can later be replaced with actual data maps.
SpaDES.tools::neutralLandscapeMap() |
Creates a random map using Gaussian random fields |
SpaDES.tools::randomPolygons() |
Creates a random polygon with specified number of classes |
SpaDES
modules will often require the existence of objects in the simList
.
These are helpers for assessing this:
checkObject() |
Check for a existence of an object within a simList |
reproducible::checkPath() |
Checks the specified filepath for formatting consistencies |
These functions are essentially skeletons and are not fully implemented. They are intended to make translations from SELES (https://www.gowlland.ca/). You must know how to use SELES for these to be useful:
agentLocation() |
Agent location |
SpaDES.tools::initiateAgents() |
Initiate agents into a SpatialPointsDataFrame
|
numAgents() |
Number of agents |
probInit() |
Probability of initiating an agent or event |
transitions() |
Transition probability |
Functions that may be useful within a SpaDES
context:
SpaDES.tools::inRange() |
Test whether a number lies within range [a,b]
|
layerNames() |
Get layer names for numerous object classes |
numLayers() |
Return number of layers |
paddedFloatToChar() |
Wrapper for padding (e.g., zeros) floating numbers to character |
Simulation caching uses the reproducible
package.
Caching can be done in a variety of ways, most of which are up to the module developer. However, the one most common usage would be to cache a simulation run. This might be useful if a simulation is very long, has been run once, and the goal is just to retrieve final results. This would be an alternative to manually saving the outputs.
See example in spades()
, achieved by using cache = TRUE
argument.
reproducible::Cache() |
Caches a function, but often accessed as argument in spades()
|
reproducible::showCache() |
Shows information about the objects in the cache |
reproducible::clearCache() |
Removes objects from the cache |
reproducible::keepCache() |
Keeps only the objects described |
A module developer can build caching into their module by creating cached versions of their functions.
Much of the underlying plotting functionality is provided by quickPlot.
There are several user-accessible plotting functions that are optimized for modularity and speed of plotting:
Commonly used:
Plot() |
The workhorse plotting function |
Simulation diagrams:
eventDiagram() |
Gantt chart representing the events in a completed simulation. |
moduleDiagram() |
Network diagram of simplified module (object) dependencies. |
objectDiagram() |
Sequence diagram of detailed object dependencies. |
Other useful plotting functions:
clearPlot() |
Helpful for resolving many errors |
clickValues() |
Extract values from a raster object at the mouse click location(s) |
clickExtent() |
Zoom into a raster or polygon map that was plotted with Plot()
|
clickCoordinates() |
Get the coordinates, in map units, under mouse click |
dev() |
Specify which device to plot on, making a non-RStudio one as default |
newPlot() |
Open a new default plotting device |
rePlot() |
Re-plots all elements of device for refreshing or moving plot |
In addition to R's file operations, we have added several here to aid in bulk loading and saving of files for simulation purposes:
loadFiles() |
Load simulation objects according to a file list |
rasterToMemory() |
Read a raster from file to RAM |
saveFiles() |
Save simulation objects according to outputs and parameters |
Several dummy modules are included for testing of functionality.
These can be found with file.path(find.package("SpaDES.core"), "sampleModules")
.
randomLandscapes |
Imports, updates, and plots several raster map layers |
caribouMovement |
A simple agent-based (a.k.a., individual-based) model |
fireSpread |
A simple model of a spatial spread process |
SpaDES
packages use the following options()
to configure behaviour:
spades.browserOnError
: If TRUE
, the default, then any
error rerun the same event with debugonce
called on it to allow editing
to be done. When that browser is continued (e.g., with 'c'), then it will save it
reparse it into the simList
and rerun the edited version. This may allow a spades
call to be recovered on error, though in many cases that may not be the correct
behaviour. For example, if the simList
gets updated inside that event in an iterative
manner, then each run through the event will cause that iteration to occur.
When this option is TRUE
, then the event will be run at least 3 times: the
first time makes the error, the second time has debugonce
and the third time
is after the error is addressed. TRUE
is likely somewhat slower.
reproducible.cachePath
: The default local directory in which to
cache simulation outputs.
Default is a temporary directory (typically /tmp/RtmpXXX/SpaDES/cache
).
spades.inputPath
: The default local directory in which to
look for simulation inputs.
Default is a temporary directory (typically /tmp/RtmpXXX/SpaDES/inputs
).
spades.debug
: The default debugging value debug
argument in spades()
. Default is TRUE
.
spades.lowMemory
: If true, some functions will use more memory
efficient (but slower) algorithms. Default FALSE
.
spades.moduleCodeChecks
: Should the various code checks be run
during simInit
. These are passed to codetools::checkUsage()
.
Default is given by the function, plus these :list(suppressParamUnused = FALSE, suppressUndefined = TRUE, suppressPartialMatchArgs = FALSE, suppressNoLocalFun = TRUE, skipWith = TRUE)
.
spades.modulePath
: The default local directory where modules
and data will be downloaded and stored.
Default is a temporary directory (typically /tmp/RtmpXXX/SpaDES/modules
).
spades.moduleRepo
: The default GitHub repository to use when
downloading modules via downloadModule
.
Default "PredictiveEcology/SpaDES-modules"
.
spades.nCompleted
: The maximum number of completed events to
retain in the completed
event queue. Default 1000L
.
spades.outputPath
: The default local directory in which to
save simulation outputs.
Default is a temporary directory (typically /tmp/RtmpXXX/SpaDES/outputs
).
spades.recoveryMode
: If this a numeric greater than 0 or TRUE, then the
discrete event simulator will take a snapshot of the objects in the simList
that might change (based on metadata outputObjects
for that module), prior to
initiating every event. This will allow the
user to be able to recover in case of an error or manual interruption (e.g., Esc
).
If this is numeric, a copy of that number of "most recent events" will be
maintained so that the user can recover and restart more than one event in the past,
i.e., redo some of the "completed" events.
Default is TRUE
, i.e., it will keep the state of the simList
at the start of the current event. This can be recovered with restartSpades
and the differences can be seen in a hidden object in the stashed simList.
There is a message which describes how to find that.
spades.switchPkgNamespaces
: Should the search path be modified
to ensure a module's required packages are listed first?
Default FALSE
to keep computational overhead down. If TRUE
,
there should be no name conflicts among package objects,
but it is much slower, especially if the events are themselves fast.
spades.tolerance
: The default tolerance value used for floating
point number comparisons. Default .Machine$double.eps^0.5
.
spades.useragent
: The default user agent to use for downloading
modules from GitHub.com. Default "https://github.com/PredictiveEcology/SpaDES"
.
Maintainer: Eliot J B McIntire [email protected] (ORCID)
Authors:
Alex M Chubaty [email protected] (ORCID)
Other contributors:
Yong Luo [email protected] [contributor]
Steve Cumming [email protected] [contributor]
Ceres Barros [email protected] (ORCID) [contributor]
His Majesty the King in Right of Canada, as represented by the Minister of Natural Resources Canada [copyright holder]
.addChangedAttr
for simList
objectsThis will evaluate which elements in the simList
object changed following
this Cached function call. It will add a named character string as an
attribute attr(x, ".Cache")$changed
, indicating which ones changed.
When this function is subsequently called again, only these changed objects
will be returned. All other simList
objects will remain unchanged.
## S4 method for signature 'simList' .addChangedAttr(object, preDigest, origArguments, ...)
## S4 method for signature 'simList' .addChangedAttr(object, preDigest, origArguments, ...)
object |
Any R object returned from a function |
preDigest |
The full, element by element hash of the input arguments to that same function,
e.g., from |
origArguments |
These are the actual arguments (i.e., the values, not the names) that
were the source for |
... |
Anything passed to methods. |
returns the object with attribute added
.addTagsToOutput
for simList
objectsSee reproducible::.addTagsToOutput()
.
## S4 method for signature 'simList' .addTagsToOutput(object, outputObjects, FUN, preDigestByClass)
## S4 method for signature 'simList' .addTagsToOutput(object, outputObjects, FUN, preDigestByClass)
object |
Any R object returned from a function |
outputObjects |
Optional character vector indicating which objects to return. This is only relevant for list, environment (or similar) objects |
FUN |
A function |
preDigestByClass |
A list, usually from |
modified object
, with attributes added
Eliot McIntire
.cacheMessage
for simList
objectsSee reproducible::.cacheMessage()
.
## S4 method for signature 'simList' .cacheMessage( object, functionName, fromMemoise = getOption("reproducible.useMemoise", TRUE), verbose = getOption("reproducible.verbose") )
## S4 method for signature 'simList' .cacheMessage( object, functionName, fromMemoise = getOption("reproducible.useMemoise", TRUE), verbose = getOption("reproducible.verbose") )
object |
Any R object returned from a function |
functionName |
A character string indicating the function name |
fromMemoise |
Logical. If |
verbose |
Numeric, -1 silent (where possible), 0 being very quiet,
1 showing more messaging, 2 being more messaging, etc.
Default is 1. Above 3 will output much more information about the internals of
Caching, which may help diagnose Caching challenges. Can set globally with an
option, e.g., |
.checkCacheRepo
for simList
objectsSee reproducible::.checkCacheRepo()
.
## S4 method for signature 'list' .checkCacheRepo(object, create = FALSE)
## S4 method for signature 'list' .checkCacheRepo(object, create = FALSE)
object |
Any R object returned from a function |
create |
Logical. If TRUE, then it will create the path for cache. |
character string representing a directory path to the cache repo
How to load various types of files in R.
This function has two roles:
to proceed with the loading of files that are in a simList
; or
as a shortcut to simInit(inputs = filelist)
.
A data.frame
with information on how to load various types of files in R,
containing the columns:
exts
: the file extension;
fun
: the function to use for files with this file extension;
package
: the package from which to load fun
.
.fileExtensions() loadFiles(sim, filelist, ...) ## S4 method for signature 'simList,missing' loadFiles(sim, filelist, ...) ## S4 method for signature 'missing,ANY' loadFiles(sim, filelist, ...) ## S4 method for signature 'missing,missing' loadFiles(sim, filelist, ...) .saveFileExtensions()
.fileExtensions() loadFiles(sim, filelist, ...) ## S4 method for signature 'simList,missing' loadFiles(sim, filelist, ...) ## S4 method for signature 'missing,ANY' loadFiles(sim, filelist, ...) ## S4 method for signature 'missing,missing' loadFiles(sim, filelist, ...) .saveFileExtensions()
sim |
|
filelist |
|
... |
Additional arguments. |
data.frame
of file extension, package, and function mappings
the modified sim
, invisibly.
data.frame
Generally not intended to be used by users.
Eliot McIntire and Alex Chubaty
library(SpaDES.core) # Load random maps included with package filelist <- data.frame( files = dir(getMapPath(tempdir()), full.names = TRUE), functions = "rasterToMemory", package = "SpaDES.core" ) sim1 <- loadFiles(filelist = filelist) # loads all the maps to sim1 simList # Second, more sophisticated. All maps loaded at time = 0, and the last one is reloaded # at time = 10 and 20 (via "intervals"). # Also, pass the single argument as a list to all functions... # specifically, when add "native = TRUE" as an argument to the raster function files <- dir(getMapPath(tempdir()), full.names = TRUE) arguments <- I(rep(list(lyrs = 1), length(files))) filelist <- data.frame( files = files, functions = "terra::rast", objectName = NA, arguments = arguments, loadTime = 0, intervals = c(rep(NA, length(files)-1), 10) ) sim2 <- loadFiles(filelist = filelist) # only does the time = 0 loading; see next end(sim2) <- 10 sim2 <- spades(sim2) # loads the object at time 10 # if we extend the end time and continue running, it will load an object scheduled # at time = 10, and it will also schedule a new object loading at 20 because # interval = 10 end(sim2) <- 20 sim2 <- spades(sim2) # loads the percentPine map 2 more times, once at 10, once at 20
library(SpaDES.core) # Load random maps included with package filelist <- data.frame( files = dir(getMapPath(tempdir()), full.names = TRUE), functions = "rasterToMemory", package = "SpaDES.core" ) sim1 <- loadFiles(filelist = filelist) # loads all the maps to sim1 simList # Second, more sophisticated. All maps loaded at time = 0, and the last one is reloaded # at time = 10 and 20 (via "intervals"). # Also, pass the single argument as a list to all functions... # specifically, when add "native = TRUE" as an argument to the raster function files <- dir(getMapPath(tempdir()), full.names = TRUE) arguments <- I(rep(list(lyrs = 1), length(files))) filelist <- data.frame( files = files, functions = "terra::rast", objectName = NA, arguments = arguments, loadTime = 0, intervals = c(rep(NA, length(files)-1), 10) ) sim2 <- loadFiles(filelist = filelist) # only does the time = 0 loading; see next end(sim2) <- 10 sim2 <- spades(sim2) # loads the object at time 10 # if we extend the end time and continue running, it will load an object scheduled # at time = 10, and it will also schedule a new object loading at 20 because # interval = 10 end(sim2) <- 20 sim2 <- spades(sim2) # loads the percentPine map 2 more times, once at 10, once at 20
simList
in a nested listThis is recursive, so it will find the all simList
s even if they are deeply nested.
.findSimList(x)
.findSimList(x)
x |
any object, used here only when it is a list with at least one
|
Guess package of a function
.guessPkgFun(bsf)
.guessPkgFun(bsf)
bsf |
character. A function name |
character. The package and function name as "pkg::bsf"
.parseElems
for simList
class objects## S4 method for signature 'simList' .parseElems(tmp, elems, envir)
## S4 method for signature 'simList' .parseElems(tmp, elems, envir)
tmp |
A evaluated object |
elems |
A character string to be parsed |
envir |
An environment |
An object, parsed from a character string and an environment.
simList
Takes a snapshot of simList
objects.
## S4 method for signature 'simList' .preDigestByClass(object)
## S4 method for signature 'simList' .preDigestByClass(object)
object |
Any R object returned from a function |
See reproducible::.preDigestByClass()
.
character vector corresponding to the names of objects stored in the .xData
slot
Eliot McIntire
reproducible::.preDigestByClass
.prepareOutput
for simList
objectsSee reproducible::.prepareOutput()
.
## S4 method for signature 'simList' .prepareOutput(object, cachePath, ...)
## S4 method for signature 'simList' .prepareOutput(object, cachePath, ...)
object |
Any R object returned from a function |
cachePath |
A repository used for storing cached objects.
This is optional if |
... |
Anything passed to methods. |
the modified object
SpaDES.core
variable to switch between quick and robust checkingA variable that can be use by module developers and model users to switch between
a quick check of functions like downloadData
, Cache.
The module developer must actually use this in their code.
.quickCheck
.quickCheck
An object of class logical
of length 1.
Generate a vector of random alphanumeric strings each of an arbitrary length.
.rndstr(n = 1, len = 8) rndstr(n, len, characterFirst) ## S4 method for signature 'numeric,numeric,logical' rndstr(n, len, characterFirst) ## S4 method for signature 'numeric,numeric,missing' rndstr(n, len) ## S4 method for signature 'numeric,missing,logical' rndstr(n, characterFirst) ## S4 method for signature 'missing,numeric,logical' rndstr(len, characterFirst) ## S4 method for signature 'numeric,missing,missing' rndstr(n) ## S4 method for signature 'missing,numeric,missing' rndstr(len) ## S4 method for signature 'missing,missing,logical' rndstr(characterFirst) ## S4 method for signature 'missing,missing,missing' rndstr(n, len, characterFirst)
.rndstr(n = 1, len = 8) rndstr(n, len, characterFirst) ## S4 method for signature 'numeric,numeric,logical' rndstr(n, len, characterFirst) ## S4 method for signature 'numeric,numeric,missing' rndstr(n, len) ## S4 method for signature 'numeric,missing,logical' rndstr(n, characterFirst) ## S4 method for signature 'missing,numeric,logical' rndstr(len, characterFirst) ## S4 method for signature 'numeric,missing,missing' rndstr(n) ## S4 method for signature 'missing,numeric,missing' rndstr(len) ## S4 method for signature 'missing,missing,logical' rndstr(characterFirst) ## S4 method for signature 'missing,missing,missing' rndstr(n, len, characterFirst)
n |
Number of strings to generate (default 1). Will attempt to coerce to integer value. |
len |
Length of strings to generate (default 8). Will attempt to coerce to integer value. |
characterFirst |
Logical, if |
Character vector of random strings.
Alex Chubaty and Eliot McIntire
set.seed(11) rndstr() rndstr(len = 10) rndstr(characterFirst = FALSE) rndstr(n = 5, len = 10) rndstr(n = 5) rndstr(n = 5, characterFirst = TRUE) rndstr(len = 10, characterFirst = TRUE) rndstr(n = 5, len = 10, characterFirst = TRUE)
set.seed(11) rndstr() rndstr(len = 10) rndstr(characterFirst = FALSE) rndstr(n = 5, len = 10) rndstr(n = 5) rndstr(n = 5, characterFirst = TRUE) rndstr(len = 10, characterFirst = TRUE) rndstr(n = 5, len = 10, characterFirst = TRUE)
.robustDigest
for simList
objectsThis is intended to be used within the Cache
function, but can be used to evaluate what
a simList
would look like once it is converted to a repeatably digestible object.
## S4 method for signature 'simList' .robustDigest(object, .objects, length, algo, quick, classOptions)
## S4 method for signature 'simList' .robustDigest(object, .objects, length, algo, quick, classOptions)
object |
an object to digest. |
.objects |
Character vector of objects to be digested. This is only applicable if there is a list, environment (or similar) with named objects within it. Only this/these objects will be considered for caching, i.e., only use a subset of the list, environment or similar objects. In the case of nested list-type objects, this will only be applied outermost first. |
length |
Numeric. If the element passed to Cache is a |
algo |
The algorithms to be used; currently available choices are
|
quick |
Logical or character. If |
classOptions |
Optional list. This will pass into |
See reproducible::.robustDigest()
.
This method strips out stuff from a simList
class object that would make it otherwise not
reproducibly digestible between sessions, operating systems, or machines.
This will likely still not allow identical digest results across R versions.
Eliot McIntire
.tagsByClass
for simList
objectsSee reproducible::.tagsByClass()
. Adds current moduleName
,
eventType
, eventTime
, and function:spades
as userTags
.
## S4 method for signature 'simList' .tagsByClass(object)
## S4 method for signature 'simList' .tagsByClass(object)
object |
Any R object returned from a function |
Eliot McIntire
.wrap
and .unwrap
Methods for .wrap
and .unwrap
## S3 method for class 'simList' .wrap( obj, cachePath, preDigest, drv = getOption("reproducible.drv", NULL), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), outputObjects = NULL, ... ) ## S3 method for class '.simDeps' .wrap(obj, ...) ## S3 method for class '.simDeps' .unwrap(obj, ...) ## S3 method for class '.moduleDeps' .wrap(obj, ...) ## S3 method for class '.moduleDeps' .unwrap(obj, ...) ## S3 method for class 'simList' .unwrap( obj, cachePath, cacheId, drv = getOption("reproducible.drv", NULL), conn = getOption("reproducible.conn", NULL), ... )
## S3 method for class 'simList' .wrap( obj, cachePath, preDigest, drv = getOption("reproducible.drv", NULL), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), outputObjects = NULL, ... ) ## S3 method for class '.simDeps' .wrap(obj, ...) ## S3 method for class '.simDeps' .unwrap(obj, ...) ## S3 method for class '.moduleDeps' .wrap(obj, ...) ## S3 method for class '.moduleDeps' .unwrap(obj, ...) ## S3 method for class 'simList' .unwrap( obj, cachePath, cacheId, drv = getOption("reproducible.drv", NULL), conn = getOption("reproducible.conn", NULL), ... )
obj |
Any arbitrary R object. |
cachePath |
A repository used for storing cached objects.
This is optional if |
preDigest |
The list of |
drv |
an object that inherits from |
conn |
A |
verbose |
Numeric, -1 silent (where possible), 0 being very quiet,
1 showing more messaging, 2 being more messaging, etc.
Default is 1. Above 3 will output much more information about the internals of
Caching, which may help diagnose Caching challenges. Can set globally with an
option, e.g., |
outputObjects |
Optional character vector indicating which objects to return. This is only relevant for list, environment (or similar) objects |
... |
Other arguments. Can be in the form of |
cacheId |
An optional character vector describing the |
The same object as passed into the function, but dealt with so that it can be saved to disk.
simList
but with subset of objectsThis is copies the non-object components of a simList
(e.g., events, etc.)
then selects only the objects listed in i
using Copy(mget(i, envir(sim)))
and adds them to the returned simList
.
## S4 method for signature 'simList,character,ANY' x[i, j, ..., drop = TRUE]
## S4 method for signature 'simList,character,ANY' x[i, j, ..., drop = TRUE]
x |
A |
i |
A character vector of objects to select. |
j |
Not used. |
... |
Not used. |
drop |
Not used. |
The [
method returns a complete simList
class with all the slots
copied from the original, but only the named objects in i
are returned.
Eliot McIntire
s <- simInit() s$a <- 1 s$b <- 2 s$d <- 3 s[c("a", "d")] # a simList with only 2 objects
s <- simInit() s$a <- 1 s$b <- 2 s$d <- 3 s[c("a", "d")] # a simList with only 2 objects
simList
objectsThis function removes a few attributes that are added internally
by SpaDES.core and are not relevant to the all.equal
.
One key element removed is any time stamps, as these are guaranteed to be different.
A possibly very important argument to pass to the ...
is check.attributes = FALSE
which will allow successful comparisons of many objects that might have pointers.
## S3 method for class 'simList' all.equal(target, current, ...)
## S3 method for class 'simList' all.equal(target, current, ...)
target |
R object. |
current |
other R object, to be compared with |
... |
further arguments for different methods, notably the following two, for numerical comparison: |
.plots
module parameterThis will do all the various tests needed to determine whether
plotting of one sort or another will occur.
Testing any of the types as listed in Plots()
argument types
.
Only the first 3 letters of the type are required.
anyPlotting(.plots)
anyPlotting(.plots)
.plots |
Usually will be the |
logical of length 1
Ordinary base lists and vectors do not retain their attributes when subsetted or appended. This function appends items to a list while preserving the attributes of items in the list (but not of the list itself).
append_attr(x, y) ## S4 method for signature 'list,list' append_attr(x, y)
append_attr(x, y) ## S4 method for signature 'list,list' append_attr(x, y)
x , y
|
A |
Similar to updateList
but does not require named lists.
An updated list
with attributes.
Alex Chubaty and Eliot McIntire
tmp1 <- list("apple", "banana") tmp1 <- lapply(tmp1, `attributes<-`, list(type = "fruit")) tmp2 <- list("carrot") tmp2 <- lapply(tmp2, `attributes<-`, list(type = "vegetable")) append_attr(tmp1, tmp2) rm(tmp1, tmp2)
tmp1 <- list("apple", "banana") tmp1 <- lapply(tmp1, `attributes<-`, list(type = "fruit")) tmp2 <- list("carrot") tmp2 <- lapply(tmp2, `attributes<-`, list(type = "vegetable")) append_attr(tmp1, tmp2) rm(tmp1, tmp2)
data.table::rbindlist
This simply sets defaults to fill = TRUE
, and use.names = TRUE
.
bindrows(...)
bindrows(...)
... |
one or more |
a data.table
object
Looks in the remote repo
for a module named name
.
checkModule(name, repo) ## S4 method for signature 'character,character' checkModule(name, repo) ## S4 method for signature 'character,missing' checkModule(name)
checkModule(name, repo) ## S4 method for signature 'character,character' checkModule(name, repo) ## S4 method for signature 'character,missing' checkModule(name)
name |
Character string giving the module name. |
repo |
GitHub repository name.
Default is |
a character vector of module file paths (invisibly).
Eliot McIntire and Alex Chubaty
Looks the module path for a module named name
, and checks for existence
of all essential module files listed below.
checkModuleLocal(name, path, version) ## S4 method for signature 'character,character,character' checkModuleLocal(name, path, version) ## S4 method for signature 'character,ANY,ANY' checkModuleLocal(name, path, version)
checkModuleLocal(name, path, version) ## S4 method for signature 'character,character,character' checkModuleLocal(name, path, version) ## S4 method for signature 'character,ANY,ANY' checkModuleLocal(name, path, version)
name |
Character string giving the module name. |
path |
Local path to modules directory.
Default is specified by the global option |
version |
Character specifying the desired module version. |
‘data/CHECKSUMS.txt’
‘name.R’
Logical indicating presence of the module (invisibly).
Alex Chubaty
Will compare default in spadesOptions to getPaths ... these will be same if use
has not set them. For such case, use ".". They will be different if the user has
used setPaths
. If that is the case, then use getPaths()[["modulePath"]]
checkModulePath()
checkModulePath()
objects
slot of a
simList
objectCheck that a named object exists in the provide simList
environment slot,
and optionally has desired attributes.
checkObject(sim, name, object, layer, ...) ## S4 method for signature 'simList,ANY,ANY' checkObject(sim, name, object, layer, ...) ## S4 method for signature 'simList,character,missing' checkObject(sim, name, object, layer, ...) ## S4 method for signature 'missing,ANY,ANY' checkObject(sim, name, object, layer, ...)
checkObject(sim, name, object, layer, ...) ## S4 method for signature 'simList,ANY,ANY' checkObject(sim, name, object, layer, ...) ## S4 method for signature 'simList,character,missing' checkObject(sim, name, object, layer, ...) ## S4 method for signature 'missing,ANY,ANY' checkObject(sim, name, object, layer, ...)
sim |
A |
name |
A character string specifying the name of an object to be checked. |
object |
An object. This is mostly used internally, or with layer, because it will fail if the object does not exist. |
layer |
Character string, specifying a layer name in a Raster, if the
|
... |
Additional arguments. Not implemented. |
Invisibly return TRUE
indicating object exists; FALSE
if not.
Alex Chubaty and Eliot McIntire
sim <- simInit() sim$a <- 1 sim$b <- list(d = 1) sim$r <- terra::rast(terra::ext(0,2,0,2), res = 1, vals = 2) sim$s <- c(sim$r, terra::rast(terra::ext(0,2,0,2), res = 1, vals = 3)) names(sim$s) <- c("r1", "r2") # give layer names (checkObject(sim, name = "a")) # TRUE (checkObject(sim, name = "b", layer = "d")) # TRUE (checkObject(sim, name = "d")) # FALSE (checkObject(sim, name = "r")) # TRUE (checkObject(sim, object = sim$s)) # TRUE (checkObject(sim, object = sim$s, layer = "r1")) # TRUE
sim <- simInit() sim$a <- 1 sim$b <- list(d = 1) sim$r <- terra::rast(terra::ext(0,2,0,2), res = 1, vals = 2) sim$s <- c(sim$r, terra::rast(terra::ext(0,2,0,2), res = 1, vals = 3)) names(sim$s) <- c("r1", "r2") # give layer names (checkObject(sim, name = "a")) # TRUE (checkObject(sim, name = "b", layer = "d")) # TRUE (checkObject(sim, name = "d")) # FALSE (checkObject(sim, name = "r")) # TRUE (checkObject(sim, object = sim$s)) # TRUE (checkObject(sim, object = sim$s, layer = "r1")) # TRUE
Checks that all parameters passed are used in a module, and that all parameters used in a module are passed.
checkParams(sim, coreParams, ...) ## S4 method for signature 'simList,list' checkParams(sim, coreParams, ...)
checkParams(sim, coreParams, ...) ## S4 method for signature 'simList,list' checkParams(sim, coreParams, ...)
sim |
A |
coreParams |
List of default core parameters. |
... |
Additional arguments. Not implemented. |
Invisibly return TRUE
indicating object exists; FALSE
if not.
Sensible messages are produced identifying missing parameters.
Alex Chubaty
Save and reload the current state of the simulation, including the state of the random number generator, by scheduling checkpoint events.
checkpointFile(sim) ## S4 method for signature 'simList' checkpointFile(sim) checkpointFile(sim) <- value ## S4 replacement method for signature 'simList' checkpointFile(sim) <- value checkpointInterval(sim) ## S4 method for signature 'simList' checkpointInterval(sim) checkpointInterval(sim) <- value ## S4 replacement method for signature 'simList' checkpointInterval(sim) <- value doEvent.checkpoint(sim, eventTime, eventType, debug = FALSE) checkpointLoad(file) .checkpointSave(sim, file)
checkpointFile(sim) ## S4 method for signature 'simList' checkpointFile(sim) checkpointFile(sim) <- value ## S4 replacement method for signature 'simList' checkpointFile(sim) <- value checkpointInterval(sim) ## S4 method for signature 'simList' checkpointInterval(sim) checkpointInterval(sim) <- value ## S4 replacement method for signature 'simList' checkpointInterval(sim) <- value doEvent.checkpoint(sim, eventTime, eventType, debug = FALSE) checkpointLoad(file) .checkpointSave(sim, file)
sim |
A |
value |
The parameter value to be set (in the corresponding |
eventTime |
A numeric specifying the time of the next event. |
eventType |
A character string specifying the type of event: one of
either |
debug |
Optional logical flag determines whether |
file |
The checkpoint file. |
Returns the modified simList
object.
Checkpoint files are intended to be used locally, and do not invoke the simulation archiving tools to bundle and subsequently extract simulation files (e.g., file-backed rasters).
RNG save code adapted from: http://www.cookbook-r.com/Numbers/Saving_the_state_of_the_random_number_generator/ and https://stackoverflow.com/q/13997444/1380598
Alex Chubaty
Other functions to access elements of a 'simList' object:
.addDepends()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
Verify (and optionally write) checksums for data files in a module's
‘data/’ subdirectory. The file ‘data/CHECKSUMS.txt’ contains the
expected checksums for each data file.
Checksums are computed using reproducible:::.digest
, which is simply a
wrapper around digest::digest
.
checksums(module, path, ...)
checksums(module, path, ...)
module |
Character string giving the name of the module. |
path |
Character string giving the path to the module directory. |
... |
Passed to |
Modules may require data that for various reasons cannot be distributed with the module source code. In these cases, the module developer should ensure that the module downloads and extracts the data required. It is useful to not only check that the data files exist locally but that their checksums match those expected.
In version 1.2.0 and earlier, two checksums per file were required because of differences in the checksum hash values on Windows and Unix-like platforms. Recent versions use a different (faster) algorithm and only require one checksum value per file. To update your ‘CHECKSUMS.txt’ files using the new algorithm:
specify your module (moduleName <- "my_module"
);
use a temporary location to ensure all modules get fresh copies of the data
(tmpdir <- file.path(tempdir(), "SpaDES_modules")
);
download your module's data to the temp dir (downloadData(moduleName, tmpdir)
);
initialize a dummy simulation to ensure any 'data prep' steps in the
.inputObjects
section are run (simInit(modules = moduleName)
);
recalculate your checksums and overwrite the file
(checksums(moduleName, tmpdir, write = TRUE)
);
copy the new checksums file to your working module directory
(the one not in the temp dir)
(file.copy(from = file.path(tmpdir, moduleName, 'data', 'CHECKSUMS.txt'), to = file.path('path/to/my/moduleDir', moduleName, 'data', 'CHECKSUMS.txt'), overwrite = TRUE)
).
SpaDES
modulesThis is a wrapper around utils::citation()
for cases with package
is a
character
string. Otherwise, it takes a simList
.
citation(package, lib.loc = NULL, auto = NULL, module = character()) ## S4 method for signature 'simList' citation(package, lib.loc = NULL, auto = NULL, module = character()) ## S4 method for signature 'character' citation(package, lib.loc = NULL, auto = NULL, module = character())
citation(package, lib.loc = NULL, auto = NULL, module = character()) ## S4 method for signature 'simList' citation(package, lib.loc = NULL, auto = NULL, module = character()) ## S4 method for signature 'character' citation(package, lib.loc = NULL, auto = NULL, module = character())
package |
For compatibility with |
lib.loc |
a character vector with path names of R libraries, or
the directory containing the source for |
auto |
a logical indicating whether the default citation
auto-generated from the package ‘DESCRIPTION’ metadata should
be used or not, or |
module |
Optional character string indicating which module params should come from. |
The citation information for a SpaDES module.
Based on https://stackoverflow.com/a/5158978/1380598.
classFilter(x, include, exclude, envir) ## S4 method for signature 'character,character,character,environment' classFilter(x, include, exclude, envir) ## S4 method for signature 'character,character,character,missing' classFilter(x, include, exclude) ## S4 method for signature 'character,character,missing,environment' classFilter(x, include, envir) ## S4 method for signature 'character,character,missing,missing' classFilter(x, include)
classFilter(x, include, exclude, envir) ## S4 method for signature 'character,character,character,environment' classFilter(x, include, exclude, envir) ## S4 method for signature 'character,character,character,missing' classFilter(x, include, exclude) ## S4 method for signature 'character,character,missing,environment' classFilter(x, include, envir) ## S4 method for signature 'character,character,missing,missing' classFilter(x, include)
x |
Character vector of object names to filter, possibly from |
include |
Class(es) to include, as a character vector. |
exclude |
Optional class(es) to exclude, as a character vector. |
envir |
The environment ins which to search for objects. Default is the calling environment. |
Vector of object names matching the class filter.
inherits()
is used internally to check the object class,
which can, in some cases, return results inconsistent with is
.
See https://stackoverflow.com/a/27923346/1380598.
These (known) cases are checked manually and corrected.
Alex Chubaty
## from local (e.g., function) environment local({ e <- environment() a <- list(1:10) # class `list` b <- letters # class `character` d <- stats::runif(10) # class `numeric` f <- sample(1L:10L) # class `numeric`, `integer` g <- lm( jitter(d) ~ d ) # class `lm` h <- glm( jitter(d) ~ d ) # class `lm`, `glm` classFilter(ls(), include=c("character", "list"), envir = e) classFilter(ls(), include = "numeric", envir = e) classFilter(ls(), include = "numeric", exclude = "integer", envir = e) classFilter(ls(), include = "lm", envir = e) classFilter(ls(), include = "lm", exclude = "glm", envir = e) rm(a, b, d, e, f, g, h) }) ## from another environment (can be omitted if .GlobalEnv) e = new.env(parent = emptyenv()) e$a <- list(1:10) # class `list` e$b <- letters # class `character` e$d <- stats::runif(10) # class `numeric` e$f <- sample(1L:10L) # class `numeric`, `integer` e$g <- lm( jitter(e$d) ~ e$d ) # class `lm` e$h <- glm( jitter(e$d) ~ e$d ) # class `lm`, `glm` classFilter(ls(e), include=c("character", "list"), envir = e) classFilter(ls(e), include = "numeric", envir = e) classFilter(ls(e), include = "numeric", exclude = "integer", envir = e) classFilter(ls(e), include = "lm", envir = e) classFilter(ls(e), include = "lm", exclude = "glm", envir = e) rm(a, b, d, f, g, h, envir = e) rm(e)
## from local (e.g., function) environment local({ e <- environment() a <- list(1:10) # class `list` b <- letters # class `character` d <- stats::runif(10) # class `numeric` f <- sample(1L:10L) # class `numeric`, `integer` g <- lm( jitter(d) ~ d ) # class `lm` h <- glm( jitter(d) ~ d ) # class `lm`, `glm` classFilter(ls(), include=c("character", "list"), envir = e) classFilter(ls(), include = "numeric", envir = e) classFilter(ls(), include = "numeric", exclude = "integer", envir = e) classFilter(ls(), include = "lm", envir = e) classFilter(ls(), include = "lm", exclude = "glm", envir = e) rm(a, b, d, e, f, g, h) }) ## from another environment (can be omitted if .GlobalEnv) e = new.env(parent = emptyenv()) e$a <- list(1:10) # class `list` e$b <- letters # class `character` e$d <- stats::runif(10) # class `numeric` e$f <- sample(1L:10L) # class `numeric`, `integer` e$g <- lm( jitter(e$d) ~ e$d ) # class `lm` e$h <- glm( jitter(e$d) ~ e$d ) # class `lm`, `glm` classFilter(ls(e), include=c("character", "list"), envir = e) classFilter(ls(e), include = "numeric", envir = e) classFilter(ls(e), include = "numeric", exclude = "integer", envir = e) classFilter(ls(e), include = "lm", envir = e) classFilter(ls(e), include = "lm", exclude = "glm", envir = e) rm(a, b, d, f, g, h, envir = e) rm(e)
clearCache
for simList
objectsThis will take the cachePath(object)
and pass
## S4 method for signature 'simList' clearCache( x, userTags = character(), after = NULL, before = NULL, fun = NULL, cacheId = NULL, ask = getOption("reproducible.ask"), useCloud = FALSE, cloudFolderID = getOption("reproducible.cloudFolderID", NULL), drv = getDrv(getOption("reproducible.drv", NULL)), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), ... ) ## S4 method for signature 'simList' showCache( x, userTags = character(), after = NULL, before = NULL, fun = NULL, cacheId = NULL, drv = getDrv(getOption("reproducible.drv", NULL)), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), ... ) ## S4 method for signature 'simList' keepCache( x, userTags = character(), after = NULL, before = NULL, ask = getOption("reproducible.ask"), drv = getDrv(getOption("reproducible.drv", NULL)), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), ... )
## S4 method for signature 'simList' clearCache( x, userTags = character(), after = NULL, before = NULL, fun = NULL, cacheId = NULL, ask = getOption("reproducible.ask"), useCloud = FALSE, cloudFolderID = getOption("reproducible.cloudFolderID", NULL), drv = getDrv(getOption("reproducible.drv", NULL)), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), ... ) ## S4 method for signature 'simList' showCache( x, userTags = character(), after = NULL, before = NULL, fun = NULL, cacheId = NULL, drv = getDrv(getOption("reproducible.drv", NULL)), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), ... ) ## S4 method for signature 'simList' keepCache( x, userTags = character(), after = NULL, before = NULL, ask = getOption("reproducible.ask"), drv = getDrv(getOption("reproducible.drv", NULL)), conn = getOption("reproducible.conn", NULL), verbose = getOption("reproducible.verbose"), ... )
x |
A simList or a directory containing a valid Cache repository. Note:
For compatibility with |
userTags |
Character vector. If used, this will be used in place of the
|
after |
A time (POSIX, character understandable by data.table). Objects cached after this time will be shown or deleted. |
before |
A time (POSIX, character understandable by data.table). Objects cached before this time will be shown or deleted. |
fun |
An optional character vector describing the function name to extract. Only functions with this/these functions will be returned. |
cacheId |
An optional character vector describing the |
ask |
Logical. If |
useCloud |
Logical. If |
cloudFolderID |
A googledrive dribble of a folder, e.g., using |
drv |
an object that inherits from |
conn |
A |
verbose |
Numeric, -1 silent (where possible), 0 being very quiet,
1 showing more messaging, 2 being more messaging, etc.
Default is 1. Above 3 will output much more information about the internals of
Caching, which may help diagnose Caching challenges. Can set globally with an
option, e.g., |
... |
Other arguments. Can be in the form of |
A data.table
object showing the subset of items in the cache, located at cachePath
of the sim
object, if sim
is provided, or located in cachePath
.
For clearCache
(invoked for its side effect of clearing objects matching userTags
, or those
between after
or before
), the returned data.table
shows the removed items (invisibly).
EXPERIMENTAL – USE WITH CAUTION. This function attempts to convert a
SpaDES module to the closest rendition of the same functionality, but in an
R package. The main change is that instead of SpaDES.core
parsing the functions
using custom parsing tools, it will use pkgload::load_all
on the package functions.
These
convertToPackage( module = NULL, path = getOption("spades.modulePath"), buildDocuments = TRUE )
convertToPackage( module = NULL, path = getOption("spades.modulePath"), buildDocuments = TRUE )
module |
Character string of module name, without path |
path |
Character string of |
buildDocuments |
A logical. If |
convertToPackage
will:
move any functions that were defined within the main module file
(moduleName.R
) into the R folder, with the same name, but ending with Fns.R
;
keep the defineModule(...)
function call with all the metadata in
the same file, moduleName.R
, but with all other content removed,
i.e., only the defineModule(...)
will be here.
build documentation from all the roxygen2 tags
places one roxygen2 tag, @export
in front of the doEvent.moduleName
function, so that the function can be found by SpaDES.core
All other functions will be kept "private", i.e., not exported, unless
the user manually adds @export
, as per a normal package
will make a DESCRIPTION
file from the SpaDES module metadata
will make a NAMESPACE
file from the roxygen2 tags (e.g., @export
)
A user can continue to use the module code as before, i.e., by editing it and
putting browser()
etc. It will be parsed during simInit
. Because the functions
are "in a package", they are automatically namespaced with each other, so that
when you want to use a function from that package, there is no need to put a
prefix with the package name.
This function does not install anything (e.g., devtools::install
). After
running this function, simInit
will automatically detect that this is now
a package and will load the functions (via pkgload::load_all
) from the source files.
This will have the effect that it emulates the "non-package" behaviour of a
SpaDES module exactly. After running this function, current tests show no
impact on module behaviour, other than event-level and module-level Caching will show
changes and will be rerun. Function-level Caching appears unaffected.
In other words, this should cause no changes to running the module code via
simInit
and spades
.
This function will create
and fill a minimal DESCRIPTION
file. This will leave the defineModule
function call as the only code in the main module file. This defineModule
and a doEvent.xxx
are the only 2 elements that are required for an R
package to be considered a SpaDES module. With these changes, the module should
still function normally, but will be able to act like an
R package, e.g., for writing function documentation with roxygen2
,
using the testthat
infrastructure, etc.
This function is intended to be run once for a module that was created using
the "standard" SpaDES module structure (e.g., from a newModule
call). There
is currently no way to "revert" the changes from R (though it can be done using
version control utilities if all files are under version control, e.g., GitHub).
Currently SpaDES.core
identifies a module as being a package if it has
a DESCRIPTION
file, or if it has been installed to the .libPaths()
e.g., via devtools::install
or the like. So one can simply remove the
package from .libPaths
and delete the DESCRIPTION
file and
SpaDES.core
will treat it as a normal module.
Invoked for its side effects. There will be a new or modified
DESCRIPTION
file in the root directory of the module. Any functions that
were in the main module script (i.e., the .R file whose filename is the name of
the module and is in the root directory of the module) will be moved to individual
.R
files in the R
folder. Any function with a dot prefix will have the
dot removed in its respective filename, but the function name is unaffected.
Currently, SpaDES.core
does not install the package under any circumstances.
It will load it via pkgdown::load_all
, and optionally (option("spades.moduleDocument" = TRUE)
)
build documentation via roxygen2::roxygenise
within the simInit
call.
This means that any modifications to source code
will be read in during the simInit
call, as is the practice when a module
is not a package.
invoked for the side effect of converting a module to a package
Currently, this is not a reversible process. We recommend trying one module at
a time, running your code. If all seems to work, then great. Commit the changes.
If things don't seem to work, then revert the changes and continue on as before.
Ideally, file a bug report on the SpaDES.core
GitHub.com pages.
Currently
The only function that will be exported by default is the doEvent.xxx
,
where xxx
is the module name. If any other module is to be exported, it must
be explicitly exported with e.g., @export
, and then building the NAMESPACE
file, e.g., via devtools::document(moduleRootPath)
. NOTE: as long as all
the functions are being used inside each other, and they all can be traced back
to a call in doEvent.xxx
, then there is no need to export anything else.
The DESCRIPTION
file that is created (destroying any existing DESCRIPTION
file) with this function will have
several elements that a user may wish to change. Notably, all packages that were
in reqdPkgs
in the SpaDES module metadata will be in the Imports
section of the DESCRIPTION
. To accommodate the need to see these functions,
a new R script, imports.R
will be created with @import
for each
package in reqdPkgs
of the module metadata. However, if a module already has used
@importFrom
for importing a function from a package, then the generic
@import
will be omitted for that (those) package(s).
So, a user should likely follow standard R package
best practices and use @importFrom
to identify the specific functions that
are required within external packages, thereby limiting function name collisions
(and the warnings that come with them).
Other elements of a standard DESCRIPTION
file that will be missing or possibly
inappropriately short are Title
, Description
, URL
,
BugReports
.
There is no need to "install" the source code as a package because simInit
will load it on the fly. But, there may be reasons to install it, e.g., to have
access to individual functions, help manual, running tests etc. To do this,
simply use the devtools::install(pathToModuleRoot)
. Even if it is installed,
simInit
will nevertheless run pkgload::load_all
to ensure the
spades
call will be using the current source code.
if (requireNamespace("ggplot2") && requireNamespace("pkgload") ) { tmpdir <- tempdir2() newModule("test", tmpdir, open = FALSE) convertToPackage("test", path = tmpdir) pkgload::load_all(file.path(tmpdir, "test")) pkgload::unload("test") }
if (requireNamespace("ggplot2") && requireNamespace("pkgload") ) { tmpdir <- tempdir2() newModule("test", tmpdir, open = FALSE) convertToPackage("test", path = tmpdir) pkgload::load_all(file.path(tmpdir, "test")) pkgload::unload("test") }
simList
class objectsBecause a simList
works with an environment to hold all objects,
all objects within that slot are pass-by-reference.
That means it is not possible to simply copy an object with an assignment operator:
the two objects will share the same objects.
As one simList
object changes so will the other.
When this is not the desired behaviour, use this function.
## S4 method for signature 'simList' Copy(object, objects, queues, modules, ...)
## S4 method for signature 'simList' Copy(object, objects, queues, modules, ...)
object |
An R object (likely containing environments) or an environment. |
objects |
Whether the objects contained within the |
queues |
Logical. Should the events queues ( |
modules |
Logical. Should list of modules be copied. |
... |
Only used for custom Methods |
simList
objects can contain a lot of information, much of which could be
in pass-by-reference objects (e.g., data.table
class), and objects that are
file-backed, such as some Raster*
-class objects. For all the objects that
are file-backed, it is likely very important to give unique file-backed
directories. This should be passed here, which gets passed on to the many methods
of Copy
in reproducible
.
a copy of object
uses capital C, to limit confusion with e.g., data.table::copy()
.
Eliot McIntire
Create a copy of an existing module
copyModule(from, to, path, ...) ## S4 method for signature 'character,character,character' copyModule(from, to, path, ...) ## S4 method for signature 'character,character,missing' copyModule(from, to, path, ...)
copyModule(from, to, path, ...) ## S4 method for signature 'character,character,character' copyModule(from, to, path, ...) ## S4 method for signature 'character,character,missing' copyModule(from, to, path, ...)
from |
The name of the module to copy. |
to |
The name of the copy. |
path |
The path to a local module directory. Defaults to the path set by
the |
... |
Additional arguments to |
Invisible logical indicating success (TRUE
) or failure (FALSE
).
Alex Chubaty
Used to specify an output object's name, class, description and other specifications.
createsOutput(objectName, objectClass, desc, ...) ## S4 method for signature 'ANY,ANY,ANY' createsOutput(objectName, objectClass, desc, ...) ## S4 method for signature 'character,character,character' createsOutput(objectName, objectClass, desc, ...)
createsOutput(objectName, objectClass, desc, ...) ## S4 method for signature 'ANY,ANY,ANY' createsOutput(objectName, objectClass, desc, ...) ## S4 method for signature 'character,character,character' createsOutput(objectName, objectClass, desc, ...)
objectName |
Character string to define the output object's name. |
objectClass |
Character string to specify the output object's class. |
desc |
Text string providing a brief description of the output object.
If there are extra spaces or carriage returns, these will be stripped,
allowing for multi-line character strings without using |
... |
Other specifications of the output object. |
A data.frame
suitable to be passed to outputObjects
in
a module's metadata.
Yong Luo
outputObjects <- bindrows( createsOutput(objectName = "outputObject1", objectClass = "character", desc = "this is for example"), createsOutput(objectName = "outputObject2", objectClass = "numeric", desc = "this is for example", otherInformation = "I am the second output object") )
outputObjects <- bindrows( createsOutput(objectName = "outputObject1", objectClass = "character", desc = "this is for example"), createsOutput(objectName = "outputObject2", objectClass = "numeric", desc = "this is for example", otherInformation = "I am the second output object") )
There are two ways to define what occurs during an event: defining a function
called doEvent.moduleName
, where moduleName
is the actual module name.
This approach is the original approach used in SpaDES.core, and it must have an
explicit switch
statement branching on eventType
.
The newer approach (still experimental) uses defineEvent()
.
Instead of creating, doEvent.moduleName()
, it creates one function
for each event, each with the name doEvent.moduleName.eventName
.
This may be a little bit cleaner, but both with still work.
defineEvent( sim, eventName = "init", code, moduleName = NULL, envir = parent.frame() )
defineEvent( sim, eventName = "init", code, moduleName = NULL, envir = parent.frame() )
sim |
A |
eventName |
Character string of the desired event name to define. Default is "init" |
code |
An expression that defines the code to execute during the event. This will
be captured, and pasted into a new function ( |
moduleName |
Character string of the name of the module. If this function is used within a module, then it will try to find the module name. |
envir |
An optional environment to specify where to put the resulting function.
The default will place a function called |
defineModule()
, simInit()
, scheduleEvent()
sim <- simInit() # these put the functions in the parent.frame() which is .GlobalEnv for an interactive user defineEvent(sim, "init", moduleName = "thisTestModule", code = { sim <- Init(sim) # initialize # Now schedule some different event for "current time", i.e., will # be put in the event queue to run *after* this current event is finished sim <- scheduleEvent(sim, time(sim), "thisTestModule", "grow") }, envir = envir(sim)) defineEvent(sim, "grow", moduleName = "thisTestModule", code = { sim <- grow(sim) # grow # Now schedule this same event for "current time plus 1", i.e., a "loop" sim <- scheduleEvent(sim, time(sim) + 1, "thisTestModule", "grow") # for "time plus 1" }) Init <- function(sim) { sim$messageToWorld <- "Now the sim has an object in it that can be accessed" sim$size <- 1 # initializes the size object --> this can be anything, Raster, list, whatever message(sim$messageToWorld) return(sim) # returns all the things you added to sim as they are in the simList } grow <- function(sim) { sim$size <- sim$size + 1 # increments the size message(sim$size) return(sim) } # schedule that first "init" event sim <- scheduleEvent(sim, 0, "thisTestModule", "init") # Look at event queue events(sim) # shows the "init" we just added # this is skipped when running in automated tests; it is fine in interactive use out <- spades(sim)
sim <- simInit() # these put the functions in the parent.frame() which is .GlobalEnv for an interactive user defineEvent(sim, "init", moduleName = "thisTestModule", code = { sim <- Init(sim) # initialize # Now schedule some different event for "current time", i.e., will # be put in the event queue to run *after* this current event is finished sim <- scheduleEvent(sim, time(sim), "thisTestModule", "grow") }, envir = envir(sim)) defineEvent(sim, "grow", moduleName = "thisTestModule", code = { sim <- grow(sim) # grow # Now schedule this same event for "current time plus 1", i.e., a "loop" sim <- scheduleEvent(sim, time(sim) + 1, "thisTestModule", "grow") # for "time plus 1" }) Init <- function(sim) { sim$messageToWorld <- "Now the sim has an object in it that can be accessed" sim$size <- 1 # initializes the size object --> this can be anything, Raster, list, whatever message(sim$messageToWorld) return(sim) # returns all the things you added to sim as they are in the simList } grow <- function(sim) { sim$size <- sim$size + 1 # increments the size message(sim$size) return(sim) } # schedule that first "init" event sim <- scheduleEvent(sim, 0, "thisTestModule", "init") # Look at event queue events(sim) # shows the "init" we just added # this is skipped when running in automated tests; it is fine in interactive use out <- spades(sim)
Specify a new module's metadata as well as object and package dependencies. Packages are loaded during this call. Any or all of these can be missing, with missing values set to defaults
defineModule(sim, x) ## S4 method for signature 'simList,list' defineModule(sim, x)
defineModule(sim, x) ## S4 method for signature 'simList,list' defineModule(sim, x)
sim |
A |
x |
A list with a number of named elements, referred to as the metadata. See details. |
Updated simList
object.
name |
Module name. Must match the filename (without the .R extension).
This is currently not parsed by SpaDES;
it is for human readers only. |
description |
Brief description of the module. This is currently not parsed by SpaDES; it is for human readers only. |
keywords |
Author-supplied keywords. This is currently not parsed by SpaDES; it is for human readers only. |
childModules |
If this contains any character vector, then it will
be treated as a parent module. If this is a parent module,
then only this list entry will be read. For normal,
i.e., 'child modules', this should be character(0) or
NA .
If a character vector is provided, then these must be the
names of the modules located in the same file path as this
parent module that will be loaded during the simInit . |
authors |
Module author information (as a vector of person()
objects. This is currently not parsed by SpaDES;
it is for human readers only. |
version |
Module version number (will be coerced to numeric_version()
if a character or numeric are supplied).
The module developer should update manually this with each change
that is made to the module. See https://semver.org/
for a widely accepted standard for version numbering. |
spatialExtent |
The spatial extent of the module supplied via
terra::ext . This is currently unimplemented.
Once implemented, this should define what spatial region this
module is scientifically reasonable to be used in. |
timeframe |
Vector (length 2) of POSIXt dates specifying the temporal extent
of the module. Currently unimplemented.
Once implemented, this should define what time frame this
module is scientifically reasonable to be used for. |
timeunit |
Time scale of the module (e.g., "day", "year"). If this is
not specified, then .timeunitDefault() will be used.
It indicates what '1' unit of time
means for this module. SpaDES interprets this
and if modules have different timeunit values
then it will correctly schedule each module, using the
smallest (currently the default) timeunit as the
'model' timeunit in the spades call. |
citation |
List of character strings specifying module citation information.
Alternatively, a list of filenames of .bib or similar files.
This is currently not parsed by SpaDES;
it is for human readers only. |
documentation |
List of filenames referring to module documentation sources. This is currently not parsed by SpaDES; it is for human readers only. |
loadOrder |
Named list of length 0, 1, or 2, with names being after and before .
Each element should be a character string/vector naming 1 or more
modules that this module must be after or before .
after and before are used from the current module's
perspective. So, list(after = c("Biomass_core")) means that
this module must come after "Biomass_core" . This should only
be used when there are cyclic dependencies (2 or more modules
have 1 or more objects that is in both inputObjects and
outputObjects of both/all modules) between this module
and other modules. In cases where the dependencies are not cyclic,
SpaDES is able to resolve the order correctly. |
reqdPkgs |
List of R package names required by the module. These
packages will be loaded when simInit is called.
Require::Require() will be used internally
to load if available, and install if not available.
Because Require::Require() can also download from
GitHub.com, these packages can specify package names stored
on GitHub, e.g., "PredictiveEcology/SpaDES.core@development" . |
parameters |
A data.frame specifying the parameters used in the module.
Usually produced by rbind -ing the outputs of multiple
defineParameter() calls. These parameters indicate
the default values that will be used unless a module user
overrides them with the params argument in the
simInit() call. The minimum and maximum are
currently used by the SpaDES.shiny::shine function and the
POM function, and they should indicate the range
of values that are reasonable scientifically. |
inputObjects |
A data.frame specifying the data objects expected as
inputs to the module,
with columns objectName (class character ),
objectClass (class character ),
sourceURL (class character ), and other
(currently spades does nothing with this column).
This data.frame identifies the objects that are expected,
but does not do any loading of that object into the simList .
The sourceURL gives the developer the opportunity
to identify the source of a data file that can be used
with the model. This URL will be
used if the user calls downloadData (or
downloadModule(..., data = TRUE) . If the raw data
must be modified, the developer can use create a
function called .inputObjects in their module. That
function will be run during the simInit call. The
developer should ensure that if the object is supplied
by the module user as an argument in the simInit , then
the .inputObjects should not be run, i.e., use an
(is.null(sim$xxx))) . |
outputObjects |
A data.frame specifying the data objects output by
the module, with columns identical to those in
inputObjects . Like inputObjects above,
this only identifies the objects that this module will output
into the simList .
The module developer must create the necessary functions
that will cause these objects to be put into the
simList . |
Alex Chubaty
moduleDefaults()
, defineEvent()
## a default version of the defineModule is created with a call to newModule newModule("test", path = tempdir(), open = FALSE) ## view the resulting module file if (interactive()) file.edit(file.path(tempdir(), "test", "test.R"))
## a default version of the defineModule is created with a call to newModule newModule("test", path = tempdir(), open = FALSE) ## view the resulting module file if (interactive()) file.edit(file.path(tempdir(), "test", "test.R"))
Used to specify a parameter's name, value, and set a default. The min
and
max
arguments are ignored by simInit
or spades
; they
are for human use only. To ensure that a user cannot set parameters outside of
a range of values, the module developer should use assertions in their module
code.
defineParameter(name, class, default, min, max, desc, ...)
defineParameter(name, class, default, min, max, desc, ...)
name |
Character string giving the parameter name. |
class |
Character string giving the parameter class. |
default |
The default value to use when none is specified by the user. Non-standard evaluation is used for the expression. |
min |
With |
max |
With |
desc |
Text string providing a brief description of the parameter.
If there are extra spaces or carriage returns, these will be stripped,
allowing for multi-line character strings without using |
... |
A convenience that allows writing a long |
a data.frame
Be sure to use the correct NA type: logical (NA
), integer (NA_integer_
),
real (NA_real_
), complex (NA_complex_
), or character (NA_character_
).
See NA()
.
Alex Chubaty and Eliot McIntire
P()
, params()
for accessing these parameters in a module.
parameters = rbind( defineParameter("lambda", "numeric", 1.23, desc = "intrinsic rate of increase"), defineParameter("P", "numeric", 0.2, 0, 1, "probability of attack"), # multi-line desc without quotes on each line -- spaces and carriage returns are stripped defineParameter("rate", "numeric", 0.2, 0, 1, "rate of arrival. This is in individuals per day. This can be modified by the user"), # multi-line desc with quotes on each line defineParameter("times", "numeric", 0.2, 0, 1, desc = "The times during the year ", "that events will occur ", "with possibility of random arrival times") ) # Create a new module, then access parameters using `P` tmpdir <- file.path(tempdir(), "test") checkPath(tmpdir, create = TRUE) # creates a new, "empty" module -- it has defaults for everything that is required newModule("testModule", tmpdir, open = FALSE) # Look at new module code -- see defineParameter if (interactive()) file.edit(file.path(tmpdir, "testModule", "testModule.R")) # initialize the simList if (requireNamespace("ggplot2", quietly = TRUE)) { # Some things not necessary in this example, if not interactive (like plotting) opts <- if (interactive()) list() else options(spades.plot = NA, spades.useRequire = FALSE, spades.moduleCodeChecks = FALSE) mySim <- simInit(modules = "testModule", paths = list(modulePath = tmpdir)) # Access one of the parameters -- because this line is not inside a module # function, we must specify the module name. If used within a module, # we can omit the module name P(mySim, module = "testModule") # gets all params in a module P(mySim, ".useCache", "testModule") # just one param options(opts) } unlink(tmpdir, recursive = TRUE)
parameters = rbind( defineParameter("lambda", "numeric", 1.23, desc = "intrinsic rate of increase"), defineParameter("P", "numeric", 0.2, 0, 1, "probability of attack"), # multi-line desc without quotes on each line -- spaces and carriage returns are stripped defineParameter("rate", "numeric", 0.2, 0, 1, "rate of arrival. This is in individuals per day. This can be modified by the user"), # multi-line desc with quotes on each line defineParameter("times", "numeric", 0.2, 0, 1, desc = "The times during the year ", "that events will occur ", "with possibility of random arrival times") ) # Create a new module, then access parameters using `P` tmpdir <- file.path(tempdir(), "test") checkPath(tmpdir, create = TRUE) # creates a new, "empty" module -- it has defaults for everything that is required newModule("testModule", tmpdir, open = FALSE) # Look at new module code -- see defineParameter if (interactive()) file.edit(file.path(tmpdir, "testModule", "testModule.R")) # initialize the simList if (requireNamespace("ggplot2", quietly = TRUE)) { # Some things not necessary in this example, if not interactive (like plotting) opts <- if (interactive()) list() else options(spades.plot = NA, spades.useRequire = FALSE, spades.moduleCodeChecks = FALSE) mySim <- simInit(modules = "testModule", paths = list(modulePath = tmpdir)) # Access one of the parameters -- because this line is not inside a module # function, we must specify the module name. If used within a module, # we can omit the module name P(mySim, module = "testModule") # gets all params in a module P(mySim, ".useCache", "testModule") # just one param options(opts) } unlink(tmpdir, recursive = TRUE)
Build edge list for module dependency graph
depsEdgeList(sim, plot) ## S4 method for signature 'simList,logical' depsEdgeList(sim, plot) ## S4 method for signature 'simList,missing' depsEdgeList(sim, plot)
depsEdgeList(sim, plot) ## S4 method for signature 'simList,logical' depsEdgeList(sim, plot) ## S4 method for signature 'simList,missing' depsEdgeList(sim, plot)
sim |
A |
plot |
Logical indicating whether the edgelist (and subsequent graph)
will be used for plotting. If |
A data.table
whose first two columns give a list of edges
and remaining columns the attributes of the dependency objects
(object name, class, etc.).
Alex Chubaty
Build a module dependency graph
depsGraph(sim, plot) ## S4 method for signature 'simList,logical' depsGraph(sim, plot) ## S4 method for signature 'simList,missing' depsGraph(sim)
depsGraph(sim, plot) ## S4 method for signature 'simList,logical' depsGraph(sim, plot) ## S4 method for signature 'simList,missing' depsGraph(sim)
sim |
A |
plot |
Logical indicating whether the edgelist (and subsequent graph)
will be used for plotting. If |
An igraph()
object.
Alex Chubaty
SpaDES
modules commonly use approximate durations that divide with no
remainder among themselves.
For example, models that simulate based on a "week" timestep, will likely
want to fall in lock step with a second module that is a "year" timestep.
Since, weeks, months, years don't really have this behaviour because of:
leap years, leap seconds, not quite 52 weeks in a year, months that are of
different duration, etc.
We have generated a set of units that work well together that are based on
the astronomical or "Julian" year.
In an astronomical year, leap years are added within each year with an extra
1/4 day, (i.e., 1 year == 365.25 days); months are defined as year/12, and
weeks as year/52.
dhour(x) dmin(x) dday(x) dyears(x) ## S4 method for signature 'numeric' dyears(x) dmonths(x) ## S4 method for signature 'numeric' dmonths(x) dweeks(x) ## S4 method for signature 'numeric' dweeks(x) dweek(x) dmonth(x) dyear(x) dsecond(x) dNA(x) ## S4 method for signature 'ANY' dNA(x)
dhour(x) dmin(x) dday(x) dyears(x) ## S4 method for signature 'numeric' dyears(x) dmonths(x) ## S4 method for signature 'numeric' dmonths(x) dweeks(x) ## S4 method for signature 'numeric' dweeks(x) dweek(x) dmonth(x) dyear(x) dsecond(x) dNA(x) ## S4 method for signature 'ANY' dNA(x)
x |
numeric. Number of the desired units |
When these units are not correct, a module developer can create their own
time unit, and create a function to calculate the number of seconds
in that unit using the "d" prefix (for duration), following the
lubridate
package standard:
ddecade <- function(x) lubridate::duration(dyear(10))
.
Then the module developer can use "decade" as the module's time unit.
Number of seconds within each unit
Eliot McIntire
Download external data for a module if not already present in the module directory, or if there is a checksum mismatch indicating that the file is not the correct one.
downloadData( module, path, quiet, quickCheck = FALSE, overwrite = FALSE, files = NULL, checked = NULL, urls = NULL, children = NULL, ... ) ## S4 method for signature 'character,character,logical' downloadData( module, path, quiet, quickCheck = FALSE, overwrite = FALSE, files = NULL, checked = NULL, urls = NULL, children = NULL, ... ) ## S4 method for signature 'character,missing,missing' downloadData(module, quickCheck, overwrite, files, checked, urls, children) ## S4 method for signature 'character,missing,logical' downloadData( module, quiet, quickCheck, overwrite, files, checked, urls, children ) ## S4 method for signature 'character,character,missing' downloadData( module, path, quickCheck, overwrite, files, checked, urls, children )
downloadData( module, path, quiet, quickCheck = FALSE, overwrite = FALSE, files = NULL, checked = NULL, urls = NULL, children = NULL, ... ) ## S4 method for signature 'character,character,logical' downloadData( module, path, quiet, quickCheck = FALSE, overwrite = FALSE, files = NULL, checked = NULL, urls = NULL, children = NULL, ... ) ## S4 method for signature 'character,missing,missing' downloadData(module, quickCheck, overwrite, files, checked, urls, children) ## S4 method for signature 'character,missing,logical' downloadData( module, quiet, quickCheck, overwrite, files, checked, urls, children ) ## S4 method for signature 'character,character,missing' downloadData( module, path, quickCheck, overwrite, files, checked, urls, children )
module |
Character string giving the name of the module. |
path |
Character string giving the path to the module directory. |
quiet |
Logical. This is passed to |
quickCheck |
Logical. If |
overwrite |
Logical. Should local data files be overwritten in case they exist?
Default is |
files |
A character vector of length 1 or more if only a subset of files should be checked in the ‘CHECKSUMS.txt’ file. |
checked |
The result of a previous |
urls |
Character vector of urls from which to get the data. This is automatically
found from module metadata when this function invoked with
|
children |
The character vector of child modules (without path) to also
run |
... |
Passed to |
downloadData
requires a checksums file to work, as it will only download
the files specified therein. Hence, module developers should make sure they
have manually downloaded all the necessary data and ran checksums
to
build a checksums file.
There is an experimental attempt to use the googledrive package to download
data from a shared (publicly or with individual users) file.
To try this, put the Google Drive URL in sourceURL
argument of
expectsInputs
in the module metadata, and put the filename once downloaded
in the objectName
argument.
If using RStudio Server, you may need to use "out of band" authentication by
setting options(httr_oob_default = TRUE)
.
To avoid caching of Oauth credentials, set options(httr_oauth_cache = TRUE)
.
There is also an experimental option for the user to make a new ‘CHECKSUMS.txt’
file if there is a sourceURL
but no entry for that file.
This is experimental and should be used with caution.
Invisibly, a list of downloaded files.
Alex Chubaty & Eliot McIntire
prepInputs()
, checksums()
, and downloadModule()
for downloading modules and building a checksums file.
# In metadata, each expectsInput has a sourceURL; downloadData will look for # that and download if it defined; however this sample module has all # NAs for sourceURL, so nothing to download modulePath <- getSampleModules(tempdir()) downloadData("caribouMovement", path = modulePath)
# In metadata, each expectsInput has a sourceURL; downloadData will look for # that and download if it defined; however this sample module has all # NAs for sourceURL, so nothing to download modulePath <- getSampleModules(tempdir()) downloadData("caribouMovement", path = modulePath)
Download a .zip file of the module and extract (unzip) it to a user-specified location.
downloadModule( name, path, version, repo, data, quiet, quickCheck = FALSE, overwrite = FALSE ) ## S4 method for signature ## 'character,character,character,character,logical,logical,ANY,logical' downloadModule( name, path, version, repo, data, quiet, quickCheck = FALSE, overwrite = FALSE ) ## S4 method for signature ## 'character,missing,missing,missing,missing,missing,ANY,ANY' downloadModule(name, quickCheck, overwrite) ## S4 method for signature 'character,ANY,ANY,ANY,ANY,ANY,ANY,ANY' downloadModule( name, path, version, repo, data, quiet, quickCheck = FALSE, overwrite = FALSE )
downloadModule( name, path, version, repo, data, quiet, quickCheck = FALSE, overwrite = FALSE ) ## S4 method for signature ## 'character,character,character,character,logical,logical,ANY,logical' downloadModule( name, path, version, repo, data, quiet, quickCheck = FALSE, overwrite = FALSE ) ## S4 method for signature ## 'character,missing,missing,missing,missing,missing,ANY,ANY' downloadModule(name, quickCheck, overwrite) ## S4 method for signature 'character,ANY,ANY,ANY,ANY,ANY,ANY,ANY' downloadModule( name, path, version, repo, data, quiet, quickCheck = FALSE, overwrite = FALSE )
name |
Character string giving the module name. |
path |
Character string giving the location in which to save the downloaded module. |
version |
The module version to download. (If not specified, or |
repo |
GitHub repository name, specified as |
data |
Logical. If |
quiet |
Logical. This is passed to |
quickCheck |
Logical. If |
overwrite |
Logical. Should local module files be overwritten in case they exist?
Default |
Currently only works with GitHub repositories where modules are located in
a modules
directory in the root tree on the master
branch.
Module .zip files' names should contain the version number and be inside their
respective module folders (see zipModule()
for zip compression of modules).
A list of length 2. The first element is a character vector containing
a character vector of extracted files for the module. The second element is
a tbl
with details about the data that is relevant for the function,
including whether it was downloaded or not, and whether it was renamed
(because there was a local copy that had the wrong file name).
downloadModule
uses the GITHUB_PAT
environment variable
if a value is set. This alleviates 403 errors caused by too-frequent downloads.
Generate a GitHub personal access token with no additional permissions at
https://github.com/settings/tokens, and add this key to ‘.Renviron’
as GITHUB_PAT=<your-github-pat-here>
.
The default is to overwrite any existing files in the case of a conflict.
Alex Chubaty
zipModule()
for creating module .zip folders.
Accessor functions for the .xData
slot, which is the default virtual
slot for an S4 class object that inherits from an S3 object (specifically,
the simList
inherits from environment
) in a simList
object.
These are included for advanced users.
envir(sim) ## S4 method for signature 'simList' envir(sim) envir(sim) <- value ## S4 replacement method for signature 'simList' envir(sim) <- value
envir(sim) ## S4 method for signature 'simList' envir(sim) envir(sim) <- value ## S4 replacement method for signature 'simList' envir(sim) <- value
sim |
A |
value |
The object to be stored at the slot. |
Currently, only get and set methods are defined. Subset methods are not.
Returns or sets the value of the slot from the simList
object.
Alex Chubaty
SpaDES.core-package, specifically the section 1.2.8 on simList
environment.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
Create a Gantt Chart representing the events in a completed simulation.
This event diagram is constructed using the completed event list
To change the number of events shown, provide an n
argument.
eventDiagram(sim, n, startDate, ...) ## S4 method for signature 'simList,numeric,character' eventDiagram(sim, n, startDate, ...) ## S4 method for signature 'simList,missing,character' eventDiagram(sim, n, startDate, ...) ## S4 method for signature 'simList,missing,missing' eventDiagram(sim, n, startDate, ...)
eventDiagram(sim, n, startDate, ...) ## S4 method for signature 'simList,numeric,character' eventDiagram(sim, n, startDate, ...) ## S4 method for signature 'simList,missing,character' eventDiagram(sim, n, startDate, ...) ## S4 method for signature 'simList,missing,missing' eventDiagram(sim, n, startDate, ...)
sim |
A |
n |
The number of most recently completed events to plot. |
startDate |
A character representation of date in |
... |
Additional arguments passed to |
Simulation time is presented on the x-axis, starting at date startDate
.
Each module appears in a colour-coded row, within which each event for that
module is displayed corresponding to the sequence of events for that module.
Note that only the start time of the event is meaningful is these figures:
the width of the bar associated with a particular module's event DOES NOT
correspond to an event's "duration".
Based on this Stack Overflow answer: https://stackoverflow.com/a/29999300/1380598.
Plots an event diagram as Gantt Chart, invisibly returning a mermaid
object.
A red vertical line corresponding to the current date may appear on the figure. This is useful for Gantt Charts generally but can be considered a 'bug' here.
Alex Chubaty
DiagrammeR::mermaid
.
Accessor functions for the events
and completed
slots of a
simList
object. These path functions will extract the values that were
provided to the simInit
function in the path
argument.
events(sim, unit) ## S4 method for signature 'simList,character' events(sim, unit) ## S4 method for signature 'simList,missing' events(sim, unit) events(sim) <- value ## S4 replacement method for signature 'simList' events(sim) <- value conditionalEvents(sim, unit) ## S4 method for signature 'simList,character' conditionalEvents(sim, unit) ## S4 method for signature 'simList,missing' conditionalEvents(sim, unit) current(sim, unit) ## S4 method for signature 'simList,character' current(sim, unit) ## S4 method for signature 'simList,missing' current(sim, unit) current(sim) <- value ## S4 replacement method for signature 'simList' current(sim) <- value completed(sim, unit, times = TRUE) ## S4 method for signature 'simList,character' completed(sim, unit, times = TRUE) ## S4 method for signature 'simList,missing' completed(sim, unit, times = TRUE) completed(sim) <- value ## S4 replacement method for signature 'simList' completed(sim) <- value
events(sim, unit) ## S4 method for signature 'simList,character' events(sim, unit) ## S4 method for signature 'simList,missing' events(sim, unit) events(sim) <- value ## S4 replacement method for signature 'simList' events(sim) <- value conditionalEvents(sim, unit) ## S4 method for signature 'simList,character' conditionalEvents(sim, unit) ## S4 method for signature 'simList,missing' conditionalEvents(sim, unit) current(sim, unit) ## S4 method for signature 'simList,character' current(sim, unit) ## S4 method for signature 'simList,missing' current(sim, unit) current(sim) <- value ## S4 replacement method for signature 'simList' current(sim) <- value completed(sim, unit, times = TRUE) ## S4 method for signature 'simList,character' completed(sim, unit, times = TRUE) ## S4 method for signature 'simList,missing' completed(sim, unit, times = TRUE) completed(sim) <- value ## S4 replacement method for signature 'simList' completed(sim) <- value
sim |
A |
unit |
Character. One of the time units used in |
value |
The object to be stored at the slot. |
times |
Logical. Should this function report the |
By default, the event lists are shown when the simList
object is printed,
thus most users will not require direct use of these methods.
events |
Scheduled simulation events (the event queue). |
completed |
Completed simulation events. |
Currently, only get and set methods are defined. Subset methods are not.
Returns or sets the value of the slot from the simList
object.
Each event is represented by a data.table()
row consisting of:
eventTime
: The time the event is to occur.
moduleName
: The module from which the event is taken.
eventType
: A character string for the programmer-defined event type.
SpaDES.core-package, specifically the section 1.2.6 on Simulation event queues.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
Used to specify an input object's name, class, description, source url and other specifications.
expectsInput(objectName, objectClass, desc, sourceURL, ...) ## S4 method for signature 'ANY,ANY,ANY,ANY' expectsInput(objectName, objectClass, desc, sourceURL, ...) ## S4 method for signature 'character,character,character,character' expectsInput(objectName, objectClass, desc, sourceURL, ...) ## S4 method for signature 'character,character,character,missing' expectsInput(objectName, objectClass, desc, sourceURL, ...)
expectsInput(objectName, objectClass, desc, sourceURL, ...) ## S4 method for signature 'ANY,ANY,ANY,ANY' expectsInput(objectName, objectClass, desc, sourceURL, ...) ## S4 method for signature 'character,character,character,character' expectsInput(objectName, objectClass, desc, sourceURL, ...) ## S4 method for signature 'character,character,character,missing' expectsInput(objectName, objectClass, desc, sourceURL, ...)
objectName |
Character string to define the input object's name. |
objectClass |
Character string to specify the input object's class. |
desc |
Text string providing a brief description of the input object.
If there are extra spaces or carriage returns, these will be stripped,
allowing for multi-line character strings without using |
sourceURL |
Character string to specify an URL to reach the input object,
default is |
... |
Other specifications of the input object. |
A data.frame
suitable to be passed to inputObjects
in a module's metadata.
Yong Luo
inputObjects <- bindrows( expectsInput(objectName = "inputObject1", objectClass = "character", desc = "this is for example", sourceURL = "not available"), expectsInput(objectName = "inputObject2", objectClass = "numeric", desc = "this is for example", sourceURL = "not available", otherInformation = "I am the second input object") )
inputObjects <- bindrows( expectsInput(objectName = "inputObject1", objectClass = "character", desc = "this is for example", sourceURL = "not available"), expectsInput(objectName = "inputObject2", objectClass = "numeric", desc = "this is for example", sourceURL = "not available", otherInformation = "I am the second input object") )
This will get the sourceURL
for the object named.
extractURL(objectName, sim, module) ## S4 method for signature 'character,missing' extractURL(objectName, sim, module) ## S4 method for signature 'character,simList' extractURL(objectName, sim, module)
extractURL(objectName, sim, module) ## S4 method for signature 'character,missing' extractURL(objectName, sim, module) ## S4 method for signature 'character,simList' extractURL(objectName, sim, module)
objectName |
A character string of the object name in the metadata. |
sim |
A |
module |
An optional character string of the module name whose metadata is
to be used. If omitted, the function will use the |
The url.
Eliot McIntire
Extract filename (without extension) of a file
fileName(x)
fileName(x)
x |
List or character vector |
A character vector.
Eliot McIntire
Get copies of sample files for examples and tests
getMapPath(tmpdir) getSampleModules(tmpdir)
getMapPath(tmpdir) getSampleModules(tmpdir)
tmpdir |
character specifying the path to a temporary directory (e.g., |
character vector of filepaths to the copied files
Modified from https://stackoverflow.com/a/25485782/1380598.
getModuleVersion(name, repo) ## S4 method for signature 'character,character' getModuleVersion(name, repo) ## S4 method for signature 'character,missing' getModuleVersion(name)
getModuleVersion(name, repo) ## S4 method for signature 'character,character' getModuleVersion(name, repo) ## S4 method for signature 'character,missing' getModuleVersion(name)
name |
Character string giving the module name. |
repo |
GitHub repository name, specified as |
getModuleVersion
extracts a module's most recent version by
looking at the module ‘.zip’ files contained in the module directory.
It takes the most recent version, based on the name of the zip file.
See the modules vignette for details of module directory structure (https://spades-core.predictiveecology.org/articles/ii-modules.html#module-directory-structure-modulename), and see our SpaDES-modules repo for details of module repository structure (https://github.com/PredictiveEcology/SpaDES-modules).
numeric_version
Alex Chubaty
zipModule()
for creating module ‘.zip’ folders.
globals
, and the alias G
, accesses or sets the "globals"
in the simList
. This currently is not an explicit slot in the simList
,
but it is a .globals
element in the params
slot of the simList
.
globals(sim) ## S4 method for signature 'simList' globals(sim) globals(sim) <- value ## S4 replacement method for signature 'simList' globals(sim) <- value G(sim) ## S4 method for signature 'simList' G(sim) G(sim) <- value ## S4 replacement method for signature 'simList' G(sim) <- value
globals(sim) ## S4 method for signature 'simList' globals(sim) globals(sim) <- value ## S4 replacement method for signature 'simList' globals(sim) <- value G(sim) ## S4 method for signature 'simList' G(sim) G(sim) <- value ## S4 replacement method for signature 'simList' G(sim) <- value
sim |
A |
value |
The parameter value to be set (in the corresponding |
SpaDES.core-package, specifically the section 1.2.1 on Simulation Parameters.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
simList
objectGiven the name or the definition of a class, plus optionally data to be
included in the object, new
returns an object from that class.
Given the name or the definition of a class, plus optionally data to be
included in the object, new
returns an object from that class.
## S4 method for signature 'simList' initialize(.Object, ...) ## S4 method for signature 'simList_' initialize(.Object, ...)
## S4 method for signature 'simList' initialize(.Object, ...) ## S4 method for signature 'simList_' initialize(.Object, ...)
.Object |
A |
... |
Optional Values passed to any or all slot |
These accessors extract the metadata for a module (if specified) or all modules
in a simList
if not specified.
inputObjects(sim, module, path) ## S4 method for signature 'simList' inputObjects(sim, module, path) ## S4 method for signature 'missing' inputObjects(sim, module, path) outputObjects(sim, module, path) ## S4 method for signature 'simList' outputObjects(sim, module, path) ## S4 method for signature 'missing' outputObjects(sim, module, path) outputObjectNames(sim, module) ## S4 method for signature 'simList' outputObjectNames(sim, module) reqdPkgs(sim, module, modulePath) ## S4 method for signature 'simList' reqdPkgs(sim, module, modulePath) ## S4 method for signature 'missing' reqdPkgs(sim, module, modulePath) documentation(sim, module) ## S4 method for signature 'simList' documentation(sim, module) sessInfo(sim) ## S4 method for signature 'simList' sessInfo(sim)
inputObjects(sim, module, path) ## S4 method for signature 'simList' inputObjects(sim, module, path) ## S4 method for signature 'missing' inputObjects(sim, module, path) outputObjects(sim, module, path) ## S4 method for signature 'simList' outputObjects(sim, module, path) ## S4 method for signature 'missing' outputObjects(sim, module, path) outputObjectNames(sim, module) ## S4 method for signature 'simList' outputObjectNames(sim, module) reqdPkgs(sim, module, modulePath) ## S4 method for signature 'simList' reqdPkgs(sim, module, modulePath) ## S4 method for signature 'missing' reqdPkgs(sim, module, modulePath) documentation(sim, module) ## S4 method for signature 'simList' documentation(sim, module) sessInfo(sim) ## S4 method for signature 'simList' sessInfo(sim)
sim |
A |
module |
Character vector of module name(s) |
path |
The path to the module., i.e., the |
modulePath |
That path where |
# set modulePath setPaths(modulePath = getSampleModules(tempdir())) # use Require and reqdPkgs pkgs <- reqdPkgs(module = c("caribouMovement", "randomLandscapes", "fireSpread"))
# set modulePath setPaths(modulePath = getSampleModules(tempdir())) # use Require and reqdPkgs pkgs <- reqdPkgs(module = c("caribouMovement", "randomLandscapes", "fireSpread"))
Accessor functions for the inputs
slots in a simList
object.
inputs(sim) ## S4 method for signature 'simList' inputs(sim) inputs(sim) <- value ## S4 replacement method for signature 'simList' inputs(sim) <- value inputArgs(sim) ## S4 method for signature 'simList' inputArgs(sim) inputArgs(sim) <- value ## S4 replacement method for signature 'simList' inputArgs(sim) <- value
inputs(sim) ## S4 method for signature 'simList' inputs(sim) inputs(sim) <- value ## S4 replacement method for signature 'simList' inputs(sim) <- value inputArgs(sim) ## S4 method for signature 'simList' inputArgs(sim) inputArgs(sim) <- value ## S4 replacement method for signature 'simList' inputArgs(sim) <- value
sim |
A |
value |
The object to be stored at the slot. See Details. |
These functions are one of three mechanisms to add the information about which input files
to load in a spades
call.
As arguments to a simInit
call. Specifically, inputs
or outputs
.
See ?simInit
.
With the outputs(simList)
function call.
By adding a function called .inputObjects
inside a module, which will be executed
during the simInit
call. This last way is the most "modular" way to create
default data sets for your model.
See below for more details.
Returns or sets the value(s) of the input
or output
slots
in the simList
object.
simInit
inputs
accepts a data.frame, with up to 7 columns.
Columns are:
file |
required, a character string indicating the file path. There is no default. |
objectName |
optional, character string indicating the name of the object
that the loaded file will be assigned to in the simList . This object
can therefore be accessed with sim$xxx in any module, where
objectName = "xxx" . Defaults to the filename without file extension or
directory information. |
fun |
optional, a character string indicating the function to use to
load that file. Defaults to the known extensions in SpaDES (found by
examining .fileExtensions() ). The package and fun can be
jointly specified here as "packageName::functionName" , e.g.,
"terra::rast" . |
package |
optional character string indicating the package in
which to find the fun ); |
loadTime |
optional numeric, indicating when in simulation time the file
should be loaded. The default is the highest priority at start(sim) ,
i.e., at the very start. |
interval |
optional numeric, indicating at what interval should this same
exact file be reloaded from disk, e.g,. 10 would mean every 10 time units. The
default is NA or no interval, i.e, load the file only once as described in
loadTime |
arguments |
is a list of lists of named arguments, one list for each
fun . For example, if fun="raster" , arguments = list(native = TRUE)
will pass the argument "native = TRUE" to raster. If there is only one list,
then it is assumed to apply to all files and will be recycled as per normal R
rules of recycling for each fun . |
Currently, only file
is required. All others will be filled with defaults
if not specified.
See the modules vignette for more details (browseVignettes("SpaDES.core")
).
.inputObjects
function placed inside moduleAny code placed inside a function called .inputObjects
will be run during
simInit()
for the purpose of creating any objects required by this module,
i.e., objects identified in the inputObjects
element of defineModule
.
This is useful if there is something required before simulation to produce the module
object dependencies, including such things as downloading default datasets, e.g.,
downloadData('LCC2005', modulePath(sim))
.
Nothing should be created here that does not create an named object in inputObjects
.
Any other initiation procedures should be put in the "init" eventType
of the doEvent
function.
Note: the module developer can use sim$.userSuppliedObjNames
inside the function to
selectively skip unnecessary steps because the user has provided those inputObjects
in the
simInit
call. e.g., the following code would look to see if the user had passed defaultColor
into during simInit
. If the user had done this, then this function would not override
that value with 'red'. If the user has not passed in a value for defaultColor
, then
the module will get it here:
if (!('defaultColor' %in% sim$.userSuppliedObjNames)) {
sim$defaultColor <- 'red'
}
SpaDES.core-package, specifically the section 1.2.2 on loading and saving.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
####################### # inputs ####################### # Start with a basic empty simList sim <- simInit() test <- 1:10 tmpdir <- file.path(tempdir(), "inputs") |> checkPath(create = TRUE) tmpFile <- file.path(tmpdir, "test.rds") saveRDS(test, file = tmpFile) inputs(sim) <- data.frame(file = tmpFile) # using only required column, "file" inputs(sim) # see that it is not yet loaded, but when it is scheduled to be loaded simOut <- spades(sim) inputs(simOut) # confirm it was loaded simOut$test # can put data.frame for inputs directly inside simInit call allTifs <- dir(getMapPath(tempdir()), full.names = TRUE) # next: .objectNames are taken from the filenames (without the extension) # This will load all 5 tifs in the SpaDES sample directory, using # the rast fuction in the terra package, all at time = 0 sim <- simInit( inputs = data.frame( files = allTifs, functions = "rast", package = "terra", loadTime = 0, stringsAsFactors = FALSE) ) ############################## # A fully described inputs object, including arguments: files <- dir(getMapPath(tempdir()), full.names = TRUE) # arguments must be a list of lists. This may require I() to keep it as a list # once it gets coerced into the data.frame. # arguments = I(rep(list(native = TRUE), length(files))) filelist <- data.frame( objectName = paste0("Maps", 1:5), files = files, functions = "terra::rast", # arguments = arguments, loadTime = 0, intervals = c(rep(NA, length(files) - 1), 10) ) inputs(sim) <- filelist spades(sim) # Example showing loading multiple objects from global environment onto the # same object in the simList, but at different load times a1 <- 1 a2 <- 2 # Note arguments must be a list of NROW(inputs), with each element itself being a list, # which is passed to do.call(fun[x], arguments[[x]]), where x is row number, one at a time args <- lapply(1:2, function(x) { list(x = paste0("a", x), envir = environment()) # may be necessary to specify in which envir a1, a2 # are located, if not in an interactive session }) inputs <- data.frame(objectName = "a", loadTime = 1:2, fun = "base::get", arguments = I(args)) a <- simInit(inputs = inputs, times = list(start = 0, end = 1)) a <- spades(a) identical(a1, a$a) end(a) <- 3 a <- spades(a) # different object (a2) loaded onto a$a identical(a2, a$a) # Clean up after unlink(tmpdir, recursive = TRUE)
####################### # inputs ####################### # Start with a basic empty simList sim <- simInit() test <- 1:10 tmpdir <- file.path(tempdir(), "inputs") |> checkPath(create = TRUE) tmpFile <- file.path(tmpdir, "test.rds") saveRDS(test, file = tmpFile) inputs(sim) <- data.frame(file = tmpFile) # using only required column, "file" inputs(sim) # see that it is not yet loaded, but when it is scheduled to be loaded simOut <- spades(sim) inputs(simOut) # confirm it was loaded simOut$test # can put data.frame for inputs directly inside simInit call allTifs <- dir(getMapPath(tempdir()), full.names = TRUE) # next: .objectNames are taken from the filenames (without the extension) # This will load all 5 tifs in the SpaDES sample directory, using # the rast fuction in the terra package, all at time = 0 sim <- simInit( inputs = data.frame( files = allTifs, functions = "rast", package = "terra", loadTime = 0, stringsAsFactors = FALSE) ) ############################## # A fully described inputs object, including arguments: files <- dir(getMapPath(tempdir()), full.names = TRUE) # arguments must be a list of lists. This may require I() to keep it as a list # once it gets coerced into the data.frame. # arguments = I(rep(list(native = TRUE), length(files))) filelist <- data.frame( objectName = paste0("Maps", 1:5), files = files, functions = "terra::rast", # arguments = arguments, loadTime = 0, intervals = c(rep(NA, length(files) - 1), 10) ) inputs(sim) <- filelist spades(sim) # Example showing loading multiple objects from global environment onto the # same object in the simList, but at different load times a1 <- 1 a2 <- 2 # Note arguments must be a list of NROW(inputs), with each element itself being a list, # which is passed to do.call(fun[x], arguments[[x]]), where x is row number, one at a time args <- lapply(1:2, function(x) { list(x = paste0("a", x), envir = environment()) # may be necessary to specify in which envir a1, a2 # are located, if not in an interactive session }) inputs <- data.frame(objectName = "a", loadTime = 1:2, fun = "base::get", arguments = I(args)) a <- simInit(inputs = inputs, times = list(start = 0, end = 1)) a <- spades(a) identical(a1, a$a) end(a) <- 3 a <- spades(a) # different object (a2) loaded onto a$a identical(a2, a$a) # Clean up after unlink(tmpdir, recursive = TRUE)
Current pre-defined units are found within the spadesTimes()
function.
The user can define a new unit.
The unit name can be anything, but the function definition must be of the
form "dunitName"
, e.g., dyear
or dfortnight
.
The unit name is the part without the d
and the function name
definition includes the d
.
This new function, e.g., dfortnight <- function(x) lubridate::duration(dday(14))
can be placed anywhere in the search path or in a module
(you will need to declare "lubridate"
in your pkgDeps
in the metadata).
This function takes a numeric with a "unit" attribute and converts it to
another numeric with a different time attribute.
If the units passed to argument units
are the same as
attr(time, "unit")
, then it simply returns input time
.
inSeconds(unit, envir, skipChecks = FALSE) convertTimeunit(time, unit, envir, skipChecks = FALSE) .spadesTimes spadesTimes() checkTimeunit(unit, envir) ## S4 method for signature 'character,missing' checkTimeunit(unit, envir) ## S4 method for signature 'character,environment' checkTimeunit(unit, envir)
inSeconds(unit, envir, skipChecks = FALSE) convertTimeunit(time, unit, envir, skipChecks = FALSE) .spadesTimes spadesTimes() checkTimeunit(unit, envir) ## S4 method for signature 'character,missing' checkTimeunit(unit, envir) ## S4 method for signature 'character,environment' checkTimeunit(unit, envir)
unit |
Character. One of the time units used in |
envir |
An environment. This is where to look up the function definition for the time unit. See details. |
skipChecks |
For speed, the internal checks for classes and missingness can be skipped.
Default |
time |
Numeric. With a unit attribute, indicating the time unit of the input numeric. See Details. |
An object of class character
of length 12.
Because of R scoping, if envir
is a simList
environment, then
this function will search there first, then up the current search()
path.
Thus, it will find a user defined or module defined unit before a SpaDES unit.
This means that a user can override the dyear
given in SpaDES, for example,
which is 365.25 days, with dyear <- function(x) lubridate::duration(dday(365))
.
If time
has no unit
attribute, then it is assumed to be
seconds.
A numeric vector of length 1, with unit
attribute set to "seconds".
Alex Chubaty & Eliot McIntire
Eliot McIntire
simList
and ancillary filesLoading a simList
from file can be problematic as there are non-standard
objects that must be rebuilt. See description in saveSimList()
for details.
unzipSimList
is a convenience wrapper around unzip
and loadSimList
where
all the files are correctly identified and passed to
loadSimList(..., otherFiles = xxx)
. See zipSimList for details.
loadSimList( filename, projectPath = getwd(), tempPath = tempdir(), paths = NULL, otherFiles = "", verbose = getOption("reproducible.verbose") ) unzipSimList(zipfile, load = TRUE, paths = getPaths(), ...)
loadSimList( filename, projectPath = getwd(), tempPath = tempdir(), paths = NULL, otherFiles = "", verbose = getOption("reproducible.verbose") ) unzipSimList(zipfile, load = TRUE, paths = getPaths(), ...)
filename |
Character giving the name of a saved simulation file.
Currently, only file types |
projectPath |
An optional path for the project within which the |
tempPath |
A character string specifying the new base directory for the
temporary paths maintained in a |
paths |
A list of character vectors for all the |
otherFiles |
A character vector of (absolute) file names locating each of the
existing file-backed |
verbose |
Numeric, -1 silent (where possible), 0 being very quiet,
1 showing more messaging, 2 being more messaging, etc.
Default is 1. Above 3 will output much more information about the internals of
Caching, which may help diagnose Caching challenges. Can set globally with an
option, e.g., |
zipfile |
Filename of a zipped |
load |
Logical. If |
... |
passed to |
If cache
is used, it is likely that it should be trimmed before
zipping, to include only cache elements that are relevant.
For loadSimList()
, a simList
object.
For unzipSimList()
, either a character vector of file names unzipped
(if load = FALSE
), or a simList
object.
simList
correctly work with memoise
Because of the environment slot, simList
objects don't correctly
memoise a simList
.
This method for simList
converts the object to a simList_
first.
## S3 method for class 'simList' makeMemoisable(x) ## S3 method for class 'simList_' unmakeMemoisable(x)
## S3 method for class 'simList' makeMemoisable(x) ## S3 method for class 'simList_' unmakeMemoisable(x)
x |
An object to make memoisable. See individual methods in other packages. |
A simList_
object or a simList
, in the case of unmakeMemoisable
.
reproducible::makeMemoisable()
Determine the largest timestep unit in a simulation
maxTimeunit(sim) ## S4 method for signature 'simList' maxTimeunit(sim)
maxTimeunit(sim) ## S4 method for signature 'simList' maxTimeunit(sim)
sim |
A |
The timeunit as a character string. This defaults to NA
if
none of the modules has explicit units.
Eliot McIntire and Alex Chubaty
system("ps")
This will give a slightly different estimate than pryr::mem_used
, which uses gc()
internally.
The purpose of this function is to allow continuous monitoring, external to the R session.
Normally, this is run in a different session.
This will only work if the user has specified before running the spades
call,
set the interval, in seconds, that ps
is run.
E.g., options("spades.memoryUseInterval" = 0.5)
, will assess memory use every 0.5 seconds.
The default is 0
, meaning no interval, "off".
memoryUseThisSession(thisPid) memoryUse(sim, max = TRUE)
memoryUseThisSession(thisPid) memoryUse(sim, max = TRUE)
thisPid |
Numeric or integer, the |
sim |
A completed |
max |
Logical. If TRUE, then it the return value will be summarized by
module/event, showing the maximum memory used. If |
estimated memory use in MiB
data.table
summarizing the estimated memory use (in MiB) for each event type,
for each module, during the simulation.
The suggested future
and future.callr
packages must be available.
The vignette("iv-modules")
When modules have different timeunit, SpaDES automatically takes the smallest (e.g., "second") as the unit for a simulation.
minTimeunit(sim) ## S4 method for signature 'simList' minTimeunit(sim) ## S4 method for signature 'list' minTimeunit(sim)
minTimeunit(sim) ## S4 method for signature 'simList' minTimeunit(sim) ## S4 method for signature 'list' minTimeunit(sim)
sim |
A |
The timeunit as a character string. This defaults to "second" if none of the modules has explicit units.
Eliot McIntire
This can be used e.g., for Caching, to identify which files have changed.
moduleCodeFiles(paths, modules)
moduleCodeFiles(paths, modules)
paths |
An optional named list with up to 4 named elements,
|
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 ‘caribou.R’,
located at the specified |
character vector of file paths.
Calculate the test coverage by unit tests for the module and its functions.
moduleCoverage(mod, modulePath = "..")
moduleCoverage(mod, modulePath = "..")
mod |
Character string. The module's name. Default is |
modulePath |
Character string. The path to the module directory (default is "..", i.e., one level up from working directory). |
Return a list of two coverage objects and two data.table objects.
The two coverage objects are named moduleCoverage
and functionCoverage
.
The moduleCoverage
object contains the percent value of unit test coverage
for the module.
The functionCoverage
object contains percentage values for unit test
coverage for each function defined in the module.
Please use covr::report()
to view the coverage information.
Two data.tables give the information of all the tested and untested functions
in the module.
When running this function, the test files must be strictly placed in
the ‘tests/testthat/’ directory under module path.
To automatically generate this folder, please set unitTests = TRUE
when creating a new module using newModule()
.
To accurately test your module, the test filename must follow the format
test-functionName.R
.
Yong Luo
defineModule
Where individual elements are missing in defineModule
, these defaults will be used.
moduleDefaults
moduleDefaults
An object of class list
of length 13.
named list of default module metadata
Create a network diagram illustrating the simplified module dependencies of a
simulation. Offers a less detailed view of specific objects than does
plotting the depsEdgeList
directly with objectDiagram()
.
moduleDiagram(sim, type, showParents = TRUE, ...) ## S4 method for signature 'simList,character,logical' moduleDiagram(sim, type = "plot", showParents = TRUE, ...) ## S4 method for signature 'simList,ANY,ANY' moduleDiagram(sim, type, showParents = TRUE, ...)
moduleDiagram(sim, type, showParents = TRUE, ...) ## S4 method for signature 'simList,character,logical' moduleDiagram(sim, type = "plot", showParents = TRUE, ...) ## S4 method for signature 'simList,ANY,ANY' moduleDiagram(sim, type, showParents = TRUE, ...)
sim |
A |
type |
Character string, either |
showParents |
Logical. If TRUE, then any children that are grouped into parent
modules will be grouped together by coloured blobs. Internally,
this is calling |
... |
Additional arguments passed to plotting function specified by |
invoked for its side effect of plotting the module dependency diagram.
Alex Chubaty
igraph()
, moduleGraph()
for a version that accounts for
parent and children module structure.
if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { library(igraph) times <- list(start = 0, end = 6, "month") parameters <- list( .globals = list(stackName = "landscape"), caribouMovement = list( .saveObjects = "caribou", .saveInitialTime = 1, .saveInterval = 1 ), randomLandscapes = list(.plotInitialTime = NA, nx = 20, ny = 20)) modules <- list("randomLandscapes", "caribouMovement") paths <- list( modulePath = getSampleModules(tempdir()) ) # Set some options so example runs faster opts <- options(spades.moduleCodeChecks = FALSE, spades.loadReqdPkgs = FALSE) sim <- simInit(times = times, params = parameters, modules = modules, paths = paths) options(opts) moduleDiagram(sim) # Can also use default base::plot modDia <- depsGraph(sim, plot = TRUE) # See ?plot.igraph plot(modDia, layout = layout_as_star) # Or for more control - here, change the label "_INPUT_" to "DATA" edgeList <- depsEdgeList(sim) edgeList <- edgeList[, list(from, to)] edgeList[from == "_INPUT_", from := "Data"] edgeList[to == "_INPUT_", to := "Data"] edgeList <- unique(edgeList) ig <- graph_from_data_frame(edgeList[, list(from, to)]) plot(ig) }
if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { library(igraph) times <- list(start = 0, end = 6, "month") parameters <- list( .globals = list(stackName = "landscape"), caribouMovement = list( .saveObjects = "caribou", .saveInitialTime = 1, .saveInterval = 1 ), randomLandscapes = list(.plotInitialTime = NA, nx = 20, ny = 20)) modules <- list("randomLandscapes", "caribouMovement") paths <- list( modulePath = getSampleModules(tempdir()) ) # Set some options so example runs faster opts <- options(spades.moduleCodeChecks = FALSE, spades.loadReqdPkgs = FALSE) sim <- simInit(times = times, params = parameters, modules = modules, paths = paths) options(opts) moduleDiagram(sim) # Can also use default base::plot modDia <- depsGraph(sim, plot = TRUE) # See ?plot.igraph plot(modDia, layout = layout_as_star) # Or for more control - here, change the label "_INPUT_" to "DATA" edgeList <- depsEdgeList(sim) edgeList <- edgeList[, list(from, to)] edgeList[from == "_INPUT_", from := "Data"] edgeList[to == "_INPUT_", to := "Data"] edgeList <- unique(edgeList) ig <- graph_from_data_frame(edgeList[, list(from, to)]) plot(ig) }
This is still experimental, but this will show the hierarchical structure of
parent and children modules and return a list with an igraph
object
and an igraph
communities object, showing the groups.
Currently only tested with relatively simple structures.
moduleGraph(sim, plot, ...) ## S4 method for signature 'simList,logical' moduleGraph(sim, plot, ...) ## S4 method for signature 'simList,missing' moduleGraph(sim, plot, ...)
moduleGraph(sim, plot, ...) ## S4 method for signature 'simList,logical' moduleGraph(sim, plot, ...) ## S4 method for signature 'simList,missing' moduleGraph(sim, plot, ...)
sim |
A |
plot |
Logical indicating whether the edgelist (and subsequent graph)
will be used for plotting. If |
... |
Arguments passed to |
A list with 2 elements, an igraph()
object and an igraph
communities object.
Eliot McIntire
Parse and extract module metadata
moduleMetadata( sim, module, path = getOption("spades.modulePath", NULL), defineModuleListItems = c("name", "description", "keywords", "childModules", "authors", "version", "spatialExtent", "timeframe", "timeunit", "citation", "documentation", "reqdPkgs", "parameters", "inputObjects", "outputObjects") ) ## S4 method for signature 'missing,character,character' moduleMetadata(module, path, defineModuleListItems) ## S4 method for signature 'missing,character,missing' moduleMetadata(module, defineModuleListItems) ## S4 method for signature 'ANY,ANY,ANY' moduleMetadata( sim, module, path = getOption("spades.modulePath", NULL), defineModuleListItems = c("name", "description", "keywords", "childModules", "authors", "version", "spatialExtent", "timeframe", "timeunit", "citation", "documentation", "reqdPkgs", "parameters", "inputObjects", "outputObjects") )
moduleMetadata( sim, module, path = getOption("spades.modulePath", NULL), defineModuleListItems = c("name", "description", "keywords", "childModules", "authors", "version", "spatialExtent", "timeframe", "timeunit", "citation", "documentation", "reqdPkgs", "parameters", "inputObjects", "outputObjects") ) ## S4 method for signature 'missing,character,character' moduleMetadata(module, path, defineModuleListItems) ## S4 method for signature 'missing,character,missing' moduleMetadata(module, defineModuleListItems) ## S4 method for signature 'ANY,ANY,ANY' moduleMetadata( sim, module, path = getOption("spades.modulePath", NULL), defineModuleListItems = c("name", "description", "keywords", "childModules", "authors", "version", "spatialExtent", "timeframe", "timeunit", "citation", "documentation", "reqdPkgs", "parameters", "inputObjects", "outputObjects") )
sim |
A |
module |
Character string. Your module's name. |
path |
Character string specifying the file path to modules directory.
Default is to use the |
defineModuleListItems |
A vector of metadata entries to return values about. |
A list of module metadata, matching the structure in defineModule()
.
Alex Chubaty
## turn off code checking -- don't need it here opts <- options("spades.moduleCodeChecks" = FALSE, "spades.useRequire" = FALSE) path <- getSampleModules(tempdir()) sampleModules <- dir(path) x <- moduleMetadata(sampleModules[3], path = path) ## using simList if (require("SpaDES.tools", quietly = TRUE)) { mySim <- simInit( times = list(start = 2000.0, end = 2001.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape") ), modules = list("caribouMovement"), paths = list(modulePath = path) ) moduleMetadata(sim = mySim) } # turn code checking back on -- don't need it here options(opts)
## turn off code checking -- don't need it here opts <- options("spades.moduleCodeChecks" = FALSE, "spades.useRequire" = FALSE) path <- getSampleModules(tempdir()) sampleModules <- dir(path) x <- moduleMetadata(sampleModules[3], path = path) ## using simList if (require("SpaDES.tools", quietly = TRUE)) { mySim <- simInit( times = list(start = 2000.0, end = 2001.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape") ), modules = list("caribouMovement"), paths = list(modulePath = path) ) moduleMetadata(sim = mySim) } # turn code checking back on -- don't need it here options(opts)
These are more or less wrappers around moduleMetadata
, with the exception
that extraneous spaces and End-Of-Line characters will be removed from the
desc
arguments in defineParameters
, defineInputs
, and
defineOutputs
moduleParams(module, path) ## S4 method for signature 'character,character' moduleParams(module, path) moduleInputs(module, path) ## S4 method for signature 'character,character' moduleInputs(module, path) moduleOutputs(module, path) ## S4 method for signature 'character,character' moduleOutputs(module, path)
moduleParams(module, path) ## S4 method for signature 'character,character' moduleParams(module, path) moduleInputs(module, path) ## S4 method for signature 'character,character' moduleInputs(module, path) moduleOutputs(module, path) ## S4 method for signature 'character,character' moduleOutputs(module, path)
module |
Character string. Your module's name. |
path |
Character string specifying the file path to modules directory.
Default is to use the |
data.frame
Alex Chubaty
## easily include these tables in Rmd files using knitr path <- getSampleModules(tempdir()) sampleModules <- dir(path) p <- moduleParams(sampleModules[3], path = path) i <- moduleInputs(sampleModules[3], path = path) o <- moduleOutputs(sampleModules[3], path = path) knitr::kable(p) knitr::kable(i) knitr::kable(o)
## easily include these tables in Rmd files using knitr path <- getSampleModules(tempdir()) sampleModules <- dir(path) p <- moduleParams(sampleModules[3], path = path) i <- moduleInputs(sampleModules[3], path = path) o <- moduleOutputs(sampleModules[3], path = path) knitr::kable(p) knitr::kable(i) knitr::kable(o)
Accessor functions for the depends
and modules
slots in a simList
object.
These are included for advanced users.
depends() |
List of simulation module dependencies. (advanced) |
modules() |
List of simulation modules to be loaded. (advanced) |
inputs() |
List of loaded objects used in simulation. (advanced) |
modules(sim, hidden = FALSE) ## S4 method for signature 'simList' modules(sim, hidden = FALSE) modules(sim) <- value ## S4 replacement method for signature 'simList' modules(sim) <- value depends(sim) ## S4 method for signature 'simList' depends(sim) depends(sim) <- value ## S4 replacement method for signature 'simList' depends(sim) <- value
modules(sim, hidden = FALSE) ## S4 method for signature 'simList' modules(sim, hidden = FALSE) modules(sim) <- value ## S4 replacement method for signature 'simList' modules(sim) <- value depends(sim) ## S4 method for signature 'simList' depends(sim) depends(sim) <- value ## S4 replacement method for signature 'simList' depends(sim) <- value
sim |
A |
Logical. If TRUE, show the default core modules. |
|
value |
The object to be stored at the slot. |
Currently, only get and set methods are defined. Subset methods are not.
Returns or sets the value of the slot from the simList
object.
Alex Chubaty
SpaDES.core-package, specifically the section 1.2.7 on Modules and dependencies.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
Parse and extract a module's version
moduleVersion(module, path, sim, envir = NULL) ## S4 method for signature 'character,character,missing' moduleVersion(module, path, envir) ## S4 method for signature 'character,missing,missing' moduleVersion(module, envir) ## S4 method for signature 'character,missing,simList' moduleVersion(module, sim, envir)
moduleVersion(module, path, sim, envir = NULL) ## S4 method for signature 'character,character,missing' moduleVersion(module, path, envir) ## S4 method for signature 'character,missing,missing' moduleVersion(module, envir) ## S4 method for signature 'character,missing,simList' moduleVersion(module, sim, envir)
module |
Character string. Your module's name. |
path |
Character string specifying the file path to modules directory.
Default is to use the |
sim |
A |
envir |
Optional environment in which to store parsed code. This may be
useful if the same file is being parsed multiple times. This
function will check in that environment for the parsed file before
parsing again. If the |
numeric_version
indicating the module's version.
Alex Chubaty
# using filepath path <- getSampleModules(tempdir()) moduleVersion("caribouMovement", path) # using simList options("spades.useRequire" = FALSE) if (require("SpaDES.tools", quietly = TRUE)) { mySim <- simInit( times = list(start = 2000.0, end = 2002.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("caribouMovement"), paths = list(modulePath = path) ) moduleVersion("caribouMovement", sim = mySim) }
# using filepath path <- getSampleModules(tempdir()) moduleVersion("caribouMovement", path) # using simList options("spades.useRequire" = FALSE) if (require("SpaDES.tools", quietly = TRUE)) { mySim <- simInit( times = list(start = 2000.0, end = 2002.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("caribouMovement"), paths = list(modulePath = path) ) moduleVersion("caribouMovement", sim = mySim) }
Generate a skeleton for a new SpaDES module, a template for a
documentation file, a citation file, a license file, a ‘README.md’ file,
and a folder that contains unit tests information. newModule
is largely a
wrapper around newModuleCode
and newModuleDocumentation
.
newModuleCode
will not generate the module code.
newModuleDocumentation
will create the other files.
newModule(name, path, ..., events = NULL, envir = parent.frame()) ## S4 method for signature 'character,character' newModule(name, path, ..., events = NULL, envir = parent.frame()) ## S4 method for signature 'character,missing' newModule(name, path, ..., events = NULL, envir = parent.frame()) newModuleCode(name, path, ..., events) ## S4 method for signature 'character,character' newModuleCode(name, path, ..., events) newModuleDocumentation(name, path, ...) ## S4 method for signature 'character,character' newModuleDocumentation(name, path, ...) ## S4 method for signature 'character,missing' newModuleDocumentation(name, path, ...)
newModule(name, path, ..., events = NULL, envir = parent.frame()) ## S4 method for signature 'character,character' newModule(name, path, ..., events = NULL, envir = parent.frame()) ## S4 method for signature 'character,missing' newModule(name, path, ..., events = NULL, envir = parent.frame()) newModuleCode(name, path, ..., events) ## S4 method for signature 'character,character' newModuleCode(name, path, ..., events) newModuleDocumentation(name, path, ...) ## S4 method for signature 'character,character' newModuleDocumentation(name, path, ...) ## S4 method for signature 'character,missing' newModuleDocumentation(name, path, ...)
name |
Character string specifying the name of the new module. |
path |
Character string. Subdirectory in which to place the new module code file. The default is the current working directory. |
... |
Additional arguments. Currently, these can be either named
function definitions (which will be added to the
For
|
events |
A list of named expressions, each of which is surrounded by |
envir |
An environment where objects being passed to |
All files will be created within a subdirectory named name
within the path
:
<path>/ |_ <name>/ |_ R/ # contains additional module R scripts |_ data/ # directory for all included data |_ CHECKSUMS.txt # contains checksums for data files |_ tests/ # contains unit tests for module code |_ citation.bib # bibtex citation for the module |_ LICENSE # describes module's legal usage |_ README.md # provide overview of key aspects |_ <name>.R # module code file (incl. metadata) |_ <name>.Rmd # documentation, usage info, etc.
NULL (invisibly). The new module file is created at ‘path/name.R’, as well as ancillary files for documentation, citation, ‘LICENSE’, ‘README’, and ‘tests’ directory.
newModuleCode
is invoked for its side effect of creating new module code files.
newModuleDocumentation
is nvoked for its side effect of
creating new module documentation files.
On Windows there is currently a bug in RStudio that prevents the editor
from opening when file.edit
is called.
Similarly, in RStudio on macOS, there is an issue opening files where they
are opened in an overlaid window rather than a new tab.
file.edit
does work if the user types it at the command prompt.
A message with the correct lines to copy and paste is provided.
Alex Chubaty and Eliot McIntire
Eliot McIntire and Alex Chubaty
Other module creation helpers:
newModuleTests()
Other module creation helpers:
newModuleTests()
Other module creation helpers:
newModuleTests()
tmpdir <- tempdir2("exampleNewModule") ## create a "myModule" module in the "modules" subdirectory. newModule("myModule", tmpdir) ## create a new parent module in the "modules" subdirectory. newModule("myParentModule", tmpdir, type = "parent", children = c("child1", "child2")) unlink(tmpdir, recursive = TRUE) if (requireNamespace("ggplot2")) { # We can also specify events and functions in `newModule`; it will still get all # functions that are not specified from the module template (e.g., plotFun below) nm <- "test" modulePath <- Require::tempdir2() newModule(nm, path = modulePath, open = FALSE, events = list( init = { sim <- Init(sim) # finds definition below sim <- scheduleEvent(sim, start(sim) + 1, eventType = "plot") }, plot = { plotFun(sim) # finds the templated plotFun sim <- scheduleEvent(sim, time(sim) + 1, eventType = "plot") } , ), Init = function(sim) { # replaces Init definition from template sim$a <- 1 return(sim) } ) out <- simInitAndSpades(module = nm, paths = list(modulePath = modulePath)) # clean up unlink(dir(modulePath, pattern = nm, full.names = TRUE), recursive = TRUE) }
tmpdir <- tempdir2("exampleNewModule") ## create a "myModule" module in the "modules" subdirectory. newModule("myModule", tmpdir) ## create a new parent module in the "modules" subdirectory. newModule("myParentModule", tmpdir, type = "parent", children = c("child1", "child2")) unlink(tmpdir, recursive = TRUE) if (requireNamespace("ggplot2")) { # We can also specify events and functions in `newModule`; it will still get all # functions that are not specified from the module template (e.g., plotFun below) nm <- "test" modulePath <- Require::tempdir2() newModule(nm, path = modulePath, open = FALSE, events = list( init = { sim <- Init(sim) # finds definition below sim <- scheduleEvent(sim, start(sim) + 1, eventType = "plot") }, plot = { plotFun(sim) # finds the templated plotFun sim <- scheduleEvent(sim, time(sim) + 1, eventType = "plot") } , ), Init = function(sim) { # replaces Init definition from template sim$a <- 1 return(sim) } ) out <- simInitAndSpades(module = nm, paths = list(modulePath = modulePath)) # clean up unlink(dir(modulePath, pattern = nm, full.names = TRUE), recursive = TRUE) }
Create template testing structures for new modules
newModuleTests(name, path, open, useGitHub) ## S4 method for signature 'character,character,logical,logical' newModuleTests(name, path, open, useGitHub)
newModuleTests(name, path, open, useGitHub) ## S4 method for signature 'character,character,logical,logical' newModuleTests(name, path, open, useGitHub)
name |
Character string specifying the name of the new module. |
path |
Character string. Subdirectory in which to place the new module code file. The default is the current working directory. |
open |
Logical. Should the new module file be opened after creation?
Default |
useGitHub |
Logical indicating whether GitHub will be used.
If |
NULL (invisibly). Invoked for its side effect of creating new module test files.
Eliot McIntire and Alex Chubaty
Other module creation helpers:
newModule()
simInit
or spades
callThis does an rbindlist(sim$._objectsCreated)
.
This object in the sim
records the yellow message that reports on when objects are created.
newObjectsCreated(sim)
newObjectsCreated(sim)
sim |
A |
The data.table
of the objects created, alongside the current(sim)
at each moment of creation.
Shows a progress bar that is scaled to simulation end time.
newProgressBar(sim) setProgressBar(sim)
newProgressBar(sim) setProgressBar(sim)
sim |
A |
The progress bar object is stored in a separate environment, #' .pkgEnv
.
invoked for side effect of creating progress bar
Alex Chubaty and Eliot McIntire
Initialize a project with subdirectories ‘cache/’, ‘modules/’,
‘inputs/’, ‘outputs/’, and setPaths
accordingly.
If invoked from Rstudio, will also create a new Rstudio project file.
newProject(name, path, open) ## S4 method for signature 'character,character,logical' newProject(name, path, open) ## S4 method for signature 'character,character,missing' newProject(name, path, open)
newProject(name, path, open) ## S4 method for signature 'character,character,logical' newProject(name, path, open) ## S4 method for signature 'character,character,missing' newProject(name, path, open)
name |
project name (name of project directory) |
path |
path to directory in which to create the project directory |
open |
Logical. Should the new project file be opened after creation?
Default |
invoked for side effect of project file creation
myProjDir <- newProject("myProject", tempdir()) dir.exists(file.path(myProjDir, "cache")) dir.exists(file.path(myProjDir, "inputs")) dir.exists(file.path(myProjDir, "modules")) dir.exists(file.path(myProjDir, "outputs")) unlink(myProjDir, recursive = TRUE) ## cleanup
myProjDir <- newProject("myProject", tempdir()) dir.exists(file.path(myProjDir, "cache")) dir.exists(file.path(myProjDir, "inputs")) dir.exists(file.path(myProjDir, "modules")) dir.exists(file.path(myProjDir, "outputs")) unlink(myProjDir, recursive = TRUE) ## cleanup
Create new module code file
newProjectCode(name, path, open) ## S4 method for signature 'character,character,logical' newProjectCode(name, path, open = interactive())
newProjectCode(name, path, open) ## S4 method for signature 'character,character,logical' newProjectCode(name, path, open = interactive())
name |
project name (name of project directory) |
path |
path to directory in which to create the project directory |
open |
Logical. Should the new project file be opened after creation?
Default |
invoked for side effect of project file creation
Alex Chubaty
Provides the text to be sent to warning
in each module as the default switch
case.
noEventWarning(sim)
noEventWarning(sim)
sim |
A |
A text string specifying the event name and module for which there is no event
Create a sequence diagram illustrating the data object dependencies of a
simulation. Offers a more detailed view of specific objects than does
plotting the depsEdgeList
directly with moduleDiagram()
.
objectDiagram(sim, ...) ## S4 method for signature 'simList' objectDiagram(sim, ...)
objectDiagram(sim, ...) ## S4 method for signature 'simList' objectDiagram(sim, ...)
sim |
A |
... |
Additional arguments passed to |
Plots a sequence diagram, invisibly returning a DiagrammeR::mermaid
object.
Alex Chubaty
DiagrammeR::mermaid
.
if (requireNamespace("DiagrammeR", quietly = TRUE)) { sim <- simInit() objectDiagram(sim) # if there are lots of objects, may need to increase width and/or height objectDiagram(sim, height = 3000, width = 3000) }
if (requireNamespace("DiagrammeR", quietly = TRUE)) { sim <- simInit() objectDiagram(sim) # if there are lots of objects, may need to increase width and/or height objectDiagram(sim, height = 3000, width = 3000) }
simList
This will create active bindings amongst the synonyms. To minimize copying,
the first one that exists in the character vector will become the "canonical"
object. All others named in the character vector will be activeBindings
to
that canonical one. This synonym list will be assigned to the envir
,
as an object named objectSynonyms
. That object will have an attribute
called, bindings
indicating which one is the canonical one and which
is/are the activeBindings.
EXPERIMENTAL: If the objects are removed during a
spades
call by, say, a module, then at the end of the event, the
spades
call will replace the bindings. In other words, if a module
deletes the object, it will "come back". This may not always be desired.
objectSynonyms(envir, synonyms)
objectSynonyms(envir, synonyms)
envir |
An environment, which in the context of SpaDES.core is usually
a |
synonyms |
A list of synonym character vectors, such as
|
This is very experimental and only has minimal tests. Please report if this is not working, and under what circumstances (e.g., please submit a reproducible example to our issues tracker)
This function will append any new objectSynonym
to any pre-existing
objectSynonym
in the envir
. Similarly, this function assumes
transitivity, i.e., if age
and ageMap
are synonyms, and ageMap
and timeSinceFire
are synonyms, then age
and timeSinceFire
must be synonyms.
Active bindings in the envir
so that all synonyms point to the same
canonical object, e.g., they would be at envir[[synonym[[1]][1]]]
and
envir[[synonym[[1]][2]]]
, if a list of length one is passed into
synonyms
, with a character vector of length two. See examples.
sim <- simInit() sim$age <- 1:10; sim <- objectSynonyms(sim, list(c("age", "ageMap"))) identical(sim$ageMap, sim$age) sim$age <- 4 identical(sim$ageMap, sim$age) sim$ageMap <- 2:5 sim$ageMap[3] <- 11 identical(sim$ageMap, sim$age) # Also works to pass it in as an object objectSynonyms <- list(c("age", "ageMap")) sim <- simInit(objects = list(objectSynonyms = objectSynonyms)) identical(sim$ageMap, sim$age) # they are NULL at this point sim$age <- 1:10 identical(sim$ageMap, sim$age) # they are not NULL at this point ## More complicated, with 'updating' i.e., you can add new synonyms to previous sim <- simInit() os <- list(c("age", "ageMap"), c("vegMap", "veg"), c("studyArea", "studyArea2")) os2 <- list(c("ageMap", "timeSinceFire", "tsf"), c("systime", "systime2"), c("vegMap", "veg")) sim <- objectSynonyms(sim, os) sim <- objectSynonyms(sim, os2) # check sim$objectSynonyms
sim <- simInit() sim$age <- 1:10; sim <- objectSynonyms(sim, list(c("age", "ageMap"))) identical(sim$ageMap, sim$age) sim$age <- 4 identical(sim$ageMap, sim$age) sim$ageMap <- 2:5 sim$ageMap[3] <- 11 identical(sim$ageMap, sim$age) # Also works to pass it in as an object objectSynonyms <- list(c("age", "ageMap")) sim <- simInit(objects = list(objectSynonyms = objectSynonyms)) identical(sim$ageMap, sim$age) # they are NULL at this point sim$age <- 1:10 identical(sim$ageMap, sim$age) # they are not NULL at this point ## More complicated, with 'updating' i.e., you can add new synonyms to previous sim <- simInit() os <- list(c("age", "ageMap"), c("vegMap", "veg"), c("studyArea", "studyArea2")) os2 <- list(c("ageMap", "timeSinceFire", "tsf"), c("systime", "systime2"), c("vegMap", "veg")) sim <- objectSynonyms(sim, os) sim <- objectSynonyms(sim, os2) # check sim$objectSynonyms
The [[
and $
operators provide "shortcuts" for accessing
objects in the simulation environment.
I.e., instead of using envir(sim)$object
or envir(sim)[["object"]]
,
one can simply use sim$object
or sim[["object"]]
.
objs(sim, ...) ## S4 method for signature 'simList' objs(sim, ...) objs(sim) <- value ## S4 replacement method for signature 'simList' objs(sim) <- value moduleObjects(sim, module, path) findObjects(objects, sim, module, path)
objs(sim, ...) ## S4 method for signature 'simList' objs(sim, ...) objs(sim) <- value ## S4 replacement method for signature 'simList' objs(sim) <- value moduleObjects(sim, module, path) findObjects(objects, sim, module, path)
sim |
A |
... |
passed to |
value |
objects to assign to the |
module |
Character vector of module name(s) |
path |
The path to the module., i.e., the |
objects |
A character vector of length >= 1 with name(s) of objects to look
for in the metadata. This is used in a |
objs
can take ...
arguments passed to ls
,
allowing, e.g. all.names=TRUE
objs<-
requires takes a named list of values to be assigned in
the simulation environment.
Returns or sets a list of objects in the simList
environment.
moduleObjects
returns a data.table with 4 columns, module
, objectName
, type
, and desc
,
pulled directly from the object metadata in the createsOutputs
and expectsInputs
. These
will be determined either from a simList
or from the module source code.
findObjects
returns a data.table similar to moduleObjects
, but with only the
objects provided by objects
.
SpaDES.core-package, specifically the section 1.2.1 on Simulation Parameters.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
packages()
,
params()
,
paths()
,
progressInterval()
,
times()
# findObjects path <- getSampleModules(tempdir()) findObjects(path = path, module = dir(path), objects = "caribou")
# findObjects path <- getSampleModules(tempdir()) findObjects(path = path, module = dir(path), objects = "caribou")
simList
Recursively, runs reproducible::objSize()
on the simList
environment,
so it estimates the correct size of functions stored there (e.g., with their enclosing
environments) plus, it adds all other "normal" elements of the simList
, e.g.,
objSize(completed(sim))
.
The output is structured into 2 elements: the sim
environment and all its objects,
and the other slots in the simList
(e.g., events, completed, modules, etc.).
The returned object also has an attribute, "total", which shows the total size.
## S3 method for class 'simList' objSize(x, quick = TRUE, ...)
## S3 method for class 'simList' objSize(x, quick = TRUE, ...)
x |
An object |
quick |
Logical. If |
... |
Additional arguments (currently unused), enables backwards compatible use. |
an estimate of the size of the object, in bytes.
a <- simInit(objects = list(d = 1:10, b = 2:20)) objSize(a) utils::object.size(a)
a <- simInit(objects = list(d = 1:10, b = 2:20)) objSize(a) utils::object.size(a)
This is just a convenience wrapper for opening several modules at once, recursively.
A module is defined as any file that ends in .R
or .r
and has a
directory name identical to its filename. Thus, this must be case sensitive.
openModules(name, path) ## S4 method for signature 'character,character' openModules(name, path) ## S4 method for signature 'missing,missing' openModules() ## S4 method for signature 'missing,character' openModules(path) ## S4 method for signature 'character,missing' openModules(name) ## S4 method for signature 'simList,missing' openModules(name)
openModules(name, path) ## S4 method for signature 'character,character' openModules(name, path) ## S4 method for signature 'missing,missing' openModules() ## S4 method for signature 'missing,character' openModules(path) ## S4 method for signature 'character,missing' openModules(name) ## S4 method for signature 'simList,missing' openModules(name)
name |
Character vector with names of modules to open. If missing, then all modules will be opened within the base directory. |
path |
Character string of length 1. The base directory within which there are only module subdirectories. |
NULL (invisibly). All file are open via file.edit
.
On Windows there is currently a bug in RStudio that prevents the editor
from opening when file.edit
is called. file.edit
does work if the
user types it at the command prompt. A message with the correct lines to copy
and paste is provided.
Eliot McIntire
if (interactive()) openModules("modules")
if (interactive()) openModules("modules")
Accessor functions for the outputs
slots in a simList
object.
If a module saves a file to disk during events, it can be useful to keep track
of the files that are saved e.g., for saveSimList()
so that all files can
be added to the archive. In addition to setting outputs
at the simInit
stage, a module developer can also put this in a using any saving mechanism that
is relevant (e.g., qs::qsave
, saveRDS
etc.). When a module event does this
it can be useful to register that saved file. registerOutputs
offers an additional
mechanism to do this. See examples.
outputs(sim) ## S4 method for signature 'simList' outputs(sim) outputs(sim) <- value ## S4 replacement method for signature 'simList' outputs(sim) <- value registerOutputs(filename, sim, ...) outputArgs(sim) ## S4 method for signature 'simList' outputArgs(sim) outputArgs(sim) <- value ## S4 replacement method for signature 'simList' outputArgs(sim) <- value
outputs(sim) ## S4 method for signature 'simList' outputs(sim) outputs(sim) <- value ## S4 replacement method for signature 'simList' outputs(sim) <- value registerOutputs(filename, sim, ...) outputArgs(sim) ## S4 method for signature 'simList' outputArgs(sim) outputArgs(sim) <- value ## S4 replacement method for signature 'simList' outputArgs(sim) <- value
sim |
A |
value |
The object to be stored at the slot. See Details. |
filename |
The filename to register in the |
... |
Not used. |
These functions are one of three mechanisms to add information about which output files to save.
As arguments to a simInit
call. Specifically, inputs
or outputs
.
See ?simInit
.
With the outputs(simList)
function call.
By adding a function called .inputObjects
inside a module, which will be executed
during the simInit
call. This last way is the most "modular" way to create
default data sets for your model.
See below for more details.
Note using registerOutputs
: a user can pass any other
arguments to registerOutputs
that are in the
outputs(sim)
data.frame, such as objectName
, fun
, package
, though these
will not be used to save the files as this function is only about
registering an output that has already been saved.
A simList
which will be the sim
passed in with a new object registered
in the outputs(sim)
simInit
outputs
accepts a data.frame similar to the inputs
data.frame, but
with up to 6 columns.
objectName |
required, character string indicating the name of the object
in the simList that will be saved to disk (without the sim$ prefix). |
file |
optional, a character string indicating the file path to save to.
The default is to concatenate objectName with the model timeunit and
saveTime , separated by underscore, '_ '. So a default filename would be
"Fires_year1.rds" . |
fun |
optional, a character string indicating the function to use to
save that file. The default is saveRDS() |
package |
optional character string indicating the package in
which to find the fun ); |
saveTime |
optional numeric, indicating when in simulation time the file
should be saved. The default is the lowest priority at end(sim) ,
i.e., at the very end. |
arguments |
is a list of lists of named arguments, one list for each
fun . For example, if fun = "write.csv" ,
arguments = list(row.names = TRUE) will pass the argument
row.names = TRUE to write.csv If there is only one list,
then it is assumed to apply to all files and will be recycled as per normal R
rules of recycling for each fun . |
See the modules vignette for more details (browseVignettes("SpaDES.core")
).
The automatic file type handling only adds the correct extension from a given
fun
and package
. It does not do the inverse, from a given extension find the
correct fun
and package
.
registerOutputs()
which enables files that are saved to be added to
the simList
using the outputs(sim)
mechanism, so the files that are saved
during a module event can be tracked at the simList
level. saveSimList()
which will optionally add all the outputs that are tracked into an archive.
####################### # outputs ####################### tmpdir <- file.path(tempdir(), "outputs") |> checkPath(create = TRUE) tmpFile <- file.path(tmpdir, "temp.rds") tempObj <- 1:10 # Can add data.frame of outputs directly into simInit call sim <- simInit(objects = c("tempObj"), outputs = data.frame(objectName = "tempObj"), paths = list(outputPath = tmpdir)) outputs(sim) # To see what will be saved, when, what filename sim <- spades(sim) outputs(sim) # To see that it was saved, when, what filename # Also can add using assignment after a simList object has been made sim <- simInit(objects = c("tempObj"), paths = list(outputPath = tmpdir)) outputs(sim) <- data.frame(objectName = "tempObj", saveTime = 1:10) sim <- spades(sim) outputs(sim) # To see that it was saved, when, what filename. # can do highly variable saving tempObj2 <- paste("val", 1:10) df1 <- data.frame(col1 = tempObj, col2 = tempObj2) sim <- simInit(objects = c("tempObj", "tempObj2", "df1"), paths = list(outputPath = tmpdir)) outputs(sim) <- data.frame( objectName = c(rep("tempObj", 2), rep("tempObj2", 3), "df1"), saveTime = c(c(1, 4), c(2, 6, 7), end(sim)), fun = c(rep("saveRDS", 5), "write.csv"), package = c(rep("base", 5), "utils"), stringsAsFactors = FALSE) # since write.csv has a default of adding a column, x, with rownames, must add additional # argument for 6th row in data.frame (corresponding to the write.csv function) outputArgs(sim)[[6]] <- list(row.names = FALSE) sim <- spades(sim) outputs(sim) # read one back in just to test it all worked as planned newObj <- read.csv(dir(tmpdir, pattern = "year10.csv", full.name = TRUE)) newObj # using saving with SpaDES-aware methods # To see current ones SpaDES can do .saveFileExtensions() library(terra) ras <- rast(ncol = 4, nrow = 5) ras[] <- 1:20 sim <- simInit(objects = c("ras"), paths = list(outputPath = tmpdir)) outputs(sim) <- data.frame( file = "test", fun = "writeRaster", package = "terra", objectName = "ras", stringsAsFactors = FALSE) simOut <- spades(sim) outputs(simOut) newRas <- rast(dir(tmpdir, full.name = TRUE, pattern = ".tif")[1]) all.equal(newRas, ras) # Should be TRUE # Clean up after unlink(tmpdir, recursive = TRUE) # For `registerOutputs` sim <- simInit() # This would normally be a save call, e.g., `writeRaster` tf <- reproducible::tempfile2(fileext = ".tif") sim <- registerOutputs(sim, filename = tf) # Using a pipe tf <- reproducible::tempfile2(fileext = ".rds") sim$a <- 1 sim <- saveRDS(sim$a, tf) |> registerOutputs() # confirm: outputs(sim) # has object --> saved = TRUE
####################### # outputs ####################### tmpdir <- file.path(tempdir(), "outputs") |> checkPath(create = TRUE) tmpFile <- file.path(tmpdir, "temp.rds") tempObj <- 1:10 # Can add data.frame of outputs directly into simInit call sim <- simInit(objects = c("tempObj"), outputs = data.frame(objectName = "tempObj"), paths = list(outputPath = tmpdir)) outputs(sim) # To see what will be saved, when, what filename sim <- spades(sim) outputs(sim) # To see that it was saved, when, what filename # Also can add using assignment after a simList object has been made sim <- simInit(objects = c("tempObj"), paths = list(outputPath = tmpdir)) outputs(sim) <- data.frame(objectName = "tempObj", saveTime = 1:10) sim <- spades(sim) outputs(sim) # To see that it was saved, when, what filename. # can do highly variable saving tempObj2 <- paste("val", 1:10) df1 <- data.frame(col1 = tempObj, col2 = tempObj2) sim <- simInit(objects = c("tempObj", "tempObj2", "df1"), paths = list(outputPath = tmpdir)) outputs(sim) <- data.frame( objectName = c(rep("tempObj", 2), rep("tempObj2", 3), "df1"), saveTime = c(c(1, 4), c(2, 6, 7), end(sim)), fun = c(rep("saveRDS", 5), "write.csv"), package = c(rep("base", 5), "utils"), stringsAsFactors = FALSE) # since write.csv has a default of adding a column, x, with rownames, must add additional # argument for 6th row in data.frame (corresponding to the write.csv function) outputArgs(sim)[[6]] <- list(row.names = FALSE) sim <- spades(sim) outputs(sim) # read one back in just to test it all worked as planned newObj <- read.csv(dir(tmpdir, pattern = "year10.csv", full.name = TRUE)) newObj # using saving with SpaDES-aware methods # To see current ones SpaDES can do .saveFileExtensions() library(terra) ras <- rast(ncol = 4, nrow = 5) ras[] <- 1:20 sim <- simInit(objects = c("ras"), paths = list(outputPath = tmpdir)) outputs(sim) <- data.frame( file = "test", fun = "writeRaster", package = "terra", objectName = "ras", stringsAsFactors = FALSE) simOut <- spades(sim) outputs(simOut) newRas <- rast(dir(tmpdir, full.name = TRUE, pattern = ".tif")[1]) all.equal(newRas, ras) # Should be TRUE # Clean up after unlink(tmpdir, recursive = TRUE) # For `registerOutputs` sim <- simInit() # This would normally be a save call, e.g., `writeRaster` tf <- reproducible::tempfile2(fileext = ".tif") sim <- registerOutputs(sim, filename = tf) # Using a pipe tf <- reproducible::tempfile2(fileext = ".rds") sim$a <- 1 sim <- saveRDS(sim$a, tf) |> registerOutputs() # confirm: outputs(sim) # has object --> saved = TRUE
Get module or simulation package dependencies
packages(sim, modules, paths, filenames, envir, clean = FALSE, ...) ## S4 method for signature 'ANY' packages(sim, modules, paths, filenames, envir, clean = FALSE, ...)
packages(sim, modules, paths, filenames, envir, clean = FALSE, ...) ## S4 method for signature 'ANY' packages(sim, modules, paths, filenames, envir, clean = FALSE, ...)
sim |
A |
modules |
Character vector, specifying the name or vector of names of module(s) |
paths |
Character vector, specifying the name or vector of names of paths(s) for
those modules. If path not specified, it will be taken from
|
filenames |
Character vector specifying filenames of modules (i.e.
combined path & module. If this is specified, then |
envir |
Optional environment in which to store parsed code. This may be
useful if the same file is being parsed multiple times. This
function will check in that environment for the parsed file before
parsing again. If the |
clean |
Optional logical. If |
... |
All |
A sorted character vector of package names.
Alex Chubaty & Eliot McIntire
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
params()
,
paths()
,
progressInterval()
,
times()
This function is intended to be part of module code and will test whether
the value of a parameter within the current module matches the value of the
same parameter in other modules. This is a test for parameters that might expect
to be part of a params = list(.globals = list(someParam = "test"))
passed to simInit()
.
paramCheckOtherMods( sim, paramToCheck, moduleToUse = "all", ifSetButDifferent = c("error", "warning", "message", "silent"), verbose = getOption("reproducible.verbose") )
paramCheckOtherMods( sim, paramToCheck, moduleToUse = "all", ifSetButDifferent = c("error", "warning", "message", "silent"), verbose = getOption("reproducible.verbose") )
sim |
A |
paramToCheck |
A character string, length one, of a parameter name to check and compare between the current module and one or more or all others |
moduleToUse |
A character vector of module names to check against. This can be
|
ifSetButDifferent |
A character string indicating whether to |
verbose |
Logical or Numeric, follows |
It is considered a "fail" under several conditions:
current module has a value that is not NULL
or "default"
and another module
has a different value;
there is more than one value for the paramToCheck
in the other modules,
so it is ambiguous which one to return.
Either the current module is different than other modules, unless it is "default" or NULL.
If the value of the paramToCheck
in the current module is either NULL
or
"default"
, and there is only one other value across all modules named in moduleToUse
,
then this will return a character string with the value of the single parameter value
in the other module(s).
It will return the current value if there are no other modules with the same parameter.
params
, P
and Par
(an active binding, like "mod") access the parameter
slot in the simList
.
params
has a replace method, so can be used to update a parameter value.
params(sim) ## S4 method for signature 'simList' params(sim) params(sim) <- value ## S4 replacement method for signature 'simList' params(sim) <- value P(sim, param, module) P(sim, param, module) <- value parameters(sim, asDF = FALSE) ## S4 method for signature 'simList' parameters(sim, asDF = FALSE)
params(sim) ## S4 method for signature 'simList' params(sim) params(sim) <- value ## S4 replacement method for signature 'simList' params(sim) <- value P(sim, param, module) P(sim, param, module) <- value parameters(sim, asDF = FALSE) ## S4 method for signature 'simList' parameters(sim, asDF = FALSE)
sim |
A |
value |
The parameter value to be set (in the corresponding |
param |
Optional character string indicating which parameter to choose. |
module |
Optional character string indicating which module params should come from. |
asDF |
Logical. For |
parameters
will extract only the metadata with the metadata defaults,
NOT the current values that may be overwritten by a user. See examples.
Returns or sets the value of the slot from the simList
object.
The differences between P()
, params()
and being explicit with passing arguments
are mostly a question of speed and code compactness.
The computationally fastest way to get a parameter is to specify moduleName
and parameter name,
as in: P(sim, "paramName", "moduleName")
(replacing moduleName
and paramName
with your
specific module and parameter names), but it is more verbose than P(sim)$paramName
.
Note: the important part for speed (e.g., 2-4x faster) is specifying the moduleName
.
Specifying the parameter name is <5% faster.
SpaDES.core-package, specifically the section 1.2.1 on Simulation parameters.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
paths()
,
progressInterval()
,
times()
s <- simInit() # add a parameter to tmp module params(s)$tmp <- list(a = 1) # Only work inside a module, inside a function with `sim` is an argument # P(s, "a") # get "a" parameter inside the current module # Par$a # same. Get "a" parameter inside the current module if (requireNamespace("NLMR", quietly = TRUE) && requireNamespace("SpaDES.tools", quietly = TRUE)) { opts <- options("spades.moduleCodeChecks" = FALSE) # not necessary for example modules <- list("randomLandscapes") paths <- list(modulePath = getSampleModules(tempdir())) mySim <- simInit(modules = modules, paths = paths, params = list(.globals = list(stackName = "landscape"))) # update some parameters using assignment -- currently only params will work params(mySim)$randomLandscapes$nx <- 200 params(mySim)$randomLandscapes$ny <- 200 parameters(mySim) # Does not contain these user overridden values # These next 2 are same here because they are not within a module P(mySim) # Does contain the user overridden values params(mySim) # Does contain the user overridden values # NOTE -- deleting a parameter will affect params and P, not parameters params(mySim)$randomLandscapes$nx <- NULL params(mySim)$randomLandscapes$ny <- NULL parameters(mySim) # Shows nx and ny # These next 2 are same here because they are not within a module P(mySim) # nx and ny are Gone params(mySim) # nx and ny are Gone options(opts) # reset }
s <- simInit() # add a parameter to tmp module params(s)$tmp <- list(a = 1) # Only work inside a module, inside a function with `sim` is an argument # P(s, "a") # get "a" parameter inside the current module # Par$a # same. Get "a" parameter inside the current module if (requireNamespace("NLMR", quietly = TRUE) && requireNamespace("SpaDES.tools", quietly = TRUE)) { opts <- options("spades.moduleCodeChecks" = FALSE) # not necessary for example modules <- list("randomLandscapes") paths <- list(modulePath = getSampleModules(tempdir())) mySim <- simInit(modules = modules, paths = paths, params = list(.globals = list(stackName = "landscape"))) # update some parameters using assignment -- currently only params will work params(mySim)$randomLandscapes$nx <- 200 params(mySim)$randomLandscapes$ny <- 200 parameters(mySim) # Does not contain these user overridden values # These next 2 are same here because they are not within a module P(mySim) # Does contain the user overridden values params(mySim) # Does contain the user overridden values # NOTE -- deleting a parameter will affect params and P, not parameters params(mySim)$randomLandscapes$nx <- NULL params(mySim)$randomLandscapes$ny <- NULL parameters(mySim) # Shows nx and ny # These next 2 are same here because they are not within a module P(mySim) # nx and ny are Gone params(mySim) # nx and ny are Gone options(opts) # reset }
Accessor functions for the paths
slot in a simList
object.
dataPath
will return file.path(modulePath(sim), currentModule(sim), "data")
.
dataPath
, like currentModule
,is namespaced. This means that when
it is used inside a module, then it will return that model-specific information.
For instance, if used inside a module called "movingAgent"
,
then currentModule(sim)
will return "movingAgent"
, and dataPath(sim)
will return
file.path(modulePath(sim), "movingAgent", "data")
paths(sim) ## S4 method for signature 'simList' paths(sim) paths(sim) <- value ## S4 replacement method for signature 'simList' paths(sim) <- value cachePath(sim) ## S4 method for signature 'simList' cachePath(sim) cachePath(sim) <- value ## S4 replacement method for signature 'simList' cachePath(sim) <- value inputPath(sim) ## S4 method for signature 'simList' inputPath(sim) inputPath(sim) <- value ## S4 replacement method for signature 'simList' inputPath(sim) <- value outputPath(sim) ## S4 method for signature 'simList' outputPath(sim) outputPath(sim) <- value ## S4 replacement method for signature 'simList' outputPath(sim) <- value figurePath(sim) ## S4 method for signature 'simList' figurePath(sim) logPath(sim) ## S4 method for signature 'simList' logPath(sim) modulePath(sim, module) ## S4 method for signature 'simList' modulePath(sim, module) modulePath(sim) <- value ## S4 replacement method for signature 'simList' modulePath(sim) <- value scratchPath(sim) ## S4 method for signature 'simList' scratchPath(sim) scratchPath(sim) <- value ## S4 replacement method for signature 'simList' scratchPath(sim) <- value rasterPath(sim) ## S4 method for signature 'simList' rasterPath(sim) rasterPath(sim) <- value ## S4 replacement method for signature 'simList' rasterPath(sim) <- value terraPath(sim) ## S4 method for signature 'simList' terraPath(sim) terraPath(sim) <- value ## S4 replacement method for signature 'simList' terraPath(sim) <- value dataPath(sim) ## S4 method for signature 'simList' dataPath(sim)
paths(sim) ## S4 method for signature 'simList' paths(sim) paths(sim) <- value ## S4 replacement method for signature 'simList' paths(sim) <- value cachePath(sim) ## S4 method for signature 'simList' cachePath(sim) cachePath(sim) <- value ## S4 replacement method for signature 'simList' cachePath(sim) <- value inputPath(sim) ## S4 method for signature 'simList' inputPath(sim) inputPath(sim) <- value ## S4 replacement method for signature 'simList' inputPath(sim) <- value outputPath(sim) ## S4 method for signature 'simList' outputPath(sim) outputPath(sim) <- value ## S4 replacement method for signature 'simList' outputPath(sim) <- value figurePath(sim) ## S4 method for signature 'simList' figurePath(sim) logPath(sim) ## S4 method for signature 'simList' logPath(sim) modulePath(sim, module) ## S4 method for signature 'simList' modulePath(sim, module) modulePath(sim) <- value ## S4 replacement method for signature 'simList' modulePath(sim) <- value scratchPath(sim) ## S4 method for signature 'simList' scratchPath(sim) scratchPath(sim) <- value ## S4 replacement method for signature 'simList' scratchPath(sim) <- value rasterPath(sim) ## S4 method for signature 'simList' rasterPath(sim) rasterPath(sim) <- value ## S4 replacement method for signature 'simList' rasterPath(sim) <- value terraPath(sim) ## S4 method for signature 'simList' terraPath(sim) terraPath(sim) <- value ## S4 replacement method for signature 'simList' terraPath(sim) <- value dataPath(sim) ## S4 method for signature 'simList' dataPath(sim)
sim |
A |
value |
The parameter value to be set (in the corresponding |
module |
The optional character string of the module(s) whose paths are desired. If omitted, will return all module paths, if more than one exist. |
These are ways to add or access the file paths used by spades()
.
There are five file paths: cachePath
, modulePath
,
inputPath
, outputPath
, and rasterPath
.
Each has a function to get or set the value in a simList
object.
If no paths are specified, the defaults are as follows:
cachePath
: getOption("reproducible.cachePath")
;
inputPath
: getOption("spades.modulePath")
;
modulePath
: getOption("spades.inputPath")
;
outputPath
: getOption("spades.outputPath")
;
rasterPath
: file.path(getOption("spades.scratchPath"), "raster")
;
scratchPath
: getOption("spades.scratchPath")
;
terraPath
: file.path(getOption("spades.scratchPath"), "terra")
Returns or sets the value of the slot from the simList
object.
SpaDES.core-package, specifically the section 1.2.4 on Simulation Paths.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
progressInterval()
,
times()
simList
objectsExtends quickPlot::Plot
for simList
objects.
## S4 method for signature 'simList' Plot( ..., new = FALSE, addTo = NULL, gp = gpar(), gpText = gpar(), gpAxis = gpar(), axes = FALSE, speedup = 1, size = 5, cols = NULL, col = NULL, zoomExtent = NULL, visualSqueeze = NULL, legend = TRUE, legendRange = NULL, legendText = NULL, pch = 19, title = NULL, na.color = "#FFFFFF00", zero.color = NULL, length = NULL, arr = NULL, plotFn = "plot", verbose = getOption("quickPlot.verbose") )
## S4 method for signature 'simList' Plot( ..., new = FALSE, addTo = NULL, gp = gpar(), gpText = gpar(), gpAxis = gpar(), axes = FALSE, speedup = 1, size = 5, cols = NULL, col = NULL, zoomExtent = NULL, visualSqueeze = NULL, legend = TRUE, legendRange = NULL, legendText = NULL, pch = 19, title = NULL, na.color = "#FFFFFF00", zero.color = NULL, length = NULL, arr = NULL, plotFn = "plot", verbose = getOption("quickPlot.verbose") )
... |
A combination of |
new |
Logical. If |
addTo |
Character vector, with same length as |
gp |
A |
gpText |
A |
gpAxis |
A |
axes |
Logical or |
speedup |
Numeric. The factor by which the number of pixels is divided by to plot rasters. See Details. |
size |
Numeric. The size, in points, for |
cols |
(also |
col |
(also |
zoomExtent |
An |
visualSqueeze |
Numeric. The proportion of the white space to be used for plots. Default is 0.75. |
legend |
Logical indicating whether a legend should be drawn.
Default is |
legendRange |
Numeric vector giving values that, representing the lower
and upper bounds of a legend (i.e., |
legendText |
Character vector of legend value labels.
Defaults to |
pch |
see |
title |
Logical or character string. If logical, it
indicates whether to print the object name as the title
above the plot. If a character string, it will print this
above the plot. NOTE: the object name is used with |
na.color |
Character string indicating the colour for |
zero.color |
Character string indicating the colour for zero values, when zero is the minimum value, otherwise, zero is treated as any other colour. Default transparent. |
length |
Numeric. Optional length, in inches, of the arrow head. |
arr |
A vector of length 2 indicating a desired arrangement of plot areas indicating number of rows, number of columns. Default NULL, meaning let Plot function do it automatically. |
plotFn |
An optional function name to do the plotting internally, e.g., "barplot" to get a barplot() call. Default "plot". |
verbose |
Numeric or logical. If |
See quickPlot::Plot
.
This method strips out stuff from a simList
class object that would make it otherwise not
reproducibly digestible between sessions, operating systems, or machines.
This will likely still not allow identical digest results across R versions.
invoked for side effect of plotting
quickPlot::Plot
Plot
wrapper intended for use in a SpaDES moduleThis is a single function call that allows a user to change which format in which
the plots will occur.
Specifically, the two common formats would be to "screen"
or to disk as an image file,
such as "png"
.
This has currently been tested with ggplot2
, RasterLayer
, and tmap
objects.
The default (or change with e.g., fn = "print", usePlot = FALSE
) uses
Plot
internally, so individual plots may be rearranged. When saved to
disk (e.g., via type = 'png'
), then Plot
will not be used and the single object
that is the result of this Plots
call will be saved to disk.
This function requires at least 2 things: a plotting function and arguments passed
to that function (which could include data
, but commonly would simply be named
arguments required by fn
).
See below and examples.
Plots( data, fn, filename, types = quote(params(sim)[[currentModule(sim)]]$.plots), path = quote(figurePath(sim)), .plotInitialTime = quote(params(sim)[[currentModule(sim)]]$.plotInitialTime), ggsaveArgs = list(), usePlot = getOption("spades.PlotsUsePlot", FALSE), deviceArgs = list(), ... )
Plots( data, fn, filename, types = quote(params(sim)[[currentModule(sim)]]$.plots), path = quote(figurePath(sim)), .plotInitialTime = quote(params(sim)[[currentModule(sim)]]$.plotInitialTime), ggsaveArgs = list(), usePlot = getOption("spades.PlotsUsePlot", FALSE), deviceArgs = list(), ... )
data |
An (optional) arbitrary data object. If supplied, it will be passed as
the first argument to |
fn |
An arbitrary plotting function. If not provided, defaults to using |
filename |
A name that will be the base for the files that will be saved, i.e,
do not supply the file extension, as this will be determined based on |
types |
Character vector, zero or more of types. If used within a module, this
will be deduced from the |
path |
Currently a single path for the saved objects on disk. If |
.plotInitialTime |
A numeric. If |
ggsaveArgs |
An optional list of arguments passed to |
usePlot |
Logical. If |
deviceArgs |
An optional list of arguments passed to one of |
... |
Anything needed by |
type
"screen"
– Will plot to the current device, normally a plot window
"object"
– Will save the plot object, e.g., ggplot
object
"raw"
– Will save the raw data prior to plotting, e.g.,
the data argument
"png"
– or any other type save-able with ggsave
Called for its side effect of plot creation.
In cases where files are saved, and where Plots
is used within a SpaDES module,
the file(s) that is/are saved will be appended to the outputs
slot of the
simList
of the module. This will, therefore, keep a record of figures saved
within the simList
This is still experimental and could change in the next release.
Plots
now has experimental support for "just a Plot
call", but with types
specified.
See examples.
The devices to save on disk will have some different behaviours to the screen representation,
since "wiping" an individual plot on a device doesn't exist for a file device.
This offers up to 4 different actions for a given plot:
To screen device
To disk as raw data (limited testing)
To disk as a saved plot object (limited testing)
To disk as a ‘.png’ or other image file, e.g., ‘.pdf’
To turn off plotting both to screen and disk, set both
.plotInititalTime = NA
and .plots = NA
or any other
value that will not trigger a TRUE with a grepl
with the types
argument (e.g., ""
will omit all saving).
# Note: if this is used inside a SpaDES module, do not define this # function inside another function. Put it outside in a normal # module script. Otherwise, it will cause a memory leak. if (requireNamespace("ggplot2")) { fn <- function(d) ggplot2::ggplot(d, ggplot2::aes(a)) + ggplot2::geom_histogram() sim <- simInit() sim$something <- data.frame(a = sample(1:10, replace = TRUE)) Plots(data = sim$something, fn = fn, types = c("png"), path = file.path("figures"), filename = tempfile(), .plotInitialTime = 1) # plot to active device and to png Plots( data = sim$something, fn = fn, types = c("png", "screen"), path = file.path("figures"), filename = tempfile(), .plotInitialTime = 1 ) # Can also be used like quickPlot::Plot, but with control over output type r <- terra::rast(terra::ext(0,10,0,10), vals = sample(1:3, size = 100, replace = TRUE)) Plots(r, types = c("screen", "png"), filename = tempfile(), deviceArgs = list(width = 700, height = 500), usePlot = TRUE) # with ggplotify, Plots can also be used to plot/save # non-ggplot objects: if (require("ggplotify")) { if (!require("lattice")) stop("please install lattice") p1 <- densityplot(~mpg|cyl, data=mtcars) Plots(data = p1, fn = as.ggplot, filename = tempfile(), ggsaveArgs = list(width = 5, height = 4, dpi = 300, bg = "white", units = "in"), types = c("screen", "png"), .plotInitialTime = 1) } } # end ggplot # end of dontrun
# Note: if this is used inside a SpaDES module, do not define this # function inside another function. Put it outside in a normal # module script. Otherwise, it will cause a memory leak. if (requireNamespace("ggplot2")) { fn <- function(d) ggplot2::ggplot(d, ggplot2::aes(a)) + ggplot2::geom_histogram() sim <- simInit() sim$something <- data.frame(a = sample(1:10, replace = TRUE)) Plots(data = sim$something, fn = fn, types = c("png"), path = file.path("figures"), filename = tempfile(), .plotInitialTime = 1) # plot to active device and to png Plots( data = sim$something, fn = fn, types = c("png", "screen"), path = file.path("figures"), filename = tempfile(), .plotInitialTime = 1 ) # Can also be used like quickPlot::Plot, but with control over output type r <- terra::rast(terra::ext(0,10,0,10), vals = sample(1:3, size = 100, replace = TRUE)) Plots(r, types = c("screen", "png"), filename = tempfile(), deviceArgs = list(width = 700, height = 500), usePlot = TRUE) # with ggplotify, Plots can also be used to plot/save # non-ggplot objects: if (require("ggplotify")) { if (!require("lattice")) stop("please install lattice") p1 <- densityplot(~mpg|cyl, data=mtcars) Plots(data = p1, fn = as.ggplot, filename = tempfile(), ggsaveArgs = list(width = 5, height = 4, dpi = 300, bg = "white", units = "in"), types = c("screen", "png"), .plotInitialTime = 1) } } # end ggplot # end of dontrun
Preset event priorities: 1 = first (highest); 5 = normal; 10 = last (lowest).
.first() .highest() .last() .lowest() .normal()
.first() .highest() .last() .lowest() .normal()
numeric of length 1.
Alex Chubaty
The progress bar can be set in two ways in SpaDES. First, by setting values
in the .progress
list element in the params list element passed to simInit()
.
Second, at the spades()
call itself, which can be simpler. See examples.
progressInterval(sim) ## S4 method for signature 'simList' progressInterval(sim) progressInterval(sim) <- value ## S4 replacement method for signature 'simList' progressInterval(sim) <- value progressType(sim) ## S4 method for signature 'simList' progressType(sim) progressType(sim) <- value ## S4 replacement method for signature 'simList' progressType(sim) <- value
progressInterval(sim) ## S4 method for signature 'simList' progressInterval(sim) progressInterval(sim) <- value ## S4 replacement method for signature 'simList' progressInterval(sim) <- value progressType(sim) ## S4 method for signature 'simList' progressType(sim) progressType(sim) <- value ## S4 replacement method for signature 'simList' progressType(sim) <- value
sim |
A |
value |
The parameter value to be set (in the corresponding |
Progress Bar:
Progress type can be one of "text"
, "graphical"
, or "shiny"
.
Progress interval can be a numeric.
These both can get set by passing a
.progress = list(type = "graphical", interval = 1)
into the simInit
call.
See examples.
for progressInterval
, a numeric corresponding to the progress update interval;
for progressInterval<-
, an updated simList
object.
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
times()
if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { opts <- options("spades.moduleCodeChecks" = FALSE) # not necessary for example mySim <- simInit( times = list(start=0.0, end=100.0), params = list(.globals = list(stackName = "landscape"), .progress = list(type = "text", interval = 10), checkpoint = list(interval = 10, file = "chkpnt.RData")), modules = list("randomLandscapes"), paths = list(modulePath = getSampleModules(tempdir())) ) # progress bar progressType(mySim) # "text" progressInterval(mySim) # 10 # parameters params(mySim) # returns all parameters in all modules # including .global, .progress, checkpoint globals(mySim) # returns only global parameters # checkpoint checkpointFile(mySim) # returns the name of the checkpoint file # In this example, "chkpnt.RData" checkpointInterval(mySim) # 10 options(opts) # reset }
if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { opts <- options("spades.moduleCodeChecks" = FALSE) # not necessary for example mySim <- simInit( times = list(start=0.0, end=100.0), params = list(.globals = list(stackName = "landscape"), .progress = list(type = "text", interval = 10), checkpoint = list(interval = 10, file = "chkpnt.RData")), modules = list("randomLandscapes"), paths = list(modulePath = getSampleModules(tempdir())) ) # progress bar progressType(mySim) # "text" progressInterval(mySim) # 10 # parameters params(mySim) # returns all parameters in all modules # including .global, .progress, checkpoint globals(mySim) # returns only global parameters # checkpoint checkpointFile(mySim) # returns the name of the checkpoint file # In this example, "chkpnt.RData" checkpointInterval(mySim) # 10 options(opts) # reset }
Raster*
objectThis wraps either raster::raster
, raster::stack
, raster::brick
, or terra::rast
,
allowing a single function to be used to create a new object of the same class as a template.
This works for all Raster*
and SpatRaster
class templates.
rasterCreate(x, ...) ## Default S3 method: rasterCreate(x, ...)
rasterCreate(x, ...) ## Default S3 method: rasterCreate(x, ...)
x |
An object, notably a |
... |
Passed to |
a new (empty) object of same class as the original.
rasterCreate(default)
: Simply passes through argument with no effect
Wrapper to the raster
function, that creates the raster object in
memory, even if it was read in from file. There is the default method which is
just a pass through, so this can be safely used on large complex objects,
recursively, e.g., a simList
.
rasterToMemory(x, ...) ## S4 method for signature 'list' rasterToMemory(x, ...) ## S4 method for signature 'character' rasterToMemory(x, ...) ## S4 method for signature 'ANY' rasterToMemory(x, ...) ## S4 method for signature 'simList' rasterToMemory(x, ...)
rasterToMemory(x, ...) ## S4 method for signature 'list' rasterToMemory(x, ...) ## S4 method for signature 'character' rasterToMemory(x, ...) ## S4 method for signature 'ANY' rasterToMemory(x, ...) ## S4 method for signature 'simList' rasterToMemory(x, ...)
x |
An object passed directly to the function raster (e.g., character string of a filename). |
... |
Additional arguments to |
A raster object whose values are stored in memory.
Eliot McIntire and Alex Chubaty
raster()
, terra::rast()
.
Defunct. Will be removed by mid-2023.
remoteFileSize(url)
remoteFileSize(url)
url |
The url of the remote file. |
A numeric indicating the size of the remote file in bytes.
Eliot McIntire and Alex Chubaty
This will attempt to restart the R session, reloading all packages, and
saving and reloading the simList
.
Currently, this is not intended for general use: it has many specialized
pieces for using inside a spades
call.
The main purpose for doing this is to clear memory leaks (possibly deep
in R https://github.com/r-lib/fastmap) that are not fully diagnosed.
This is still very experimental.
This should only be used if there are RAM limitations being hit with long running simulations.
It has been tested to work Linux within Rstudio and at a terminal R session.
The way to initiate restarting of R is simply setting the spades.restartRInterval
or
setting the equivalent parameter in the restartR
core module via:
simInit(..., params = list(.restartR = list(.restartRInterval = 1)), ...)
greater than 0, which is the default,
e.g., options("spades.restartRInterval" = 100)
.
This is only intended to restart a simulation in exactly the same place as it was
(i.e., cannot change machines), and because of the restart, the assignment of the spades
call will be either to sim
or the user must make such an assignment manually,
e.g., sim <- savedSimEnv()$.sim
, or perhaps, the safer sim <- Copy(savedSimEnv()$.sim)
.
This is stated in a message.
restartR( sim, reloadPkgs = TRUE, .First = NULL, .RDataFile = getOption("spades.restartR.RDataFilename"), restartDir = getOption("spades.restartR.restartDir", NULL) )
restartR( sim, reloadPkgs = TRUE, .First = NULL, .RDataFile = getOption("spades.restartR.RDataFilename"), restartDir = getOption("spades.restartR.restartDir", NULL) )
sim |
Required. A |
reloadPkgs |
Logical. If |
.First |
A function to save to ‘~/.qs’ which will
be loaded at restart from ‘~/.qs’ and run. Default is |
.RDataFile |
A filename for saving the |
restartDir |
A character string indicating root directory to
save |
The process responds to several options. Though under most cases,
the default behaviour should suffice. These are of 3 types: restartRInterval
the arguments to restartR
and the arguments to saveSimList
, these latter two
using a dot to separate the function name and its argument. The defaults for
two key options are: options("spades.restartR.restartDir" = NULL
, meaning
use file.path(restartDir, "restartR", paste0(sim$._startClockTime, "_", .rndString))
and options("spades.saveSimList.fileBackend" = 0)
, which means don't do anything
with raster-backed files.
See specific functions for defaults and argument meanings.
The only difference from the default function values is with saveSimList
argument
fileBackend = FALSE
during restartR
by default, because it is assumed that
the file backends will still be intact after a restart, so no need to move them all to memory.
invoked for side effect of restarting the R session
Because of the restarting, the object name of the original assignment of the
spades
call can not be preserved. The spades
call will be
assigned to sim
in the .GlobalEnv
.
Because this function is focused on restarting during a spades
call,
it will remove all objects in the .GlobalEnv
, emulating q("no")
.
If the user wants to keep those objects, then they should be saved to disk
immediately before the spades
call.
This can then be recovered immediately after the return from the spades
call.
To keep the saved simList
, use options("spades.restartR.clearFiles" = TRUE)
.
The default is to treat these files as temporary files and so will be removed.
This is very experimental and has not been thoroughly tested. Use with caution.
This function will re-parse a single module (currently) into the simList
where its source code should reside, and then optionally restart a simulation
that stopped on an error, presumably after the developer has modified the
source code of the module that caused the break.
This will restart the simulation at the next event in the event queue
(i.e., returned by events(sim)
). Because of this, this function will
not do anything if the event queue is empty.
restartSpades(sim = NULL, module = NULL, numEvents = Inf, restart = TRUE, ...)
restartSpades(sim = NULL, module = NULL, numEvents = Inf, restart = TRUE, ...)
sim |
A |
module |
A character string length one naming the module that caused the error and
whose source code was fixed. This module will be re-parsed and placed into the |
numEvents |
Numeric. Default is Inf (i.e., all available). In the |
restart |
Logical. If |
... |
Passed to |
This will only parse the source code from the named module. It will not affect any
objects that are in the mod
or sim
.
The random number seed will be reset to the state it was at the start of the earliest event recovered, thereby returning to the exact stochastic simulation trajectory.
A simList
as if spades
had been called on a simList
.
This will only work reliably
if the simList
was not modified yet during the event which caused the error.
The simList
will be in the state it was at the time of the error.
# options("spades.recoveryMode" = 1) # now the default s <- simInit() s <- spades(s) # if this is interrupted or fails # the following line will not work if the previous line didn't fail s <- restartSpades(s) # don't need to specify `sim` if previous line fails # will take from savedSimEnv()$.sim automatically
# options("spades.recoveryMode" = 1) # now the default s <- simInit() s <- spades(s) # if this is interrupted or fails # the following line will not work if the previous line didn't fail s <- restartSpades(s) # don't need to specify `sim` if previous line fails # will take from savedSimEnv()$.sim automatically
If the user sets options(reproducible.memoisePersist = TRUE)
,
the global environment will be used, otherwise, a package environment.
savedSimEnv(envir = .GlobalEnv)
savedSimEnv(envir = .GlobalEnv)
envir |
an environment to use to store the |
.saveObjects
in params
slot of simInit
In the simInit()
call, a parameter called .saveObjects
can be provided in
each module.
This must be a character string vector of all object names to save. These objects will
then be saved whenever a call to saveFiles
is made.
saveFiles(sim)
saveFiles(sim)
sim |
A |
The file names will be equal to the object name plus time(sim)
is
appended at the end.
The files are saved as .rds
files, meaning, only one object gets
saved per file.
For objects saved using this function, the module developer must create save
events that schedule a call to saveFiles
.
If this function is used outside of a module, it will save all files in the
outputs(sim)
that are scheduled to be saved at the current time in the simList.
There are several ways to save objects using SpaDES
.
(invisibly) the modified sim
object.
invoked for side effect of saving the simulation to file.
Using the outputs
slot in the simInit()
call.
See example in simInit()
.
This can be convenient because it gives overall control of many modules at a
time, and it gets automatically scheduled during the simInit()
call.
Using the saveFiles
function inside a module.
This must be accompanied by a .saveObjects
vector or list element in the
params
slot in the simList()
.
Usually a module developer will create this method for future users of their module.
A module developer can save any object at any time inside their module, using
standard R functions for saving R objects (e.g., save
or saveRDS
).
This is the least modular approach, as it will happen whether a module user
wants it or not.
It is not possible to schedule separate saving events for each object
that is listed in the .saveObjects
.
Eliot McIntire and Alex Chubaty
if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { ## This will save the "caribou" object at the save interval of 1 unit of time ## in the outputPath location outputPath <- file.path(tempdir(), "test_save") times <- list(start = 0, end = 1, "month") modules <- list("randomLandscapes", "caribouMovement") paths <- list( modulePath = getSampleModules(tempdir()), outputPath = outputPath ) opts <- options("spades.moduleCodeChecks" = FALSE, "spades.useRequire" = FALSE) # not necessary for example ## save multiple outputs parameters <- list( .globals = list(stackName = "landscape"), caribouMovement = list( .saveObjects = c("caribou", "habitatQuality"), .saveInitialTime = 1, .saveInterval = 1 ), randomLandscapes = list(.plots = NA, nx = 20, ny = 20)) mySim <- simInit(times = times, params = parameters, modules = modules, paths = paths) spades(mySim, .plotInitialTime = NA) # plotting not relevant for this example dir(outputPath) # remove the files file.remove(dir(outputPath, full.names = TRUE)) options(opts) # clean up }
if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { ## This will save the "caribou" object at the save interval of 1 unit of time ## in the outputPath location outputPath <- file.path(tempdir(), "test_save") times <- list(start = 0, end = 1, "month") modules <- list("randomLandscapes", "caribouMovement") paths <- list( modulePath = getSampleModules(tempdir()), outputPath = outputPath ) opts <- options("spades.moduleCodeChecks" = FALSE, "spades.useRequire" = FALSE) # not necessary for example ## save multiple outputs parameters <- list( .globals = list(stackName = "landscape"), caribouMovement = list( .saveObjects = c("caribou", "habitatQuality"), .saveInitialTime = 1, .saveInterval = 1 ), randomLandscapes = list(.plots = NA, nx = 20, ny = 20)) mySim <- simInit(times = times, params = parameters, modules = modules, paths = paths) spades(mySim, .plotInitialTime = NA) # plotting not relevant for this example dir(outputPath) # remove the files file.remove(dir(outputPath, full.names = TRUE)) options(opts) # clean up }
simList
object to diskSaving a simList
may not work using the standard approaches
(e.g., save
, saveRDS
, and qs::qsave
).
There are 2 primary reasons why this doesn't work as expected:
the activeBindings
that are in place within modules
(these allow the mod
and Par
to exist), and file-backed objects,
such as SpatRaster
and Raster*
.
Because of these, a user should use saveSimList
and loadSimList
.
These will save the object and recover the object using the filename
supplied,
if there are no file-backed objects.
If there are file-backed objects, then it will save an archive
(default is .tar.gz
using the archive
package for non-Windows and zip()
if using Windows, as there is currently an unidentified bug in archive*
on Windows).
The user does not need to specify the filename any differently,
as the code will search based on the filename without the file extension.
saveSimList( sim, filename, projectPath = getwd(), outputs = TRUE, inputs = TRUE, cache = FALSE, envir, ... )
saveSimList( sim, filename, projectPath = getwd(), outputs = TRUE, inputs = TRUE, cache = FALSE, envir, ... )
sim |
Either a |
filename |
Character string with the path for saving |
projectPath |
Should be the "top level" or project path for the |
outputs |
Logical. If |
inputs |
Logical. If |
cache |
Logical. Not yet implemented. If |
envir |
If |
... |
Additional arguments. See Details. |
There is a family of 2 functions that are mutually useful for saving and
loading simList
objects and their associated files (e.g., file-backed
Raster*
, inputs
, outputs
, cache
) saveSimList()
, loadSimList()
.
Additional arguments may be passed via ...
, including:
files
: logical indicating whether files should be included in the archive.
if FALSE
, will override cache
, inputs
, outputs
, setting them to FALSE
.
symlinks
: a named list of paths corresponding to symlinks, which will be used to substitute
normalized absolute paths of files.
Names should correspond to the names in paths()
;
values should be project-relative paths.
E.g., list(cachePath = "cache", inputPath = "inputs", outputPath = "outputs")
.
Invoked for side effects of saving both a .qs
(or .rds
) file,
and a compressed archive (one of .tar.gz
if using non-Windows OS or .zip
on Windows).
Adds a new event to the simulation's conditional event queue,
updating the simulation object by creating or appending to
sim$._conditionalEvents
.
This is very experimental. Use with caution.
scheduleConditionalEvent( sim, condition, moduleName, eventType, eventPriority = .normal(), minEventTime = start(sim), maxEventTime = end(sim) )
scheduleConditionalEvent( sim, condition, moduleName, eventType, eventPriority = .normal(), minEventTime = start(sim), maxEventTime = end(sim) )
sim |
A |
condition |
A string, call or expression that will be assessed for |
moduleName |
A character string specifying the module from which to
call the event. If missing, it will use
|
eventType |
A character string specifying the type of event from within the module. |
eventPriority |
A numeric specifying the priority of the event.
Lower number means higher priority. As a best practice, it is
recommended that decimal values are conceptual
grouped by their integer values (e.g., 4.0, 4.25, 4.5 are conceptually
similar).
See |
minEventTime |
A numeric specifying the time before which the event should not occur,
even if the condition is met. Defaults to |
maxEventTime |
A numeric specifying the time after which the event should not occur,
even if the condition is met. Defaults to |
This conditional event queue will be assessed at every single event in the normal event
queue. If there are no conditional events, then spades
will proceed as normal.
As conditional event conditions are found to be true, then it will trigger a call to
scheduleEvent(...)
with the current time passed to eventTime
and
it will remove the conditional event from the conditional queue.
If the user would like the triggered conditional event to occur as the very next event,
then a possible strategy would be to set eventPriority
of the conditional event
to very low or even negative to ensure it gets inserted at the top of the event queue.
Returns the modified simList
object, i.e., sim$._conditionalEvents
.
Eliot McIntire
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
scheduleEvent()
, conditionalEvents()
sim <- simInit(times = list(start = 0, end = 2)) condition <- "sim$age > 1" # provide as string condition <- quote(sim$age > 1) # provide as a call condition <- expression(sim$age > 1) # provide as an expression sim <- scheduleConditionalEvent(sim, condition, "firemodule", "burn") conditionalEvents(sim) sim <- spades(sim) # no changes to sim$age, i.e., it is absent events(sim) # nothing scheduled sim$age <- 2 # change the value sim <- spades(sim) # Run spades, the condition is now true, so event is # scheduled at current time events(sim) # now scheduled in the normal event queue
sim <- simInit(times = list(start = 0, end = 2)) condition <- "sim$age > 1" # provide as string condition <- quote(sim$age > 1) # provide as a call condition <- expression(sim$age > 1) # provide as an expression sim <- scheduleConditionalEvent(sim, condition, "firemodule", "burn") conditionalEvents(sim) sim <- spades(sim) # no changes to sim$age, i.e., it is absent events(sim) # nothing scheduled sim$age <- 2 # change the value sim <- spades(sim) # Run spades, the condition is now true, so event is # scheduled at current time events(sim) # now scheduled in the normal event queue
Adds a new event to the simulation's event queue, updating the simulation object.
scheduleEvent( sim, eventTime, moduleName, eventType, eventPriority = .pkgEnv$.normalVal, .skipChecks = FALSE )
scheduleEvent( sim, eventTime, moduleName, eventType, eventPriority = .pkgEnv$.normalVal, .skipChecks = FALSE )
sim |
A |
eventTime |
A numeric specifying the time of the next event. |
moduleName |
A character string specifying the module from which to
call the event. If missing, it will use
|
eventType |
A character string specifying the type of event from within the module. |
eventPriority |
A numeric specifying the priority of the event.
Lower number means higher priority. As a best practice, it is
recommended that decimal values are conceptual
grouped by their integer values (e.g., 4.0, 4.25, 4.5 are conceptually
similar).
See |
.skipChecks |
Logical. If |
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).
Returns the modified simList
object.
Alex Chubaty
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
priority()
, scheduleConditionalEvent()
sim <- simInit() sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn") # default priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .normal()) # default priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .normal()-1) # higher priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .normal()+1) # lower priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .highest()) # highest priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .lowest()) # lowest priority events(sim) # shows all scheduled events, with eventTime and priority
sim <- simInit() sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn") # default priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .normal()) # default priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .normal()-1) # higher priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .normal()+1) # lower priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .highest()) # highest priority sim <- scheduleEvent(sim, time(sim) + 1.0, "fireSpread", "burn", .lowest()) # lowest priority events(sim) # shows all scheduled events, with eventTime and priority
Show an Object
## S4 method for signature 'simList' show(object)
## S4 method for signature 'simList' show(object)
object |
|
Alex Chubaty
Assists with saving and retrieving simulations (e.g., with saveSimList
and loadSimList
).
simFile(name, path, time = NULL, ext = "rds")
simFile(name, path, time = NULL, ext = "rds")
name |
Object name (e.g., |
path |
Directory location in where the file will be located (e.g., an |
time |
Optional simulation time to use as filename suffix. Default |
ext |
The file extension to use (default |
character string giving a file path for a simulation file
Create a new simulation object, the sim
object (a simList
).
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 signature ## 'list,list,list,list,list,data.frame,data.frame,character' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature 'ANY,ANY,ANY,character,ANY,ANY,ANY,ANY' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature 'ANY,ANY,character,ANY,ANY,ANY,ANY,ANY' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature 'ANY,ANY,ANY,ANY,ANY,ANY,ANY,ANY' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) simInit2(l) simInitDefaults()
simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature ## 'list,list,list,list,list,data.frame,data.frame,character' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature 'ANY,ANY,ANY,character,ANY,ANY,ANY,ANY' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature 'ANY,ANY,character,ANY,ANY,ANY,ANY,ANY' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) ## S4 method for signature 'ANY,ANY,ANY,ANY,ANY,ANY,ANY,ANY' simInit( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan = NULL, ... ) simInit2(l) simInitDefaults()
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 ‘caribou.R’,
located at the specified |
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 character vector 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 |
... |
An alternative way to pass |
l |
A list of arguments to passed to |
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))
.
The params
list can contain a list (named .globals
) of named objects
e.g., .globals = list(climateURL = "https:\\something.com")
entry. Any and every
module that has a parameter with that name (in this case climateURL
) will be
overridden with this value as passed.
params
can be used to set the seed for a specific event in a module. This
is done using the normal params
argument, specifying .seed
as a list
where the elements are a numeric for the seed and the name is the event. Since
parameters must be specific to a module, this creates a module and event specific
seed e.g., params = list(moduleName = list(.seed = list(init = 123)))
will
set the init
event of module named moduleName
to 123. The RN stream
will be reset to its state prior to the set.seed
call after the event.
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.inputPath")
;
modulePath
: getOption("spades.modulePath")
;
outputPath
: getOption("spades.outputPath")
.
A simList
simulation object, pre-initialized from values
specified in the arguments supplied.
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.
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.
Alex Chubaty and Eliot McIntire
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
spades()
, defineModule()
to get help on metadata elements,
times()
, params()
, objs()
, paths()
,
modules()
, inputs()
, outputs()
# Tests take several seconds if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { 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 = 2.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), paths = list(modulePath = getSampleModules(tempdir())) ) 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 = getSampleModules(tempdir())) ) outSim <- spades(mySim) # A little more complicated with inputs and outputs 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 = getSampleModules(tempdir()), outputPath = tempdir()), inputs = data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "rast", package = "terra", 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(start = 0.0, end = 2.0, timeunit = "year"), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned"), randomLandscapes = list(nx = 10, ny = 10) ), paths = list( modulePath = getSampleModules(tempdir()), outputPath = tempdir() ) ) # add by accessor is equivalent inputs(mySim2) <- data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "rast", package = "terra", 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 = getSampleModules(tempdir()), outputPath = tempdir()), inputs = data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "rast", package = "terra", 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 options(opts) }
# Tests take several seconds if (requireNamespace("SpaDES.tools", quietly = TRUE) && requireNamespace("NLMR", quietly = TRUE)) { 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 = 2.0, timeunit = "year"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned") ), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), paths = list(modulePath = getSampleModules(tempdir())) ) 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 = getSampleModules(tempdir())) ) outSim <- spades(mySim) # A little more complicated with inputs and outputs 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 = getSampleModules(tempdir()), outputPath = tempdir()), inputs = data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "rast", package = "terra", 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(start = 0.0, end = 2.0, timeunit = "year"), modules = list("randomLandscapes", "fireSpread", "caribouMovement"), params = list( .globals = list(stackName = "landscape", burnStats = "nPixelsBurned"), randomLandscapes = list(nx = 10, ny = 10) ), paths = list( modulePath = getSampleModules(tempdir()), outputPath = tempdir() ) ) # add by accessor is equivalent inputs(mySim2) <- data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "rast", package = "terra", 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 = getSampleModules(tempdir()), outputPath = tempdir()), inputs = data.frame( files = dir(file.path(mapPath), full.names = TRUE, pattern = "tif")[1:2], functions = "rast", package = "terra", 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 options(opts) }
simInitAndSpades2
is a convenience wrapper for do.call(simInitAndSpades, listOfArgs)
,
i.e., a user can pass a list of all the arguments.These functions are convenience wrappers that may allow for more efficient caching.
Passes all arguments to simInit()
, then passes the created simList
to spades()
.
simInitAndSpades2(l) simInitAndSpades( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan, debug, progress, cache, .plots, .plotInitialTime, .saveInitialTime, events, ... )
simInitAndSpades2(l) simInitAndSpades( times, params, modules, objects, paths, inputs, outputs, loadOrder, notOlderThan, debug, progress, cache, .plots, .plotInitialTime, .saveInitialTime, events, ... )
l |
A list of arguments to passed to |
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 ‘caribou.R’,
located at the specified |
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 character vector 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 |
debug |
Optional tools for invoking debugging. Supplying a |
progress |
Logical ( |
cache |
Logical. If |
.plots |
Character. Sets the parameter of this name in all modules.
See |
.plotInitialTime |
Numeric. Temporarily override the |
.saveInitialTime |
Numeric. Temporarily override the |
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 |
... |
Arguments passed to |
Same as spades()
(a simList
) or
simList
classContains the minimum components of a SpaDES
simulation.
Various slot accessor methods (i.e., get and set functions) are provided
(see 'Accessor Methods' below).
Based on code from chapter 7.8.3 of Matloff (2011): "Discrete event simulation".
Here, we implement a discrete event simulation in a more modular fashion so
it's easier to add simulation components (i.e., "simulation modules").
We use S4 classes and methods, and use data.table()
instead of
data.frame()
to implement the event queue (because it is much
more efficient).
modules
List of character names specifying which modules to load.
params
Named list of potentially other lists specifying simulation parameters.
events
The list of scheduled events (i.e., event queue), which can
be converted to a sorted data.table
with events(sim)
.
See 'Event Lists' for more information.
current
The current event, as a data.table
.
See 'Event Lists' for more information..
completed
An environment consisting of completed events, with
each object named a character representation of the order
of events. This was converted from a previous version which
was a list. This was changed because the list became
slow as number of events increased.
See 'Event Lists' for more information. It is kept
as an environment of individual events for speed. The completed
method converts it to a sorted data.table
.
depends
A .simDeps
list of .moduleDeps()
objects
containing module object dependency information.
simtimes
List of numerical values describing the simulation start and end times; as well as the current simulation time.
inputs
a data.frame
or data.table
of files and
metadata
outputs
a data.frame
or data.table
of files and
metadata
paths
Named list of paths. See ?.paths
. Partial matching is performed.
.xData
Environment referencing the objects used in the simulation.
Several "shortcuts" to accessing objects referenced by this
environment are provided, and can be used on the
simList
object directly instead of specifying the
.xData
slot: $
, [[
, ls
,
ls.str
, objs
. See examples.
.envir
Deprecated. Please do not use any more.
Several slot (and sub-slot) accessor methods are provided for use, and categorized into separate help pages:
simList-accessors-envir() |
Simulation environment. |
simList-accessors-events() |
Scheduled and completed events. |
simList-accessors-inout() |
Passing data in to / out of simulations. |
simList-accessors-modules() |
Modules loaded and used; module dependencies. |
simList-accessors-objects() |
Accessing objects used in the simulation. |
simList-accessors-params() |
Global and module-specific parameters. |
simList-accessors-paths() |
File paths for modules, inputs, and outputs. |
simList-accessors-times() |
Simulation times. |
The main event list is a sorted data.table
(keyed) on eventTime
, and eventPriority.
The completed event list is an ordered list in the exact order that the events were executed.
Each event is represented by a data.table()
row consisting of:
eventTime |
The time the event is to occur. |
moduleName |
The module from which the event is taken. |
eventType |
A character string for the programmer-defined event type. |
eventPriority |
The priority given to the event. |
The simList
class extends the environment
, by adding
several slots that provide information about the metadata for a discrete
event simulation. The environment slot, if accessed directly is .xData
and this is where input and output objects from modules are placed.
The simList_()
class is similar, but it extends the list
class. All other slots are the same.
Thus, simList
is identical to simList_
, except that the former
uses an environment for objects and the latter uses a list.
The class simList_
is only used internally when saving/loading, because
saving/loading a list behaves more reliably than saving/loading an environment.
Alex Chubaty and Eliot McIntire
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
spades2
is a convenience wrapper for do.call(spades, listOfArgs)
,
i.e., a user can pass a list of all the arguments.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).
spades2(l) 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), ... )
spades2(l) 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), ... )
l |
A list of arguments to passed to |
sim |
A |
debug |
Optional tools for invoking debugging. Supplying a |
progress |
Logical ( |
cache |
Logical. If |
.plotInitialTime |
Numeric. Temporarily override the |
.saveInitialTime |
Numeric. Temporarily override the |
notOlderThan |
Date or time. Passed to |
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 |
.plots |
Character. Sets the parameter of this name in all modules.
See |
... |
Any. Can be used to make a unique cache identity, such as "replicate = 1".
This will be included in the |
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.
Invisibly returns the modified simList
object.
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.
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.
Alex Chubaty and Eliot McIntire
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
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()
.
vignettes
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)) 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) options(opts) # reset options }
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)) 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) options(opts) # reset options }
These S4 classes are defined within SpaDES
. "dot" classes are not exported and
are therefore intended for internal use only.
simList() |
The simList class |
.moduleDeps() |
Descriptor object for specifying SpaDES module dependencies |
.simDeps() |
Defines all simulation dependencies for all modules within a SpaDES simulation |
--------------------------- | ------------------------------------------------------------------------------------------ |
Eliot McIntire and Alex Chubaty
SpaDES.core
optionsThese provide top-level, powerful settings for a comprehensive SpaDES workflow.
To see defaults, run spadesOptions()
.
See Details below.
spadesOptions()
spadesOptions()
Below are options that can be set with options("spades.xxx" = newValue)
,
where xxx
is one of the values below, and newValue
is a new value to
give the option. Sometimes these options can be placed in the user's .Rprofile
file so they persist between sessions.
The following options are likely of interest to most users
OPTION | DEFAULT VALUE | DESCRIPTION |
spades.allowInitDuringSimInit |
FALSE
|
New feature as of SpaDES.core > 1.1.1.9001 ; If set to TRUE ,
simInit will evaluate the dependencies in the metadata objects and determine whether
there are modules whose init events can be run safely prior to
the .inputObjects of other modules, i.e., if a module's expectsInput
is not being supplied by any other module's createsOutput . |
spades.browserOnError |
FALSE |
If TRUE , the default, then any
error rerun the same event with debugonce called on it to allow editing
to be done. When that browser is continued (e.g., with 'c'), then it will save it
re-parse it into the simList and rerun the edited version.
This may allow a spades() call to be recovered on error,
though in many cases that may not be the correct behaviour.
For example, if the simList gets updated inside that event in an iterative
manner, then each run through the event will cause that iteration to occur.
When this option is TRUE , then the event will be run at least 3 times: the
first time makes the error, the second time has debugonce and the third time
is after the error is addressed. TRUE is likely somewhat slower. |
reproducible.cachePath |
getOption('reproducible.cachePath')
|
The default local directory in which to cache simulation outputs.
Default is a temporary directory (typically /tmp/RtmpXXX/SpaDES/cache ). |
spades.debug |
TRUE
|
The default debugging value debug argument in spades() |
spades.dotInputObjects |
TRUE
|
This is used in simInit ; if set to TRUE then the .inputObjects
function will be run; if FALSE , then it will be skipped. |
spades.DTthreads |
1L
|
The default number of data.table threads to use.
See also ?data.table::setDTthreads . |
spades.futureEvents |
FALSE
|
If set to TRUE , the event simulator will attempt to spawn events
whose outputs are not needed (by other events in the simList ) into a future.
In some cases, this will speed up simulations, by running some events in parallel.
Still VERY experimental. Use cautiously. |
spades.logPath
|
Defaults to a subdirectory (logs/ ) of the simulation output directory.
|
The default local directory in which to look for simulation inputs. |
spades.inputPath
|
Default is a temporary directory (typically /tmp/RtmpXXX/SpaDES/inputs )
|
The default local directory in which to look for simulation inputs. |
spades.loadReqdPkgs
|
Default is TRUE meaning that any reqdPkgs will be loaded via Require
or require . If FALSE , no package loading will occur. This will mean that
modules must prefix every function call from a package with that package name
with double colon (::). |
|
spades.lowMemory |
FALSE
|
If true, some functions will use more memory efficient (but slower) algorithms. |
spades.memoryUseInterval |
FALSE
|
A numeric in seconds indicating how often sample the memory use. This will
be run in a separate "future" process so it can monitor the main process.
To access the resulting memory use table, use memoryUse(sim) after the simulation
has terminated. |
spades.messagingNumCharsModule |
21
|
The number of characters to use for the messaging preamble on each line of the messaging during spades calls. |
spades.moduleCodeChecks
|
list(suppressParamUnused = FALSE, suppressUndefined = TRUE, suppressPartialMatchArgs = FALSE, suppressNoLocalFun = TRUE, skipWith = TRUE)
|
Should the various code checks be run
during simInit . These are passed to codetools::checkUsage() .
Default is given by the function, plus these: |
spades.moduleDocument |
TRUE
|
When a module is an R package e.g., via convertToPackage ,
it will, by default, rebuild documentation and reparse during simInit .
Since rebuilding documentation (from the roxygen2 tags) can be time consuming,
a user may wish to prevent this from happening each simInit call. If so,
set this option to FALSE |
spades.modulePath |
file.path(tempdir(), "SpaDES", "modules") )
|
The default local directory where modules and data will be downloaded and stored. Default is a temporary directory |
spades.moduleRepo |
"PredictiveEcology/SpaDES-modules"
|
The default GitHub repository to use when
downloading modules via downloadModule |
spades.nCompleted |
1000L |
The maximum number of completed events to
retain in the completed event queue. |
spades.outputPath
|
file.path(tempdir(), "SpaDES", "outputs")
|
The default local directory in which to save simulation outputs. |
spades.plots
|
The value of this will passed to .plots within every module; it will thus
override all module parameter values for .plots . This can, e.g., be used
to turn off all plotting.
|
The default is NULL, meaning accept the module-level parameter |
spades.recoveryMode |
1L |
If this is a numeric greater than 0 or TRUE, then the
discrete event simulator will take a snapshot of the objects in the simList
that might change (based on metadata outputObjects for that module), prior to
initiating every event. This will allow the
user to be able to recover in case of an error or manual interruption (e.g., Esc ).
If this is numeric, a copy of that number of "most
recent events" will be maintained so that the user can recover and restart
more than one event in the past, i.e., redo some of the "completed" events.
Default is TRUE , i.e., it will keep the state of the simList
at the start of the current event. This can be recovered with restartSpades
and the differences can be seen in a hidden object in the stashed simList .
There is a message which describes how to find that. |
spades.saveFileExtensions |
NULL |
a data.frame with 3 columns, exts , fun , and package indicating which
file extension, and which function from which package will be used when
using the outputs mechanism for saving files during a spades call. e.g.,
options(spades.saveFileExtensions = data.frame(exts = "shp", fun = "st_write", package = "sf") .
Then specify e.g.,
simInit(outputs = data.frame(objectName = "caribou", fun = "st_write", package = "sf"))
|
spades.scratchPath |
file.path(tempdir(), "SpaDES", "scratch") )
|
The default local directory where transient files from modules and data will written.
This includes temporary raster and terra files, as well as SpaDES recovery mode files.
Default is a temporary directory. |
spades.sessionInfo |
TRUE )
|
Assigns the utils::sessionInfo() to the simList during simInit with
the name sim$._sessionInfo . This takes about 75 milliseconds, which may be
undesirable for some situations where speed is critical. If FALSE , then
this is not assigned to the simList . |
spades.switchPkgNamespaces |
FALSE to keep computational
overhead down. |
Should the search path be modified
to ensure a module's required packages are listed first?
If TRUE , there should be no name conflicts among package objects,
but it is much slower, especially if the events are themselves fast. |
spades.testMemoryLeaks |
TRUE .
|
There is a very easy way to create a memory leak with R and SpaDES,
by adding formulas or functions to sim$ when the enclosing environment
of the formula or function contained a large object, most relevant here is
the sim object. SpaDES.core now tests for likely culprits for this
and suggests alternatives with a warning |
spades.tolerance |
.Machine$double.eps^0.5 .
|
The default tolerance value used for floating point number comparisons. |
spades.useragent |
"https://github.com/PredictiveEcology/SpaDES" .
|
: The default user agent to use for downloading modules from GitHub. |
spades.useRequire |
!tolower(Sys.getenv("SPADES_USE_REQUIRE")) %in% "false"
|
: The default for that environment variable is unset, so this returns
TRUE . If this is TRUE , then during the simInit call, when packages are
identified as being required, these will be installed if missing, only if
spades.useRequire option is TRUE , otherwise, simInit will fail because
packages are not available. |
named list of the default package options.
When loading objects into a simList
, especially during the
simInit
call, and inside the .inputObjects
functions of modules,
it is often useful to know if an object in question will or has been
by the user via the inputs
or objects
arguments, or by another
module's .inputObjects
while preparing its expected inputs (via
expectsInputs
in metadata), or if it will be supplied by another
module during its "init"
event. In all these cases, it may not
be necessary for a given module to load any default value for its expectsInputs
.
This function can be used as a check to determine whether the module needs
to proceed in getting and assigning its default value.
suppliedElsewhere( object, sim, where = c("sim", "user", "initEvent"), returnWhere = FALSE )
suppliedElsewhere( object, sim, where = c("sim", "user", "initEvent"), returnWhere = FALSE )
object |
Character vector |
sim |
A |
where |
Character vector with one to three of |
returnWhere |
Logical, default |
where
indicates which of three places to search, either "sim"
i.e.,
the simList
, which would be equivalent to is.null(sim\$objName)
, or
"user"
which would be supplied by the user in the simInit
function
call via outputs
or inputs
(equivalent to
(!('defaultColor' \%in\% sim$.userSuppliedObjNames))
),
or "initEvent"
, which would test whether a module that gets loaded before
the present one will create it as part of its outputs (i.e., as indicated by
createsOutputs
in that module's metadata). There is a caveat to this test,
however; if that other event also has the object as an expectsInput
, then
it would fail this test, as it also needs it as an input.
This final one ("initEvent"
) does not explicitly test that the object will be created
in the "init" event, only that it is in the outputs of that module, and that it is a module
that is loaded prior to this one.
logical
mySim <- simInit() suppliedElsewhere("test", mySim) # FALSE # supplied in the simList mySim$test <- 1 suppliedElsewhere("test", mySim) # TRUE test <- 1 # supplied from user at simInit time -- note, this object would eventually get into the simList # but the user supplied values come *after* the module's .inputObjects, so # a basic is.null(sim$test) would return TRUE even though the user supplied test mySim <- simInit(objects = list("test" = test)) suppliedElsewhere("test", mySim) # TRUE # Example with prepInputs # Put chunks like this in your .inputObjects if (!suppliedElsewhere("test", mySim)) sim$test <- Cache(prepInputs, "raster.tif", "downloadedArchive.zip", destinationPath = dataPath(sim), studyArea = sim$studyArea, rasterToMatch = sim$otherRasterTemplate, overwrite = TRUE)
mySim <- simInit() suppliedElsewhere("test", mySim) # FALSE # supplied in the simList mySim$test <- 1 suppliedElsewhere("test", mySim) # TRUE test <- 1 # supplied from user at simInit time -- note, this object would eventually get into the simList # but the user supplied values come *after* the module's .inputObjects, so # a basic is.null(sim$test) would return TRUE even though the user supplied test mySim <- simInit(objects = list("test" = test)) suppliedElsewhere("test", mySim) # TRUE # Example with prepInputs # Put chunks like this in your .inputObjects if (!suppliedElsewhere("test", mySim)) sim$test <- Cache(prepInputs, "raster.tif", "downloadedArchive.zip", destinationPath = dataPath(sim), studyArea = sim$studyArea, rasterToMatch = sim$otherRasterTemplate, overwrite = TRUE)
SpaDES
Functions for the simtimes
slot of a simList
object
and its elements. To maintain modularity, the behaviour of these functions depends
on where they are used. In other words, different modules can have their own
timeunit. SpaDES
converts these to seconds when running a simulation, but
shows the user time in the units of the model as shown with timeunit(sim)
times(x, ...) ## S4 method for signature 'simList' times(x) times(x) <- value ## S4 replacement method for signature 'simList' times(x) <- value ## S3 method for class 'simList' time(x, unit, ...) time(x) <- value ## S4 replacement method for signature 'simList' time(x) <- value end(x, ...) ## S3 method for class 'simList' end(x, unit, ...) end(x) <- value ## S4 replacement method for signature 'simList' end(x) <- value start(x, ...) ## S3 method for class 'simList' start(x, unit = NULL, ...) start(x) <- value ## S4 replacement method for signature 'simList' start(x) <- value timeunit(x) ## S4 method for signature 'simList' timeunit(x) timeunit(x) <- value ## S4 replacement method for signature 'simList' timeunit(x) <- value timeunits(x) ## S4 method for signature 'simList' timeunits(x) elapsedTime(x, ...) ## S3 method for class 'simList' elapsedTime(x, byEvent = TRUE, units = "auto", ...)
times(x, ...) ## S4 method for signature 'simList' times(x) times(x) <- value ## S4 replacement method for signature 'simList' times(x) <- value ## S3 method for class 'simList' time(x, unit, ...) time(x) <- value ## S4 replacement method for signature 'simList' time(x) <- value end(x, ...) ## S3 method for class 'simList' end(x, unit, ...) end(x) <- value ## S4 replacement method for signature 'simList' end(x) <- value start(x, ...) ## S3 method for class 'simList' start(x, unit = NULL, ...) start(x) <- value ## S4 replacement method for signature 'simList' start(x) <- value timeunit(x) ## S4 method for signature 'simList' timeunit(x) timeunit(x) <- value ## S4 replacement method for signature 'simList' timeunit(x) <- value timeunits(x) ## S4 method for signature 'simList' timeunits(x) elapsedTime(x, ...) ## S3 method for class 'simList' elapsedTime(x, byEvent = TRUE, units = "auto", ...)
x |
A |
... |
Additional parameters. |
value |
A time, given as a numeric, optionally with a unit attribute, but this will be deduced from the model time units or module time units (if used within a module). |
unit |
Character. One of the time units used in |
byEvent |
Logical. If |
units |
character string. Units in which the results are desired. Can be abbreviated. |
timeunit
will extract the current units of the time used in a
simulation (i.e., within a spades
call).
If it is set within a simInit
, e.g.,
times=list(start=0, end=52, timeunit = "week")
, it will set the
units for that simulation.
By default, a simInit
call will use the smallest unit contained within
the metadata for the modules being used. If there are parent modules, then the
parent module timeunit will be used even if one of its children is a smaller timeunit.
If all modules, including parents, are set to NA
, timeunit
defaults to seconds.
If parents are set to NA
, then the set of modules defined by that parent module
will be given the smallest units of the children.
Currently, available units are "second", "hours", day", "week", "month", and "year" can be used in the metadata of a module.
The user can also define a new unit. The unit name can be anything, but the
function definition must be of the form dunitName
, e.g., dyear
or dfortnight
.
The unit name is the part without the d
and the function name definition
includes the d
. This new function, e.g.,
dfortnight <- function(x) lubridate::duration(dday(14))
can be placed anywhere in the search path or in a module.
timeunits
will extract the current units of the time of all
modules used in a simulation.
This is different from timeunit
because it is not necessarily
associated with a spades
call.
In many cases, the "simpler" use of each of these functions may be slower
computationally. For instance, it is much faster to use time(sim, "year")
than time(sim)
. So as a module developer, it is advantageous to
write out the longer one, minimizing the looking up that R must do.
Returns or sets the value of the slot from the simList
object.
These have default behaviour that is based on the calling frame timeunit. When used inside a module, then the time is in the units of the module. If used in an interactive mode, then the time will be in the units of the simulation.
Additional methods are provided to access the current, start, and end times of the simulation:
time |
Current simulation time. |
start |
Simulation start time. |
end |
Simulation end time. |
timeunit |
Simulation timeunit. |
timeunits |
Module timeunits. |
times |
List of all simulation times (current, start, end, timeunit). |
Alex Chubaty and Eliot McIntire
SpaDES.core-package, specifically the section 1.2.5 on Simulation times;
elapsedTime()
,
Other functions to access elements of a 'simList' object:
.addDepends()
,
checkpointFile()
,
envir()
,
events()
,
globals()
,
inputs()
,
modules()
,
objs()
,
packages()
,
params()
,
paths()
,
progressInterval()
# Elapsed Time s1 <- simInit() s2 <- spades(s1) elapsedTime(s2) elapsedTime(s2, units = "mins")
# Elapsed Time s1 <- simInit() s2 <- spades(s1) elapsedTime(s2) elapsedTime(s2, units = "mins")
Defunct. Use utils::modifyList()
(which can not handle NULL) or
Require::modifyList2()
for case with >2 lists and can handle NULL lists.
updateList(x, y)
updateList(x, y)
x , y
|
a named list |
A named list, with elements sorted by name.
The values of matching elements in list y
replace the values in list x
.
Alex Chubaty
See corresponding vignette for more information.
use_gha(name, path)
use_gha(name, path)
name |
module name |
path |
module path |
Invoked for its side effect of creating new GitHub Actions workflow files.
Useful for debugging.
writeEventInfo(sim, file = "events.txt", append = FALSE)
writeEventInfo(sim, file = "events.txt", append = FALSE)
sim |
A |
file |
Character specifying the file name (default ‘"events.txt"’). |
append |
Logical indicating whether to append to the file (default |
Nothing returned. Invoked for its side effect of writing to file.
Alex Chubaty
Useful for debugging and ensuring reproducibility.
writeRNGInfo(file = "seed.txt", append = FALSE)
writeRNGInfo(file = "seed.txt", append = FALSE)
file |
Character specifying the filename (default |
append |
Logical indicating whether to append to the file (default |
Nothing returned. Invoked for its side effect of writing to file.
Alex Chubaty
The most common use of this would be from a "modules" directory, rather than inside a given module.
zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,character,character' zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,missing,character' zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,missing,missing' zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,character,missing' zipModule(name, path, version, data = FALSE, ...)
zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,character,character' zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,missing,character' zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,missing,missing' zipModule(name, path, version, data = FALSE, ...) ## S4 method for signature 'character,character,missing' zipModule(name, path, version, data = FALSE, ...)
name |
Character string giving the module name. |
path |
A file path to a directory containing the module subdirectory. |
version |
The module version. |
data |
Logical. If |
... |
Additional arguments to |
NULL (invisibly). Invoked for its side effect of zipping module files.
Eliot McIntire and Alex Chubaty
simList
and various fileszipSimList
will save the simList
and file-backed Raster*
objects, plus,
optionally, files identified in outputs(sim)
and inputs(sim)
.
This uses Copy
under the hood, to not affect the original simList
.
These functions have been moved to other packages.
zipSimList(sim, zipfile, ..., outputs = TRUE, inputs = TRUE, cache = FALSE) experiment(...) experiment2(...) POM(...) simInitAndExperiment(...) loadPackages(...)
zipSimList(sim, zipfile, ..., outputs = TRUE, inputs = TRUE, cache = FALSE) experiment(...) experiment2(...) POM(...) simInitAndExperiment(...) loadPackages(...)
sim |
Either a |
zipfile |
A character string indicating the filename for the zip file. Passed to |
... |
Unused. |
outputs |
Logical. If |
inputs |
Logical. If |
cache |
Logical. Not yet implemented. If |