nf-core/configs: mcw_rcc
Medical College of Wisconsin (MCW) Research Computing Center cluster profile.
nf-core/configs: MCW RCC Configuration
The Medical College of Wisconsin Research Computing Center
(RCC)
runs a SLURM-managed HPC cluster (login hosts ln*, scratch on
qfs1.rcc.mcw.edu:/scratchfs).
Important: keep everything on /scratch, not /group
The /scratch filesystem (qfs1.rcc.mcw.edu:/scratchfs) is mounted on
both login nodes and compute nodes. The /group filesystem
(qfs2.rcc.mcw.edu:/groupfs) is mounted on login nodes only —
compute nodes cannot see it.
A Nextflow run reads its samplesheet, container cache, and reference
files from compute nodes, not from the login node where you launched
nextflow. Anything under /group will appear missing or empty to
running tasks and the pipeline will fail in confusing ways.
Concretely, before launching a pipeline:
-work-dirmust point under/scratch/g/<user>/...--outdirmust point under/scratch/g/<user>/...--input(samplesheet) and any local reference files (FASTA, GTF, …) must live under/scratch/g/<user>/...
-profile mcw_rcc only binds /scratch and /hpc into containers,
not /group, so this constraint is enforced for image-level access
too.
To use, run the pipeline with -profile mcw_rcc. This loads
mcw_rcc.config, which is pre-configured for
this cluster’s SLURM partitions, per-core memory limits, and Apptainer
container runtime.
Prerequisites
Load both Nextflow and Apptainer in your submission script:
module load nextflow/25.10.2
module load apptainer/1.4.1
Apptainer must be loaded in the driver script (not just inside tasks)
because Nextflow pulls each container image from its own driver
process before launching any task — at that point, no
process.beforeScript has had a chance to run. The profile still adds
module load apptainer/1.4.1 to every task’s beforeScript, so once
the driver-side pull succeeds, individual tasks find apptainer
correctly too.
Partitions and auto-routing
The profile picks a SLURM partition per task based on the task’s declared resources:
| Partition | Nodes × CPU × Memory | Max walltime | When this profile uses it |
|---|---|---|---|
normal | 60 × 48 CPU × 360 GB | 7 days | Default for any task at ≤ 7.5 GB / core and ≤ 360 GB / node |
bigmem | 2 × 48 CPU × 1.5 TB | 7 days | Auto-selected when memory > 360 GB or memory / cpus > 7.5 GB |
gpu | 11 mixed V100 / A40 / L40S | 7 days | Tasks labeled process_gpu; one GPU is requested via --gres=gpu:1 |
The normal partition rejects allocations with more than 7680 MB per
CPU. Rather than letting those submissions fail, the profile routes
them to bigmem. If you find a process is being sent to bigmem more
aggressively than you want, lower its memory request or raise its CPU
request (e.g. via withName: '<PROC>' { memory = '...' } in a custom
-c config).
Container images and caching
-profile mcw_rcc enables Apptainer with autoMounts = true and binds
/scratch and /hpc into every container. Apptainer 1.x is fully
compatible with images built for Singularity, so nf-core images pull
and run unchanged.
You must point two apptainer cache variables at /scratch before
launching Nextflow. Home directories on this cluster are ~94 GB and
typically near-full; the OCI → SIF conversion that apptainer performs
during a fresh image pull writes multi-gigabyte temp blobs and will
exhaust home in a single run if not redirected.
# Apptainer's own blob cache and temp dir (used during pull/build):
export APPTAINER_CACHEDIR=/scratch/g/$USER/.apptainer/cache
export APPTAINER_TMPDIR=/scratch/g/$USER/.apptainer/tmp
# Create them once — apptainer fails if APPTAINER_TMPDIR doesn't exist:
mkdir -p "$APPTAINER_CACHEDIR" "$APPTAINER_TMPDIR"
The profile already sets apptainer.cacheDir (the persistent .img
store, equivalent to NXF_APPTAINER_CACHEDIR) to
/scratch/g/$USER/nf-apptainer-cache, so you do not need to export
that one. The two variables above must still be exported in your
submission script, because the driver-side pull happens before
Nextflow’s env { } scope takes effect.
Running on a compute node, not the login node
nextflow itself coordinates the run and must stay alive for hours to
days. Submit it as a SLURM job rather than running it on a login node.
A minimal submission script:
#!/bin/bash
#SBATCH --job-name=nf-driver
#SBATCH --partition=normal
#SBATCH --cpus-per-task=2
#SBATCH --mem=8G
#SBATCH --time=72:00:00
module load nextflow/25.10.2
module load apptainer/1.4.1
export APPTAINER_CACHEDIR=/scratch/g/$USER/.apptainer/cache
export APPTAINER_TMPDIR=/scratch/g/$USER/.apptainer/tmp
mkdir -p "$APPTAINER_CACHEDIR" "$APPTAINER_TMPDIR"
nextflow run nf-core/<pipeline> \
-profile mcw_rcc \
--input /scratch/g/$USER/samplesheet.csv \
--outdir /scratch/g/$USER/results \
-work-dir /scratch/g/$USER/work
Keep -work-dir under /scratch (large, fast GPFS) rather than under
your home directory.
Notes
- The cluster previously offered a
singularitymodule; it was replaced byapptainer/1.4.1. Existing scripts that ran with-profile singularityplusmodule load singularityshould switch to-profile mcw_rcc. - GPU support is provided via the
process_gpulabel. Pipelines that do not declare GPU labels will not use GPU nodes. - Open-OnDemand sessions run on the
oodpartition (12 h max) and are not used by this profile for pipeline workloads.
Config file
// nf-core/configs: Medical College of Wisconsin (MCW) RCC profile//// Cluster: MCW Research Computing Center (RCC)// Scheduler: SLURM// Container engine: Apptainer 1.4.x (drop-in replacement for Singularity)//// Partition characteristics observed on this cluster:// normal (default) — 60 × (48 CPU / 360 GB / 7 d) — MaxMemPerCPU 7680 MB// bigmem — 2 × (48 CPU / 1.5 TB / 7 d) — MaxMemPerCPU 31500 MB// gpu — 11 nodes, mixed V100 / A40 / L40S, 7 d max//// Jobs that would exceed the normal partition's 7.5 GB-per-core cap, or// its 360 GB-per-node cap, are routed to `bigmem` automatically. GPU// jobs (label `process_gpu`) are routed to `gpu` and request one device.//// Filesystem note: `/scratch` is mounted on compute nodes; `/group` is// NOT (login-node only). All inputs, outputs, work dirs, samplesheets,// and the apptainer cache MUST live under `/scratch/g/<user>/` or they// will appear empty to running tasks. The container bind list below// intentionally omits `/group`.
params { config_profile_description = 'Medical College of Wisconsin (MCW) Research Computing Center cluster profile provided by nf-core/configs.' config_profile_contact = 'Nick Semenkovich' config_profile_contact_github = '@semenko' config_profile_contact_email = 'nsemenkovich@mcw.edu' config_profile_url = 'https://www.mcw.edu/departments/clinical-and-translational-science-institute/research-services/research-computing'}
// NOTE: Apptainer is gated behind a module on this cluster, so users// MUST `module load apptainer/1.4.1` (or any 1.4.x release) AND// `export APPTAINER_CACHEDIR=/scratch/g/$USER/.apptainer/cache` (plus// APPTAINER_TMPDIR) in their submission script before invoking// `nextflow run`. The driver-side image pull and OCI→SIF conversion// happen before any `process.beforeScript` or `env { }` scope takes// effect, and home directories on this cluster are too small to hold// a fresh apptainer working set. See docs/mcw_rcc.md.apptainer { enabled = true autoMounts = true runOptions = '-B /scratch,/hpc' // Persistent image store: one shared `.img` cache per user under // /scratch. Equivalent to setting NXF_APPTAINER_CACHEDIR; doing it // here means users don't have to export it. Apptainer's own // pull-time cache (APPTAINER_CACHEDIR / APPTAINER_TMPDIR) still // needs to be exported in the driver script — see docs/mcw_rcc.md. cacheDir = "/scratch/g/${System.getenv('USER')}/nf-apptainer-cache"}
// Task-side safety net: any container engine operation that happens// inside a process picks up these paths. Users who forget to export// them in the driver script will still see the driver-side pull// fail, but task re-pulls and any in-task apptainer use are routed// to scratch automatically.env { APPTAINER_CACHEDIR = "/scratch/g/${System.getenv('USER')}/.apptainer/cache" APPTAINER_TMPDIR = "/scratch/g/${System.getenv('USER')}/.apptainer/tmp"}
process { executor = 'slurm'
// Single-node ceilings: bigmem nodes are 48 CPU / 1.5 TB; max walltime 7 days. resourceLimits = [ memory: 1500.GB, cpus : 48, time : 168.h, ]
// Apptainer replaces the old `singularity` module on this cluster. beforeScript = 'module load apptainer/1.4.1'
cache = 'lenient'
queue = { def mem_per_cpu_mb = task.memory ? (task.memory.toMega() / task.cpus) : 0 if ((task.memory && task.memory > 360.GB) || mem_per_cpu_mb > 7680) { return 'bigmem' } return 'normal' }
withLabel: 'process_gpu' { queue = 'gpu' clusterOptions = '--gres=gpu:1' containerOptions = '--nv' }}
executor { queueSize = 100 submitRateLimit = '10 sec' pollInterval = '30 sec'}