7  The simList - What is it?

Author

Eliot McIntire

Published

June 20, 2024

See Barebones R script for the code shown in this chapter

In R, there is a default environment, called the .GlobalEnv. When you start typing in R and you create an object, it is “put” in the .GlobalEnv

Code
# this is in the .GlobalEnv
a <- 1
environment()  ## the current environment is .GlobalEnv
globalenv()  ## the same

ls(envir = environment())

The .GlobalEnv is convenient to begin in R, but it quickly becomes limiting. We need more places to put objects, and we need a way to be more in control of the things that we want to keep, share, modify etc. In SpaDES, this place is called the simList. It is a rich data object that acts like a list or an environment, i.e., we can put objects into it and use them later.

Code
Require::Require(c("reproducible", "SpaDES.core  (>= 2.1.5)"),
                 repos = c("https://predictiveecology.r-universe.dev", getOption("repos")))

sim <- simInit()
sim$a <- 1
sim$b <- sim$a + 2
sim$b
SpaDES.core::envir(sim)
simList is an environment

The name simList has the word “list” in it, but it is actually an environment. The “sim” part of the name is historically inherited from “simulation” modelling, although you may want to do nothing of the sort with your SpaDES modules.

Code
sim <- simInit()
is(sim, "environment")
# [1] TRUE

Accessing objects in the simList can be done with $ or [["object_name"]] and objects are manipulated as they would normally – e.g. if DF is a data.frame one would use sim$DF[1, 3] to extract the value on the first row and third column.

There is no limit to the number of objects you can add to a simList – the limit is, of course, your machine’s RAM.

7.1 Where does simList come from?

There is only one way in SpaDES.core to create a simList:

7.2 How can we specify a simList?

A simList object is simply a structured data type containing various elements.

The main components of a simList are:

  1. A list of modules used;

  2. The event queue;

  3. A description of the data (object) dependencies.

We can examine the simList object structure in the usual R fashion by printing (showing) it, or by using str():

Code
emptySim <- SpaDES.core::simInit()
emptySim  # same as show(emptySim)
str(emptySim)

simLists are S4 objects, so we can use getSlots() and slotNames() to examine the object.

See also ?'simList-class'

7.3 Accessing the parts of a simList

The simList can be imagined as a file cabinet where all the simulation details and objects (i.e. the parameters, inputs and outputs declared by each module) are stored neatly and in an easily accessible way.

7.3.1 Initialize/create and inspect an empty simList object

Code
emptySim <- simInit()
  1. What are the names of each of the slots in the simList?

  2. What do each of these slots contain?

    Hint: see ?'simList-class'

Code
str(emptySim)
slotNames(emptySim)
getSlots('simList')
?`simList-class`

7.3.1.1 simList accessor functions

simList accessor functions are used to determine the following:

  1. the modules included in the simulation and their package dependencies;

  2. the global parameter values used;

  3. the module-specific parameter values used;

  4. the simulation start, end and current times;

  5. the time units used by the modules in the simulation;

  6. the scheduled and completed event queues;

  7. the objects (functions, data, etc.) used in the simulation;

  8. the file paths used for simulation inputs and outputs.

We will try this with the simple linear module first, for which we’ve already defined default values for the input object x (see Chapter 5).

Code
# Get the sample modules that come with SpaDES.core

modulePath <- getSampleModules(tempdir())
# options(spades.loadReqdPkgs = FALSE) # we don't need to check for packages in this example
modulePath <- "~/SpaDES_book/NewModuleIntro/NewModule"
mySim <- simInit(params = list("My_linear_model" = list(length = 20)),
                 modules = "My_linear_model",
                 paths = list(modulePath = modulePath))
events(mySim)

# b is in the .xData slot
mySim$x
mySim@.xData$x

# all functions below come from SpaDES.core::
# list modules used in the simulation
modules(mySim)

# list module dependencies and packages used
depends(mySim)
packages(mySim)

# list global and module-specific param values
params(mySim)
P(mySim)       # bonus: how do params() and P() differ?

# list start and end times
times(mySim)
start(mySim)
end(mySim)
## and the 'current' time
time(mySim)

# get the simulation and module timeunits
timeunit(mySim)
timeunits(mySim)

# get the scheduled and completed event queues
events(mySim)
completed(mySim)

# list the objects (functions, data, etc.) stored in the simList
objects(mySim)

# list the file paths used in the simulation
paths(mySim)
inputPath(mySim)
outputPath(mySim)

Now run the simulation

Code
mySimOut <- reproducible::Copy(mySim) # make a deep copy of the simList
mySimOut <- spades(mySimOut)
simNew <- sim doesn’t copy

If you don’t know what an environment is in R, it is OK. The most important feature of an environment is that it employs pass-by-reference, which means it is not copied when it is “assigned” somewhere. This makes SpaDES fast enough to use for huge workflows.

Code
sim <- simInit()
sim$a <- 1
simNew <- sim
simNew$a <- 2

# what value will this have?
sim$a

7.3.2 Compare the simList before and after spades()

Code
times(mySim)
times(mySimOut)

objects(mySim)
objects(mySimOut)

7.4 Try on your own

  • Repeat the above with more complex modules. Use the accessor functions to look at what inside the simList and try passing different parameter values or inputs.

    Code
    modulePath <- getSampleModules(tempdir())
    # options(spades.loadReqdPkgs = FALSE) # we don't need to check for packages in this example
    mySim <- simInit(modules = dir(modulePath[1:3]),
    paths = list(modulePath = modulePath),
    objects = list(b = 1))
    simOut <- spades(mySim)

7.5 See also

Environments - Advanced R

?'simList-class'

?SpaDES.core::envir

?SpaDES.core::simInit

?SpaDES.core::spades

7.6 Barebones R script

Code
# this is in the .GlobalEnv
a <- 1
environment()  ## the current environment is .GlobalEnv
globalenv()  ## the same

ls(envir = environment())

Require::Require(c("reproducible", "SpaDES.core  (>= 2.1.5)"),
                 repos = c("https://predictiveecology.r-universe.dev", getOption("repos")))

sim <- simInit()
sim$a <- 1
sim$b <- sim$a + 2
sim$b
SpaDES.core::envir(sim)

sim <- simInit()
is(sim, "environment")
# [1] TRUE

emptySim <- SpaDES.core::simInit()
emptySim  # same as show(emptySim)
str(emptySim)





emptySim <- simInit()

str(emptySim)
slotNames(emptySim)
getSlots('simList')
?`simList-class`

# Get the sample modules that come with SpaDES.core

modulePath <- getSampleModules(tempdir())
# options(spades.loadReqdPkgs = FALSE) # we don't need to check for packages in this example
modulePath <- "~/SpaDES_book/NewModuleIntro/NewModule"
mySim <- simInit(params = list("My_linear_model" = list(length = 20)),
                 modules = "My_linear_model",
                 paths = list(modulePath = modulePath))
events(mySim)

# b is in the .xData slot
mySim$x
mySim@.xData$x

# all functions below come from SpaDES.core::
# list modules used in the simulation
modules(mySim)

# list module dependencies and packages used
depends(mySim)
packages(mySim)

# list global and module-specific param values
params(mySim)
P(mySim)       # bonus: how do params() and P() differ?

# list start and end times
times(mySim)
start(mySim)
end(mySim)
and the 'current' time
time(mySim)

# get the simulation and module timeunits
timeunit(mySim)
timeunits(mySim)

# get the scheduled and completed event queues
events(mySim)
completed(mySim)

# list the objects (functions, data, etc.) stored in the simList
objects(mySim)

# list the file paths used in the simulation
paths(mySim)
inputPath(mySim)
outputPath(mySim)

mySimOut <- reproducible::Copy(mySim) # make a deep copy of the simList
mySimOut <- spades(mySimOut)

sim <- simInit()
sim$a <- 1
simNew <- sim
simNew$a <- 2

# what value will this have?
sim$a

times(mySim)
times(mySimOut)

objects(mySim)
objects(mySimOut)

modulePath <- getSampleModules(tempdir())
# options(spades.loadReqdPkgs = FALSE) # we don't need to check for packages in this example
mySim <- simInit(modules = dir(modulePath[1:3]),
paths = list(modulePath = modulePath),
objects = list(b = 1))
simOut <- spades(mySim)

  1. Note that simInitAndSpades calls simInit internally↩︎