Parallel Runs: Local and Multi-Node MPI
This page explains how to choose and size parallel runs in corgihowfsc.
corgihowfsc supports two ways to run in parallel:
Local run: run on one machine using multiprocessing.
Multi-node (MPI) run: runs with MPI ranks, usually on a cluster, across multiple nodes.
For the full YAML field descriptions, see Parameter Reference. For details on how the local multiprocessing and MPI setups are arranged, see Parallel Setup Details.
Quick Start
Local Run
Use local mode on a laptop, workstation, or single cluster node.
Note
The values below are examples. Choose num_imager_worker, num_proper_process, and num_jac_process based on the CPUs available on your machine. See Sizing a Local Run.
runtime:
use_mpi: false
num_imager_worker: 3 # null: serial image generation; set > 1 for local image workers
num_proper_process: 5 # PROPER processes inside each image worker
num_jac_process: 6 # local Jacobian processes
Run:
python run_corgisim_nulling_gitl.py --param_file default_param.yml
Multi-node (MPI) Run
Use an MPI run when one machine is not enough and you want to spread the simulation across multiple cluster nodes. MPI (Message Passing Interface) is a standard communication protocol for parallel programs that coordinates separate processes across a cluster, including across nodes with separate memory, by passing messages between them.
In an MPI run, one Python process acts as the manager. It runs the GITL loop and sends image generation or Jacobian calculations to worker processes. The worker processes wait for tasks, run them, and send the results back to the manager.
This is useful because CorgiSim/PROPER image generation and Jacobian computation can be slow and resource intensive. MPI lets several workers run these tasks at the same time across a cluster allocation.
MPI documentation often calls these processes “ranks”. This page uses “manager process” and “worker processes” to explain the run.
runtime:
use_mpi: true
num_imager_worker: 21 # MPI worker processes
num_proper_process: 5 # PROPER processes per worker process
num_jac_process: 6 # ignored in MPI mode
For this example, we launch 22 total MPI processes:
1 manager process + 21 worker processes = 22 total MPI processes
Example Slurm launch:
#SBATCH --nodes=4
#SBATCH --ntasks=22
#SBATCH --cpus-per-task=5
export OMP_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
mpirun -np $SLURM_NTASKS python run_corgisim_nulling_gitl.py --param_file example_mpi_param.yml
Note
Example MPI submission scripts are available in corgihowfsc/scripts/example_mpi_*.sh. Use them as templates, but check the module loads, conda environment, --ntasks, and --cpus-per-task values for your cluster.
Choose Between Local and MPI
Situation |
Recommended Run Type |
|---|---|
Laptop or workstation |
Local run |
First test run or debugging |
Local run |
Single-node run with enough CPUs |
Local run |
Multi-node cluster allocation |
MPI run |
Slow CorgiSim image generation across many iterations |
MPI run |
Start with a local run. Switch to MPI when the per-iteration wall time is the bottleneck and you have a cluster allocation available.
Parallel Parameters
Parameter |
Local Run ( |
MPI Run ( |
|---|---|---|
|
Number of local image worker processes. |
Number of MPI worker processes. Usually |
|
Number of PROPER subprocesses inside each local image worker. |
Number of PROPER subprocesses inside each MPI worker process. Usually matches |
|
Number of local Jacobian processes. |
Ignored. MPI Jacobian chunks use the MPI worker processes capped by |
|
|
|
Sizing a Local Run
For local image generation, the approximate peak CPU use is:
num_imager_worker x num_proper_process
For example:
num_imager_worker: 3
num_proper_process: 5
can use up to:
3 x 5 = 15 CPU cores
num_jac_process controls a separate local Jacobian process pool. It is not active at the exact same time as image generation, but it should still be no larger than the CPUs available for the job.
At the start of the local run, it checks for oversubscription and warns if the requested process count exceeds the CPUs visible to the process. Oversubscription means asking for more parallel processes than available CPU cores, which can make the run slower rather than faster because processes compete for the same cores.
For a first local run, start conservatively:
runtime:
use_mpi: false
num_imager_worker: null
num_proper_process: 5
num_jac_process: 6
Increase num_imager_worker only if image generation is the bottleneck and the machine has enough CPUs for the additional workers.
MPI Run Model
In MPI mode, one process is the manager. It runs the main loop and sends work to the workers.
process 0 manager
process 1..N-1 workers
Worker processes are initialized once and reused for image generation and Jacobian chunks.
The manager process does not compute image or Jacobian tasks. Therefore:
total MPI processes = num_imager_worker + 1
Important
In MPI mode, launch num_imager_worker + 1 total MPI processes. Rank 0 is the manager and does not run frame or Jacobian tasks.
Example:
num_imager_worker: 21
requires:
mpirun -np 22 ...
or in Slurm:
#SBATCH --ntasks=22
MPI Process and CPU Sizing
For MPI mode, use this mapping:
--ntasks = num_imager_worker + 1
--cpus-per-task = num_proper_process
Example YAML:
runtime:
use_mpi: true
num_imager_worker: 21
num_proper_process: 5
Example Slurm settings:
#SBATCH --ntasks=22
#SBATCH --cpus-per-task=5
This means:
1 manager process
21 worker processes
5 CPUs available to each MPI process
Each worker process may spawn up to num_proper_process PROPER subprocesses.
Choosing num_imager_worker
For image generation, the useful maximum is the number of images in one framelist:
n_wvl x (2 x n_probe_pairs + 1)
For HLC band 1 with 3 wavelengths and 3 probe pairs:
3 x (2 x 3 + 1) = 21
So a natural MPI setup is:
num_imager_worker: 21
and:
#SBATCH --ntasks=22
Using more than 21 worker processes will not speed up image generation for this case because there are only 21 image tasks in one framelist. Extra workers may still be initialized, but they will sit idle during image collection.
Process-Per-Core Mode
The intended parallel model is process-based:
MPI processes x PROPER processes
Threaded numerical libraries should be kept single-threaded because this workflow uses process-based parallelism:
export OMP_NUM_THREADS=1
export MKL_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
PROPER’s multi-run path uses a multiprocessing pool for NCPUS work and sets its multi-process FFT thread count to 1 internally. The environment variables above prevent threaded math libraries from adding extra parallelism around the process-based model.
Do not use:
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
Slurm Launch Notes
Prefer an explicit MPI process count:
mpirun -np $SLURM_NTASKS python run_corgisim_nulling_gitl.py --param_file example_mpi_param.yml
On systems where mpirun correctly uses the scheduler allocation, you can also omit -np:
mpirun python run_corgisim_nulling_gitl.py --param_file mpi_param.yml
Warning
Check that the MPI process count launched by Slurm matches num_imager_worker + 1. Extra MPI processes are initialized but remain idle; too few MPI processes reduce the requested parallelism.
If you use:
#SBATCH --ntasks-per-node=6
some MPI launchers may infer the total process count from:
nodes x ntasks-per-node
For example:
#SBATCH --nodes=4
#SBATCH --ntasks-per-node=6
This can launch 24 MPI processes. If your YAML has:
num_imager_worker: 21
you only wanted 22 total MPI processes, so 2 worker processes will be initialized but idle.
Common Startup Warnings
More MPI Processes Than Requested Workers
MPI launched 23 worker processes, but num_imager_worker=21.
Extra worker processes will be initialized but remain idle.
This means MPI launched more processes than your YAML will use. The run is still correct, but some allocated processes are wasted.
Fix by launching exactly:
num_imager_worker + 1
total MPI processes.
Fewer MPI Processes Than Requested Workers
MPI requested 21 active worker processes, but only 9 worker processes were launched.
The MPI task queues will use 9 workers.
The run is still correct, but slower than expected.
Fix by increasing the MPI process count or reducing num_imager_worker.
PROPER Processes Exceed CPUs Per Task
num_proper_process exceeds the CPU affinity visible to the MPI process
This usually means:
num_proper_process
is larger than:
#SBATCH --cpus-per-task
Fix by making them match, or by reducing num_proper_process.