setupProject for nimble workflowsFrom a ‘works on my machine’ script to a portable one
2026-06-12
A typical SpaDES workflow starts as an ordinary script:
simInit() then spades()It works – on the machine where it was written.
Move it elsewhere and it breaks: a missing package, a hard-coded path, a data file that was never in the repository.
## 1) Packages -- load
library(SpaDES.core)
library(SpaDES.project)
library(terra)
library(sf)
## 2) Paths ----------------------------------------------------------
setPaths(
modulePath = "~",
inputPath = "~",
outputPath = "~",
cachePath = "~",
scratchPath = "~"
)
## clean cache to avoid previous mismatches
unlink(getPaths()$cachePath, recursive = TRUE)
dir.create(getPaths()$cachePath, showWarnings = FALSE)
## 3) Download modules ----------------------------------------------
SpaDES.project::getModule(
modules = c(
"PredictiveEcology/Biomass_borealDataPrep",
"PredictiveEcology/Biomass_speciesData",
"PredictiveEcology/Biomass_core"
),
modulePath = getPaths()$modulePath,
overwrite = TRUE
)
## 4) Download study area from Google Drive -------------------------
shapeZipID <- "1gycTXyZzgXIUGM6dyAJbmFxq8TOAm-Ik"
shapeDir <- file.path(getPaths()$inputPath, "studyArea")
dir.create(shapeDir, recursive = TRUE, showWarnings = FALSE)
shapeZip <- file.path(shapeDir, "studyArea.zip")
if (!file.exists(shapeZip)) {
download.file(
url = paste0("https://drive.google.com/uc?export=download&id=", shapeZipID),
destfile = shapeZip,
mode = "wb"
)
}
## unzip ------------------------------------------------------------
if (length(list.files(shapeDir, pattern = "\\.shp$", recursive = TRUE)) == 0) {
unzip(shapeZip, exdir = shapeDir)
}
## read shapefile ---------------------------------------------------
shpFile <- list.files(shapeDir, pattern = "\\.shp$",
recursive = TRUE, full.names = TRUE)
stopifnot(length(shpFile) == 1)
studyArea <- terra::vect(shpFile)
studyArea <- terra::project(studyArea, "EPSG:3978")
## 5) Simulation settings -------------------------------------------
times <- list(start = 1, end = 1)
modules <- c("Biomass_borealDataPrep", "Biomass_speciesData", "Biomass_core")
objects <- list(studyArea = studyArea, studyAreaLarge = studyArea)
## 6) Initialize and run --------------------------------------------
sim <- simInit(times = times, modules = modules,
objects = objects, paths = getPaths())
sim <- spades(sim)setupProject()~18 lines (including installing toolkit)
declarative: what is needed
packages reconciled in one place
packages installed and loaded as needed
if (!require("SpaDES.core")) install.packages("SpaDES.core"); library("SpaDES.core")
or
pak::pak("SpaDES.core"); require("SpaDES.core")
every input starts from a URL
if (!require("pak")) install.packages("pak")
pak::pak(c("PredictiveEcology/Require@development",
"PredictiveEcology/SpaDES.project@development"),
ask = FALSE)
out <- SpaDES.project::setupProject(
modules = c(
"PredictiveEcology/Biomass_borealDataPrep",
"PredictiveEcology/Biomass_speciesData",
"PredictiveEcology/Biomass_core"),
times = list(start = 1, end = 1),
packages = c("PredictiveEcology/LandR@development (>= 1.2.0.9002)"),
shapeZipID = "1gycTXyZzgXIUGM6dyAJbmFxq8TOAm-Ik",
studyArea = reproducible::prepInputs(url = shapeZipID, fun = terra::vect) |>
terra::project("EPSG:3978"),
studyAreaLarge = studyArea
)
finalOut <- SpaDES.core::simInitAndSpades2(out)library() isn’t portablesetupProject(packages=) installs and loads into a project librarysetPaths()setupProject() sets a sane layout (override with paths =)Cache doesn’t go stale – nothing to clearprepInputs()Cache: downloads & processes once# before
shapeZipID <- "1gycTXyZzgXIUGM6dyAJbmFxq8TOAm-Ik"
shapeDir <- file.path(getPaths()$inputPath, "studyArea")
dir.create(shapeDir, recursive = TRUE, showWarnings = FALSE)
shapeZip <- file.path(shapeDir, "studyArea.zip")
if (!file.exists(shapeZip)) {
download.file(
url = paste0("https://drive.google.com/uc?export=download&id=", shapeZipID),
destfile = shapeZip,
mode = "wb"
)
}
## unzip ------------------------------------------------------------
if (length(list.files(shapeDir, pattern = "\\.shp$", recursive = TRUE)) == 0) {
unzip(shapeZip, exdir = shapeDir)
}
## read shapefile ---------------------------------------------------
shpFile <- list.files(shapeDir, pattern = "\\.shp$",
recursive = TRUE, full.names = TRUE)
stopifnot(length(shpFile) == 1)
studyArea <- terra::vect(shpFile)
studyArea <- terra::project(studyArea, "EPSG:3978").GlobalEnv?.GlobalEnv sits atop R’s search path – everything can see itsetupProject routes objects into the simList → missing inputs fail loudly, where you can fix themprepInputs() + Cache skip repeated workThese traits allow bigger projects chain many modules together without the setup collapsing under its own weight.
They also allow rapid initiation of small projects.