Parameter Sweeps

Parameter Sweeps#

Using job arrays for powerful automated parameter sweeps

  • EXAMPLE: a small SLURM job array for parameter sweeps

    A SLURM job array is a powerful way to run many similar jobs (e.g. varying a parameter or input file) without submitting hundreds of individual sbatch commands.

    • Here’s a simple template that runs OpenSees on different input files named model_1.tcl, model_2.tcl, …, model_10.tcl:

      #!/bin/bash
      #SBATCH -J ParamSweep
      #SBATCH -o output.%A_%a.out
      #SBATCH -e output.%A_%a.err
      #SBATCH -p normal
      #SBATCH -N 1
      #SBATCH -n 4
      #SBATCH -t 00:30:00
      #SBATCH --array=1-10
      
      module load intel
      module load OpenSees/3.3.0
      
      cd $SCRATCH/my_sweep_project
      
      # Run the OpenSees model for this index
      OpenSees model_${SLURM_ARRAY_TASK_ID}.tcl
      

    How it works

    • --array=1-10 tells SLURM to run this script 10 times, with SLURM_ARRAY_TASK_ID taking values from 1 to 10.

    • The %A in the output filename is replaced by the main SLURM job ID, and %a is replaced by the array index, so you get outputs like:

      output.1234567_1.out
      output.1234567_2.out
      ...
      output.1234567_10.out
      
    • Inside the script, ${SLURM_ARRAY_TASK_ID} picks the right input file.

    This is a classic way to do parameter sweeps or ensemble runs without manually submitting multiple jobs — it’s more scheduler-friendly and makes monitoring easier.

  • EXAMPLE: SLURM job array for Python scripts with parameters

    Imagine you have a single Python script, run_analysis.py, which takes a numeric parameter from the command line, like:

    python run_analysis.py 10
    

    to set, say, the load magnitude, number of stories, or other analysis variable.

    You can run a sweep of 10 different values with a job array.

    Example SLURM script: job_array_python.slurm

    #!/bin/bash
    #SBATCH -J ParamSweepPy
    #SBATCH -o output.%A_%a.out
    #SBATCH -e output.%A_%a.err
    #SBATCH -p normal
    #SBATCH -N 1
    #SBATCH -n 4
    #SBATCH -t 00:15:00
    #SBATCH --array=1-10
    
    module load python3
    
    cd $SCRATCH/my_python_project
    
    # Pass SLURM_ARRAY_TASK_ID as a command-line argument to your script
    python run_analysis.py ${SLURM_ARRAY_TASK_ID}
    
    • What’s happening here?

      • --array=1-10 runs this script 10 times, with ${SLURM_ARRAY_TASK_ID} taking values from 1 to 10.

      • Your Python script reads that value from sys.argv:

      import sys
      
      param = int(sys.argv[1])
      print(f"Running analysis with parameter: {param}")
      
      # rest of your OpenSeesPy model setup using `param`
      
      • Each run gets its own output file:

        output.1234567_1.out
        output.1234567_2.out
        ...
        output.1234567_10.out
        

      This pattern is incredibly flexible. You can:

      • Map array IDs to a lookup file with different parameter sets.

      • Use SLURM_ARRAY_TASK_ID to select different input files or load different config lines.

  • EXAMPLE: driving job arrays from a CSV of parameters

    This is a short, super-practical example of using a lookup file (CSV or text) to drive your parameter sweeps via SLURM_ARRAY_TASK_ID. This is very common in large ensembles or multi-variable studies.

    • Your parameter file

      Make a simple text or CSV file, e.g. params.csv:

      10
      20
      30
      40
      50
      60
      70
      80
      90
      100
      

      Each line is a parameter you want to use.

    • Your Python script

      Your run_analysis.py reads which line to use based on the array task ID:

      import sys
      
      # This script assumes SLURM_ARRAY_TASK_ID passed as sys.argv[1]
      task_id = int(sys.argv[1])
      
      # Read the correct line from the parameter file
      with open("params.csv") as f:
          lines = f.readlines()
          param = int(lines[task_id - 1].strip())  # SLURM_ARRAY_TASK_ID is 1-based
      
      print(f"Running analysis with parameter: {param}")
      
      # Here you could set up your OpenSeesPy model or whatever you want
      # ops.load(nodeTag, *loads) or similar
      

      Note: The task_id - 1 is because SLURM array IDs start at 1, but Python lists start at 0.

    • Your SLURM script

      #!/bin/bash
      #SBATCH -J ParamSweepCSV
      #SBATCH -o output.%A_%a.out
      #SBATCH -e output.%A_%a.err
      #SBATCH -p normal
      #SBATCH -N 1
      #SBATCH -n 4
      #SBATCH -t 00:20:00
      #SBATCH --array=1-10
      
      module load python3
      
      cd $SCRATCH/my_python_project
      
      # Copy the params file to scratch if needed
      cp ~/my_local_dir/params.csv .
      
      python run_analysis.py ${SLURM_ARRAY_TASK_ID}
      
    • Why this is powerful

      • You can drive complex studies with many input values from a single CSV or text file.

      • Each job in the array automatically reads its assigned parameter and runs independently.

      • This is the HPC-friendly way to do large parameter sweeps, sensitivity analyses, or Monte Carlo simulations.

  • EXAMPLE: multiple parameters from a CSV row

    Here is an extension of the same idea, but now reading multiple parameters per job from a CSV row, so you can vary several model inputs at once (like load, height, damping)

    • Your CSV parameter file

      Let’s say you have a file called params.csv that looks like this:

      load,height,damping
      10,5,0.02
      20,10,0.03
      30,15,0.04
      40,20,0.05
      50,25,0.06
      
    • Your Python script

      Now run_analysis.py reads the correct line based on SLURM_ARRAY_TASK_ID:

      import sys
      
      task_id = int(sys.argv[1])
      
      with open("params.csv") as f:
          lines = f.readlines()
          if task_id == 1:
              header = lines[0]  # skip header
          line = lines[task_id]  # line indexing is offset by 1 due to header
      
      # Split line into parameters
      load, height, damping = line.strip().split(',')
      
      # Convert to appropriate types
      load = float(load)
      height = float(height)
      damping = float(damping)
      
      print(f"Running analysis with load={load}, height={height}, damping={damping}")
      
      # Use these variables to set up your model, e.g.
      # ops.load(..., load)
      # ops.node(..., height)
      # ops.rayleigh(..., damping, ...)
      

      Note:

            * `task_id == 1` corresponds to the header line in most CSVs, so data starts at `task_id == 2`.
            * This is a common pitfall — watch your indexing if you have a header row!
      
    • Your SLURM job array script

      #!/bin/bash
      #SBATCH -J MultiParamSweep
      #SBATCH -o output.%A_%a.out
      #SBATCH -e output.%A_%a.err
      #SBATCH -p normal
      #SBATCH -N 1
      #SBATCH -n 4
      #SBATCH -t 00:20:00
      #SBATCH --array=2-6  # start at 2 to skip header line
      
      module load python3
      
      cd $SCRATCH/my_python_project
      cp ~/my_local_dir/params.csv .
      
      python run_analysis.py ${SLURM_ARRAY_TASK_ID}
      

Summary: super scalable studies#

What changes across runs?

How?

Load, height, damping coefficients

Controlled by params.csv

Which line each job uses

Driven by SLURM_ARRAY_TASK_ID

This lets you easily launch dozens, hundreds, or thousands of varied analyses with a single job submission, each automatically pulling its unique inputs.