EFForTS-ABM–InVEST Coupling
This section covers the specifics of running the EFForTS-ABM–InVEST coupled model on the HPC. Read sections 01, 02, 03, and 04 first.
The workflow follows the Apptainer-based rslurm pattern from Section 4 with three additions specific to this model:
- The container image (
ecomod/rstudio:netvest) bundles NetLogo, InVEST, nlrx, and a compatible R environment, but not the group-specificReffortspackage. Refforts changes too frequently to bundle in the image — it is installed from a git clone into your personal R library and updated independently. - InVEST writes output into the model directory during a run, so each compute node needs its own private copy of the model files.
- The
PROJ_LIBenvironment variable must be set so InVEST can find its spatial projection database.
One-time Setup
Build the container image
Follow Section 4 — Building the Container Image.
Use the netvest image:
Store the image in a named subdirectory of $PROJECT (e.g. $PROJECT/sebastian
or $PROJECT/efforts). Use a recognisable name rather than $USER — the HPC
account names (u12345) are not identifiable without looking them up. Create
the folder if it doesn't exist yet:
mkdir -p $PROJECT/<name>
Then build the image:
srun --partition=int --pty bash
module load apptainer
apptainer build $PROJECT/<name>/netvest.sif docker://ecomod/rstudio:netvest
Find the PROJ_LIB path
Enter the container:
apptainer shell --bind $HOME,$PROJECT $PROJECT/<name>/netvest.sif
PROJ_LIB (required by InVEST):
find /usr -name proj.db
# note the output without the trailing /proj.db, typically /usr/share/proj
Save this value. Exit the container with exit.
Install Refforts
Refforts is not bundled in the netvest image and changes too frequently to
rebuild the container image each time. It is installed directly into your
personal R library in $HOME, which is bind-mounted into the container and
persists between sessions. This is an explicit exception to the general rule in
Section 4.
First, clone the repository onto the HPC:
git clone https://github.com/EFForTS-B10/Refforts.git ~/Refforts
Then install it via apptainer exec. The container's system R library is
read-only and R_LIBS_USER is not set in this image, so specify the personal
library path explicitly. Create the directory first (one-time):
mkdir -p ~/R/netvest_library
apptainer exec --bind $HOME,$PROJECT $PROJECT/<name>/netvest.sif Rscript -e 'install.packages(path.expand("~/Refforts"), repos=NULL, type="source", lib=path.expand("~/R/netvest_library"))'
Updating Refforts: when the branch or version changes, pull (or switch branch) and reinstall:
cd ~/Refforts && git checkout <new-branch> && git pull
apptainer exec --bind $HOME,$PROJECT $PROJECT/<name>/netvest.sif \
Rscript -e 'install.packages(path.expand("~/Refforts"), repos=NULL, type="source", lib=path.expand("~/R/netvest_library"))'
If you rebuild netvest.sif: reinstall Refforts afterwards — the personal
library is tied to the container's R version and will break if that changes.
Clone EFForTS-ABM onto the HPC
ssh Emmy-p3
git clone -b <branch> https://github.com/EFForTS-B10/EFForTS-ABM.git
The model is cloned into ~/EFForTS-ABM. To switch to a different branch later:
rm -r EFForTS-ABM
git clone -b <new-branch> https://github.com/EFForTS-B10/EFForTS-ABM.git
Note for sensitivity analyses: nlrx requires that the line set-rand-seed
in EFForTS-ABM.nlogo is commented out, otherwise it ignores the seeds passed
by nlrx. Edit the file on the HPC if needed:
nano EFForTS-ABM/01_EFForTS-ABM/EFForTS-ABM.nlogo
Job Template
Save the following as submit_template_netvest.sh locally (e.g. on your laptop).
It extends the Section 4 template with three additions: loading apptainer,
setting PROJ_LIB, and copying the model to a node-local directory before
the job runs.
The per-node copy is necessary because InVEST writes output into the model directory. Without it, concurrent nodes would overwrite each other's files.
#!/bin/bash
#SBATCH --array=0-{{{max_node}}}{{{job_array_task_limit}}}
#SBATCH --cpus-per-task={{{cpus_per_node}}}
#SBATCH --job-name={{{jobname}}}
#SBATCH --output=slurm_%a.out
{{#flags}}
#SBATCH --{{{name}}}
{{/flags}}
{{#options}}
#SBATCH --{{{name}}}={{{value}}}
{{/options}}
module load apptainer
export R_LIBS_USER=$HOME/R/netvest_library
export OMP_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
export PROJ_LIB=/usr/share/proj
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
cp -r ~/EFForTS-ABM/01_EFForTS-ABM $LOCAL_TMPDIR/01_EFForTS-ABM
{{{rscript}}} --vanilla slurm_run.R
Replace PROJ_LIB path with the value retrieved earlier.
rslurm Script
Note that $LOCAL_TMPDIR must be explicitly bind-mounted into the container
(via the rscript_path) so R inside the container can access the per-node model
copy. The modelpath in the simulation function then references it via
Sys.getenv("LOCAL_TMPDIR").
library(rslurm)
library(Refforts)
sim_fun <- function(param_name, param_min, param_max) {
library("Refforts")
netlogopath <- "/opt/netlogo/6.2.1" # path inside container — verify
modelpath <- file.path(
Sys.getenv("LOCAL_TMPDIR"), "01_EFForTS-ABM", "EFForTS-ABM.nlogo"
)
nl_obj <- nl(
nlversion = "6.2.1",
nlpath = netlogopath,
modelpath = modelpath,
jvmmem = 1024
)
nl_obj@experiment <- experiment(
expname = "hpc",
repetition = 1,
tickmetrics = "true",
idsetup = c("ca", "setup-with-external-maps"),
idgo = "go",
runtime = 61,
evalticks = 60,
metrics = get.abm.metrics(),
constants = get.abm.defaults()
)
nl_obj@simdesign <- simdesign_simple(nl_obj, nseeds = 1)
return(run_nl_all(nl_obj))
}
# One row per parameter combination
params <- abm.table %>%
select(name, min, max) %>%
drop_na()
sjob <- slurm_apply(
f = sim_fun,
params = params,
jobname = "efforts_sim",
nodes = nrow(params),
cpus_per_node = 1,
rscript_path = "apptainer exec --bind $HOME,$PROJECT,$LOCAL_TMPDIR $PROJECT/<name>/netvest.sif Rscript",
sh_template = "submit_template_netvest.sh",
pkgs = c("nlrx", "Refforts", "tidyr", "dplyr", "rslurm"),
slurm_options = list(
"partition" = "scc-cpu",
"time" = "07:30:00",
"mem-per-cpu" = "2G",
"mail-type" = "END,FAIL",
"mail-user" = "your@email.de"
),
submit = FALSE
)
Transfer, submit, and retrieve results as in Section 3 — steps 3–5.