Supported Software¶
C++ and Fortran¶
Compilers are managed via modules. Always match your compiler version between compilation and execution.
# Modules are unavailable in batch scripts until you source this —
# see The Module System. Harmless to include interactively too.
source /etc/profile.d/modules.sh
# Load the GCC toolchain (includes gcc, g++, gfortran)
module load gcc/13
# Confirm you got it — a failed module load is NOT fatal and
# silently leaves you on the system GCC 11.5
gcc --version | head -1
# Compile a C++ program with optimization
g++ -O3 -march=x86-64-v3 -std=c++17 -fopenmp mycode.cpp -o myprogram
# Compile a Fortran program
gfortran -O3 -march=x86-64-v3 mycode.f90 -o myprogram_f
-march=native on this cluster.
The farm is heterogeneous, spanning Broadwell through Sapphire Rapids plus
AMD EPYC. -march=native targets whichever node happened to
compile your code, so a binary built on a recent Intel node will crash with
SIGILL (illegal instruction) when Slurm later schedules it
onto an older node — often days into a campaign, and with an error that
looks nothing like a portability problem.
Use -march=x86-64-v3. Every node in the farm
supports it, and it still enables AVX2 and FMA, which is where most of the
gain is. Do not go to x86-64-v4 (AVX-512): several
nodes lack it, including the Broadwell machines and the EPYC Milan nodes.
See System Architecture.
Python¶
Rather than relying on a system-wide Python installation or a conda-based distribution, we recommend uv — a fast, self-contained Python package and project manager. Every user installs and manages their own Python environment entirely within their home directory, with no module loading required and no administrator intervention.
uv replaces pip, venv, pyenv, and conda in a single tool. It is
meaningfully faster than all of them, handles Python version management
itself, and produces fully reproducible environments via lockfiles.
One-Time Setup — Install uv¶
This is a user-space install. Run it once in an salloc session or as a
short batch job — it is a small download and requires no compilation.
# Install uv into ~/.local/bin (no sudo, no modules required)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Reload your shell environment so ~/.local/bin is on your PATH
source $HOME/.local/bin/env
# Verify the installation
uv --version
Add the following to your ~/.bashrc so uv is available in every future
session and in your batch jobs:
Managing Python Versions¶
uv downloads and manages Python interpreters entirely in user space. You
do not need to request a specific Python version from the sysadmin team.
# Install a specific Python version
uv python install 3.12
# List all Python versions uv has installed
uv python list
Creating and Using a Project Environment¶
The recommended workflow is one virtual environment per project, created
with uv and stored under your project directory or in /home.
# Navigate to your project
cd /home/your_username/qcd_analysis
# Create a virtual environment using a specific Python version
uv venv --python 3.12 .venv
# Activate the environment
source .venv/bin/activate
# Install packages — uv resolves and installs significantly faster than pip
uv pip install numpy scipy matplotlib h5py iminuit
# Or, if your project has a pyproject.toml, simply:
uv sync
# Deactivate when done interactively
deactivate
Using Your Environment in a Batch Job¶
Because uv installs everything in user space, no module load is needed.
You only need to activate the environment and ensure ~/.local/bin is on
your PATH.
#!/bin/bash
#SBATCH --job-name=pdf_analysis
#SBATCH --partition=general
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --mem=16G
#SBATCH --time=02:00:00
#SBATCH --output=logs/python_%j.out
#SBATCH --error=logs/python_%j.err
# uv lives in user space — no module load required
export PATH="$HOME/.local/bin:$PATH"
# Activate the project environment
source /home/your_username/qcd_analysis/.venv/bin/activate
# Confirm the interpreter in use (useful for debugging)
echo "Python: $(which python) — $(python --version)"
# Run your analysis
# Note: there is no /scratch on this cluster. Write results to /home,
# or to /projects if your group has an allocation there.
python compute_distributions.py \
--config configs/run_nlo.yaml \
--output /home/your_username/pdf_results/
Most common scientific packages — numpy, scipy,
matplotlib, h5py — ship pre-built wheels and
install instantly via uv pip install with no compilation at
all. Some HEP packages do not: LHAPDF's Python bindings, for
instance, are built from the upstream C++ source rather than installed
from a wheel. However, if a
package has no available wheel and must be compiled from source, that
installation step requires a compute node. Use an salloc
session in that case. When in doubt, try on the login node and abort
immediately if you see compiler activity.
Reproducibility — Locking Your Environment¶
For research code that must be re-runnable months or years later — or shared with collaborators — pin your exact dependency versions with a lockfile:
# Export a fully pinned, platform-specific lockfile
uv pip freeze > requirements.lock
# Recreate the identical environment from the lockfile on any node
uv pip install --requirements requirements.lock
For more structured projects, uv also supports
pyproject.toml with
automatic lockfile management via uv lock and uv sync — the recommended
approach for any code that will be published or shared.
Mathematica¶
Mathematica 14.2 is installed on every compute node at
/usr/local/Wolfram/Wolfram/14.2. Three entry points are on your PATH
without loading any module — there is no module load mathematica:
| Command | Location | Use |
|---|---|---|
wolframscript |
/usr/bin |
Preferred for batch scripts |
math |
/usr/local/bin |
Terminal kernel; also runs scripts |
wolfram |
/usr/local/bin |
Same kernel, alternate name |
math, wolfram and wolframscript do
not exist on galileo — running them there fails with
command not found. This is not a broken PATH: the
software is deployed to the compute nodes only. Always go through Slurm.
Licensing — read this before you scale up¶
The cluster does not own per-node Mathematica licenses. It uses the
INFN site license, served over the network by a Wolfram license manager
(MathLM) at lm-mathematica.infn.it. Every kernel you start checks out a
seat from that pool and returns it on exit.
Three consequences that matter in practice:
- Seats are finite and shared with the rest of INFN. They are not reserved
for this cluster. A 200-task Mathematica job array can exhaust the pool —
starving both your own remaining tasks and Mathematica users elsewhere in
INFN. Always throttle Mathematica arrays with
%N(see below). - Every kernel counts, including sub-kernels.
LaunchKernels[8]checks out additional seats on top of your master kernel — budget accordingly. - It depends on the network. If connectivity to INFN is disrupted, kernels fail to license and your jobs die at startup, not mid-run. A job that failed in the first ~30 seconds with a licensing message is almost always this, not your code.
You can confirm what your job got by printing the licence details from inside your script:
Print["Version: ", $Version]; (* 14.2.0 for Linux x86 (64-bit) *)
Print["License: ", $LicenseType]; (* Professional *)
Print["Threads: ", $ProcessorCount]; (* hardware threads in your allocation *)
Kernel launch involves a network licence checkout plus loading the installation, and is a fixed cost paid by every kernel before your code runs at all. If your calculation takes 5 seconds, do not submit 500 array tasks — batch many calculations into one script instead, and you will be far faster and far kinder to the licence pool.
Batch Mode (Recommended for Long Calculations)¶
Note the resource request: --cpus-per-task=1. A plain Mathematica script
runs a single kernel and cannot use more, so requesting 8 CPUs would
idle 7 of them. See the parallel example below if you genuinely need more.
#!/bin/bash
#SBATCH --job-name=feynman_integrals
#SBATCH --partition=general
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1 # one kernel = one CPU
#SBATCH --mem=8G # raise if your expressions are large
#SBATCH --time=12:00:00
#SBATCH --output=logs/mathematica_%j.out
#SBATCH --error=logs/mathematica_%j.err
# No module load is needed — Mathematica is not a module.
# wolframscript is preferred: it prints strings cleanly, whereas
# `math -script` echoes them with surrounding quotes.
wolframscript -file /home/your_username/calc/integral_evaluation.wl
# Equivalent using the kernel directly:
# math -noprompt -script /home/your_username/calc/integral_evaluation.wl
Your .wl script should write results to a file explicitly — stdout is for
progress reporting, not for results:
(* integral_evaluation.wl *)
Print["Starting calculation at: ", DateString[]];
result = NIntegrate[
Exp[-x^2] BesselJ[0, x],
{x, 0, Infinity},
PrecisionGoal -> 12,
Method -> "GaussKronrodRule"
];
(* Write to /home or /projects — NOT to $SLURM_TMPDIR, which is
destroyed when the job ends. *)
Export["/home/your_username/results/integral_result.csv",
{{"result", result}}, "CSV"];
Print["Done. Result = ", result];
Parallel Mathematica¶
To use more than one CPU you must launch sub-kernels explicitly. Each one takes an additional licence seat, so size this deliberately rather than grabbing everything available.
$ProcessorCount counts hyper-threads, not cores.
Because the farm schedules whole physical cores with SMT enabled,
$ProcessorCount reports the threads in your
allocation — measured behaviour: --cpus-per-task=1 → 2,
=2 → 2, =4 → 4, =8 → 8. Writing
LaunchKernels[$ProcessorCount] therefore launches one kernel
per hyper-thread. For compute-bound symbolic work that is usually
slower than one kernel per physical core, and it burns twice the
licence seats. Set the count explicitly.
(* parallel_scan.wl *)
(* Set this to match --cpus-per-task in your batch script.
Do not use $ProcessorCount here — it counts hyper-threads. *)
nk = 4;
kernels = LaunchKernels[nk];
Print["Requested ", nk, " sub-kernels, launched ", Length[kernels]];
(* If fewer launched than requested, the licence pool was short —
the calculation still runs, just with less parallelism. *)
results = ParallelTable[ExpensiveFunction[i], {i, 1, 1000}];
Export["/home/your_username/results/scan.mx", results];
CloseKernels[];
Parallel speedup is only worth the extra seats if the work per item is substantial. For embarrassingly parallel scans, a throttled job array of single-kernel jobs is usually the better citizen — it gives the scheduler smaller, more backfillable pieces and holds fewer licence seats at once.
Because the licence pool is shared across INFN, an uncapped array is the one Mathematica mistake with consequences beyond your own jobs:
#SBATCH --array=1-200%8 # at most 8 kernels checked out at once
If you need sustained high-concurrency Mathematica, contact admins@lcm.mi.infn.it first so the seat usage can be checked against the site licence.
Interactive Mathematica¶
Mathematica must run on a compute node, so request one first. Either srun
or salloc works:
# Option A — srun drops you straight onto a compute node
srun --ntasks=1 --cpus-per-task=1 --mem=8G --time=01:00:00 --pty bash
# Option B — salloc reserves the resources, then you work inside them
salloc --ntasks=1 --cpus-per-task=1 --mem=8G --time=01:00:00
# Then launch the terminal interface (no module load required)
math
# Quit the kernel, then release the allocation
# In Mathematica: Quit[] or Ctrl-D
exit
The notebook front end is not installed — this is a terminal kernel only.
For graphics, Export[] to a file and view it after copying it back to your
workstation.
Troubleshooting Mathematica¶
| Symptom | Cause and fix |
|---|---|
math: command not found |
You are on the login node. Request a compute node via srun/salloc/sbatch. |
| Job dies within ~30 s with a licensing error | No free seat in the INFN pool, or the licence server is unreachable. Retry with lower array concurrency; if it persists, report it to the admins. |
LaunchKernels returns fewer kernels than requested |
Sub-kernel seats were unavailable. Reduce --cpus-per-task or run single-kernel. |
| Job killed with no error | Almost always memory. Mathematica's symbolic engine grows fast — check sacct -j JOBID --format=MaxRSS and raise --mem. |
Output strings appear quoted, e.g. "host=""bardeen" |
Cosmetic artefact of math -script. Use wolframscript -file for clean output. |