Nothing
#' Named list of core `SpaDES` modules
#'
#' Internal function.
#'
#' @return Returns a named list of the core modules.
#'
#' @author Alex Chubaty
#' @keywords internal
#' @name .coreModules
#' @rdname coreModules
.coreModules <- function() {
list(
checkpoint = "checkpoint",
save = "save",
progress = "progress",
load = "load",
restartR = "restartR"
)
}
#' @keywords internal
#' @include environment.R
.pkgEnv$.coreModules <- .coreModules() |> unname()
#' @keywords internal
#' @include environment.R
.pkgEnv$.coreModulesMinusSave <- .coreModules() |> setdiff("save") |> unname()
#' @keywords internal
.pkgEnv$.progressEmpty <- list(type = NA_character_, interval = NA_real_)
# empty event lists ---------------------------------------------------------------------------
#' Blank (template) event list
#'
#' Internal function called from `spades`, returning an empty event list.
#'
#' Event lists are sorted (keyed) first by time, second by priority.
#' Each event is represented by a [data.table::data.table()] row consisting of:
#' \tabular{ll}{
#' `eventTime` \tab The time the event is to occur.\cr
#' `moduleName` \tab The module from which the event is taken.\cr
#' `eventType` \tab A character string for the programmer-defined event type.\cr
#' `eventPriority` \tab The priority given to the event. \cr
#' }
#'
#' @param eventTime The time the event is to occur.
#' @param moduleName The module from which the event is taken.
#' @param eventType A character string for the programmer-defined event type.
#' @param eventPriority The priority given to the event.
#'
#' @return Returns an empty event list.
#'
#' @author Alex Chubaty
#' @importFrom data.table data.table
#' @keywords internal
#' @name emptyEventList
#' @rdname emptyEventList
.emptyEventListDT <- data.table(
eventTime = integer(0L),
moduleName = character(0L),
eventType = character(0L),
eventPriority = numeric(0L)
)
#' @importFrom data.table data.table
#' @keywords internal
#' @rdname emptyEventList
.singleEventListDT <- data.table(
eventTime = integer(1L),
moduleName = character(1L),
eventType = character(1L),
eventPriority = numeric(1L)
)
#' @keywords internal
#' @rdname emptyEventList
setGeneric(".emptyEventList", function(eventTime, moduleName, eventType, eventPriority) {
standardGeneric(".emptyEventList")
})
#' @keywords internal
#' @rdname emptyEventList
#' @importFrom data.table set copy
setMethod(
".emptyEventList",
signature(eventTime = "numeric", moduleName = "character",
eventType = "character", eventPriority = "numeric"),
definition = function(eventTime, moduleName, eventType, eventPriority) {
# This is faster than direct call to new data.table
eeldt <- copy(.singleEventListDT)
set(eeldt, NULL, "eventTime", eventTime)
set(eeldt, NULL, "moduleName", moduleName)
set(eeldt, NULL, "eventType", eventType)
set(eeldt, NULL, "eventPriority", eventPriority)
eeldt # don't set key because it is set later when used
})
#' @keywords internal
#' @rdname emptyEventList
setMethod(
".emptyEventList",
signature(eventTime = "missing", moduleName = "missing",
eventType = "missing", eventPriority = "missing"),
definition = function() {
copy(.emptyEventListDT)
})
#' @keywords internal
#' @rdname emptyEventList
.emptyEventListCols <- colnames(.emptyEventList())
# empty metadata ------------------------------------------------------------------------------
#' Default (empty) metadata
#'
#' Internal use only.
#' Default values to use for metadata elements when not otherwise supplied.
#'
#' @param x Not used. Should be missing.
#'
#' @author Alex Chubaty
#' @importFrom terra ext
#' @include simList-class.R
#' @keywords internal
#' @rdname emptyMetadata
setGeneric(".emptyMetadata", function(x) {
standardGeneric(".emptyMetadata")
})
#' @rdname emptyMetadata
setMethod(
".emptyMetadata",
signature(x = "missing"),
definition = function() {
out <- list(
name = moduleDefaults[["name"]],
description = moduleDefaults[["description"]],
keywords = moduleDefaults[["keywords"]],
childModules = moduleDefaults[["childModules"]],
authors = moduleDefaults[["authors"]],
version = moduleDefaults[["version"]],
spatialExtent = terra::ext(rep(0, 4)), ## match up with moduleDefaults
timeframe = as.POSIXlt(c(NA, NA)), ## match up with moduleDefaults
timeunit = moduleDefaults[["timeunit"]],
citation = moduleDefaults[["citation"]],
documentation = moduleDefaults[["documentation"]],
reqdPkgs = moduleDefaults[["reqdPkgs"]],
parameters = defineParameter(),
inputObjects = ._inputObjectsDF(),
outputObjects = ._outputObjectsDF()
)
return(out)
})
#' Find objects if passed as character strings
#'
#' Objects are passed into `simList` via `simInit` call or `objects(simList)`
#' assignment. This function is an internal helper to find those objects from their
#' environments by searching the call stack.
#'
#' @param objects A character vector of object names
#' @param functionCall A character string identifying the function name to be
#' searched in the call stack. Default is `"simInit"`.
#'
#' @author Eliot McIntire
#' @importFrom reproducible .grepSysCalls
#' @keywords internal
.findObjects <- function(objects, functionCall = "simInit") {
scalls <- sys.calls()
grep1 <- .grepSysCalls(scalls, functionCall)
grep1 <- pmax(min(grep1[sapply(scalls[grep1], function(x) {
tryCatch(is(parse(text = x), "expression"), error = function(y) NA)
})], na.rm = TRUE) - 1, 1)
# Convert character strings to their objects
lapply(objects, function(x) get(x, envir = sys.frames()[[grep1]]))
}
#' Modify package order in search path
#'
#' Intended for internal use only. It modifies the search path (i.e., `search()`)
#' such that the packages required by the current module are placed first in the
#' search path. Note, several "core" packages are not touched; or more specifically,
#' they will remain in the search path, but may move down if packages are rearranged.
#' The current set of these core packages used by SpaDES can be found here:
#' `SpaDES.core:::.corePackages`
#'
#' @param pkgs The packages that are to be placed at the beginning of the search path,
#'
#' @param removeOthers Logical. If `TRUE`, then only the packages in
#' `c(pkgs, SpaDES.core:::.corePackages)`
#' will remain in the search path, i.e., all others will be removed.
#'
#' @param skipNamespacing Logical. If `FALSE`, then the running of an event in a module
#' will not trigger a rearrangement of the search() path. This will
#' generally speed up module simulations, but may create name
#' conflicts between packages.
#'
#' @return Nothing. This is used for its side effects, which are "severe".
#'
#' @author Eliot McIntire
#' @keywords internal
#' @rdname modifySearchPath
.modifySearchPath <- function(pkgs, removeOthers = FALSE,
skipNamespacing = !getOption("spades.switchPkgNamespaces")) {
if (!skipNamespacing) {
pkgs <- c("SpaDES.core", pkgs)
pkgs <- unlist(pkgs)[!(pkgs %in% .corePackages)]
pkgsWithPrefix <- paste0("package:", unlist(pkgs))
pkgPositions <- pmatch(pkgsWithPrefix, search())
# Find all packages that are not in the first sequence after .GlobalEnv
whNotAtTop <- !((seq_along(pkgPositions) + 1) %in% pkgPositions)
if (any(whNotAtTop)) {
whAdd <- which(is.na(pkgPositions))
if (removeOthers) {
pkgsToRm <- setdiff(search(), pkgsWithPrefix)
pkgsToRm <- grep(pkgsToRm, pattern = .corePackagesGrep, invert = TRUE, value = TRUE)
whRm <- seq_along(pkgsToRm)
} else {
whRm <- which(pkgPositions > min(which(whNotAtTop)))
pkgsToRm <- pkgs[whRm]
}
if (length(whRm) > 0) {
# i.e,. ones that need reordering
suppressWarnings(
lapply(unique(gsub(pkgsToRm, pattern = "package:", replacement = "")[whRm]), function(pack) {
try(detach(paste0("package:", pack), character.only = TRUE), silent = TRUE)
})
)
}
#if (!removeOthers) {
if (length(whAdd)) {
suppressMessages(
lapply(rev(pkgs[whAdd]), function(pack) {
try(attachNamespace(pack), silent = TRUE)
})
)
}
#}
}
}
}
#' @keywords internal
.corePackages <- c(".GlobalEnv", "Autoloads", "SpaDES.core", "base", "grDevices",
"rstudio", "devtools_shims",
"methods", "utils", "graphics", "datasets", "stats", "testthat") # nolint
.corePackagesGrep <- paste(.corePackages, collapse = "|")
# .pkgEnv$corePackagesVec <- unlist(strsplit(.corePackagesGrep, split = "\\|"))
.corePackagesVec <- c(.corePackages[(1:2)], paste0("package:", .corePackages[-(1:2)]))
#' `tryCatch` that keeps warnings, errors and value (result)
#'
#' From <https://stackoverflow.com/a/24569739/3890027>
#'
#' @keywords internal
#' @rdname tryCatch
.tryCatch <- function(expr) {
warn <- err <- NULL
value <- withCallingHandlers(
tryCatch(expr, error = function(e) {
err <<- e
NULL
}), warning = function(w) {
warn <<- w
invokeRestart("muffleWarning")
})
list(value = value, warning = warn, error = err)
}
#' All equal method for `simList` objects
#'
#' This function removes a few attributes that are added internally
#' by \pkg{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.
#'
#' @inheritParams base::all.equal
#'
#' @return See [base::all.equal()]
#'
#' @method all.equal simList
#' @exportS3Method all.equal simList
#' @importFrom reproducible .wrap
all.equal.simList <- function(target, current, ...) {
attr(target, ".Cache")$newCache <- NULL
attr(current, ".Cache")$newCache <- NULL
attr(target, "removedObjs") <- NULL
attr(current, "removedObjs") <- NULL
if (length(target@completed))
completed(target) <- completed(target, times = FALSE)
if (length(current@completed))
completed(current) <- completed(current, times = FALSE)
# remove all objects starting with ._ in the simList@.xData
objNamesTarget <- ls(envir = envir(target), all.names = TRUE, pattern = "^[.]_")
objNamesCurrent <- ls(envir = envir(current), all.names = TRUE, pattern = "^[.]_")
objsTarget <- mget(objNamesTarget, envir = envir(target))
objsCurrent <- mget(objNamesCurrent, envir = envir(current))
on.exit({
# put them back on.exit
list2env(objsTarget, envir = envir(target))
list2env(objsCurrent, envir = envir(current))
})
rm(list = objNamesTarget, envir = envir(target))
rm(list = objNamesCurrent, envir = envir(current))
target1 <- .wrap(target, cachePath = getwd()) # deals with SpatVector/SpatRaster etc.
current1 <- .wrap(current, cachePath = getwd()) # deals with SpatVector/SpatRaster etc.
all.equal.default(target1, current1, ...)
}
#' @importFrom utils packageVersion
needInstall <- function(
pkg = "methods",
minVersion = NULL,
messageStart = paste0(pkg, if (!is.null(minVersion)) paste0("(>=", minVersion, ")"),
" is required. Try: ")) {
need <- FALSE
if (!requireNamespace(pkg, quietly = TRUE)) {
need <- TRUE
} else {
if (!is.null(minVersion))
if (isTRUE(packageVersion(pkg) < minVersion))
need <- TRUE
}
if (need) {
stop(messageStart, "install.packages('", pkg, "')")
}
}
.moduleNameNoUnderscore <- function(mod) gsub("_", ".", basename(mod))
#' Get copies of sample files for examples and tests
#'
#' @param tmpdir character specifying the path to a temporary directory (e.g., `tempdir()`)
#'
#' @return character vector of filepaths to the copied files
#'
#' @export
#' @importFrom reproducible checkPath
#' @rdname getSampleFiles
getMapPath <- function(tmpdir) {
mapPath <- system.file("maps", package = "quickPlot")
mapPathTmp <- checkPath(file.path(tmpdir, "maps"), create = TRUE)
file.copy(dir(mapPath, full.names = TRUE), mapPathTmp)
mapPathTmp
}
#' @export
#' @rdname getSampleFiles
getSampleModules <- function(tmpdir) {
sampModPath <- system.file("sampleModules", package = "SpaDES.core")
sampModPathTmp <- checkPath(file.path(tmpdir, "sampleModules"), create = TRUE)
allFiles <- dir(sampModPath, recursive = TRUE, full.names = TRUE)
allFilesRel <- dir(sampModPath, recursive = TRUE)
allNewFiles <- file.path(sampModPathTmp, allFilesRel)
checkPath(unique(dirname(allNewFiles)), create = TRUE)
out <- file.copy(allFiles, file.path(sampModPathTmp, allFilesRel))
sampModPathTmp
}
#' Text for no event with that name
#'
#' Provides the text to be sent to `warning` in each module as the default `switch` case.
#'
#' @inheritParams spades
#'
#' @return A text string specifying the event name and module for which there is no event
#'
#' @export
noEventWarning <- function(sim) {
paste(
"Undefined event type: \'", current(sim)[1, "eventType", with = FALSE],
"\' in module \'", current(sim)[1, "moduleName", with = FALSE], "\'",
sep = ""
)
}
._txtClockTime <- "._clockTime"
._txtStartClockTime <- "._startClockTime"
._txtPrevEventTimeFinish <- "._prevEventTimeFinish"
._txtSimNesting <- "._simNesting"
._txtDotUseCache <- ".useCache"
#' Reserved module parameter names
#'
#' These are common parameter names that are reserved for specific use within modules.
#'
#' - `.plotInitialTime`: the initial time for plotting;
#' - `.plotInterval`: the interval between plots;
#' - `.plots`: the types of plots to create (see `types` argument in [Plots()]);
#' - `.saveInitialTime`: the initial time for saving;
#' - `.saveInterval`: the interval between saves;
#' - `.useCache`: whether to use caching, or which events to cache;
#' - `.useParallel`: whether to use parallel processing, or the number of parallel cores to use;
#'
#' @keywords internal
#' @rdname dot-params
.knownDotParams <- c(".plotInitialTime", ".plotInterval",
".plots",
".saveInitialTime", ".saveInterval",
._txtDotUseCache, ".useParallel") ## TODO: add others here, e.g. .studyAreaName?
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.