Leavitt: the Bates College HPC Cluster
Accessing Leavitt
Leavitt has 9 compute nodes, forming a 1152 core cluster with two 64-core AMD EPYC processors and 512 GB per node (details here: https://www.bates.edu/research-resources/leavitt-hpc-cluster/leavitt-hardware-specs/). Queuing is provided by SLURM. It was professionally installed and tested by Dell and is generally well-run.
Backups are not provided for /home. There is no other scratch disk space on the machine, everything is in /home. You will have to transfer data to Etna in order to analyze it.
Logging in
Leavitt can be logged into at leavitt.bates.edu using ssh. On campus all you need to do is this:
ssh yourusername@leavitt.bates.eduThis uses default port 22 on campus.
If you want to sign in off campus, you have to use port 222, and you must specify it in your ssh login:
ssh -p 222 yourusername@leavitt.bates.eduIt will prompt you to enter your password – this will be your Bates password. You won’t be able to see what you’re typing so just be careful.
Creating a new directory
Using what you learned about the command line, inside the project directory, create a directory with your Bates username as the name (e.g., for me it would be cberger3).
Compiling code
We are going to use pre-written code for this exercise.
Cloning files from GitHub
In a web browser, navigate to the onboarding repository in the Bates QUEST organization. You will first need to make a GitHub account and send me your GitHub username so I can give you access to that repo.

Click on the green “Code” button, and you will see a drop-down window appear:

Copy the link shown there.
In Leavitt, navigate to the directory you created with your username so you can clone the github repo. This is just how github “copies” from their main website to whatever machine you are working on. The way to do this is the following command
git clone LINK-YOU-COPIED-EARLIERwhere you paste the link you copied after “clone.”
✅
Clone the onboarding github repo to your directory in the BergerLab directory on Leavitt
If you have any problems arise in this process, let me know in the slack.
The directory you cloned is called onboarding. Navigate into this directory and look at what’s inside. You should see the following files:
README.md- This is a text file (markdown or .md) with some description about the onboarding folder
exact_ising_solution.csv- This is another text file with comma separated values (.csv) which contains the exact solution for the Ising Model in 2D.
ising.cpp- This is a C++ code, which contains the blueprints for a program that will simulate the Ising Model using C++
make_ising- This is called a “makefile” and it contains the instructions to the computer for how to assemble your code.
ising2D.py- This is a Python program that will simulate the Ising Model using Python. It does not need to be compiled.
Compiling
Some programming languages (e.g. C++, Fortran) require you to compile your code before you can run it. This is like sending instructions to the computer to assemble a program that runs according to the blueprint you laid out in your code. Other programming languages (e.g. Python, Julia) do not require this.
To compile a code, you have to write a secondary code called a “makefile” which contains all the instructions for how to assemble the program from your code. The instructions are in another programming language, which speaks directly to the computer via the compiler. Think of the makefile as a kind of translation. You can read more about makefiles here, but I have already written the makefile for the ising.cpp code.
What you need to know at this point is that in the makefile, you define a command that you use to assemble the code into what is called an “executable” — the thing that you actually run on your computer. Use the less command to look inside the make_ising file and learn how to use the makefile.
✅
Once you have read over the make_ising file, run the command that will create your executable.
You should now have a new item in your folder: an executable called just ising. This is what you will use to run the simulation, but first we have to learn how to submit jobs to the scheduler.
Submitting a job
Leavitt uses SLURM to schedule compute jobs across the 9 nodes. This is to prevent people from accidentally overclocking a node, and also to make sure everyone gets a fair amount of access (i.e. one person can’t use all 9 nodes for a month straight while everyone else waits for them to finish).
The first and most important thing is this
❗
The node you are on when you log in to Leavitt is not one of the 9 nodes. This is a special node called the “login node” or a “head node.” Never ever run code on the login node, because if you fill that node’s processors up with your work, you can block other people from logging in.
You should use the login node for simple code editing and writing and submitting SLURM scripts. The only way you should run code is by submitting jobs to the scheduler (in the process described below). For more on login nodes and what kinds of tasks are appropriate on them, see this article from Virginia Tech.
If you get to the point where you need to test code interactively on Leavitt or you have very large code that needs a long time to compile, we will talk about how to request an interactive session, which means the scheduler gives you access to a compute node for a set amount of time to test things out.
To submit something to run, you will have to create a SLURM submission script and run that. Let’s say you call your slurm script slurmscript.sh then you would run it with
sbatch slurmscript.shYou can name your script whatever you would like, but it must end with .sh. The Leavitt documentation on the Bates website describes how to make a slurm script, but there are a few examples below.
The most important thing is to remember to assign it to the correct partition. The list of available partitions is here. You should run all your jobs on the defq partition (this means “default queue”).
An example slurm script set up for a compiled C++ code with the executable name mycode and for a Python script with the name mycode.py are shown below
slurmscriptcpp.sh
#!/bin/bash
#
#SBATCH --job-name=testcpp # Assign a name to the job
#SBATCH --partition=defq # Which partition to use
#SBATCH --nodes=1 # Number of nodes
#SBATCH --output=testcpp%j.log # Output that would print to the screen
# can be saved here
#SBATCH --error=err_testcpp%j.log # Errors that arise will be saved here
pwd; hostname; date
./mycode
dateThe #SBATCH lines allow you to define certain instructions for the scheduler. There are lots of options you can use here, but these are the ones you should always have. (Note: not everyone agrees, but this will be the requirement for this research group, so that we can have consistent organization of our code). Here’s an explanation of each line of this code and why I recommend it:
#!/bin/bashThis is required to tell the computer what kind of script this is#SBATCH --job-name=testcppThis line assigns your code with the name testcpp. You can choose what name you want to assign, but it’s useful to have so you can easily see what jobs are running in the queue.SBATCH --partition=defqThis line tells the scheduler which partition to put your job in. Students all use the default queue, so this should always be what you put.#SBATCH --nodes=1This line tells the scheduler how many nodes you need. Until you are working with parallelized code, this will always be one. When you start working with parallelized code, we will talk about how to modify this given the structure of the code.#SBATCH --output=testcpp%j.logThis line will create a file that will store anything your code would normally print to the screen. So if you have any checkpoints built in (i.e. before a loop, the code prints “beginning loop over x”), they will go into this file. Having an output file like this is useful for debugging, so I recommend including it. I also recommend using the same name you used for the job above (testcppin this example), to keep things organized. The%jwill just add the job number assigned by the scheduler once it starts running.#SBATCH --error=err_testcpp%j.logThis line will create a file to store any error messages that the computer sends you during your code’s run. This is also useful for debugging. Just as above, I recommend using the same name but addingerr_before it so you can distinguish error files from output files and the%jwill just add the job number assigned by the scheduler.pwd; hostname; dateThese three commands will put in your output file the following things: the working directory where your code is located, the node the scheduler assigned your job to, and the date and time that it starts../mycodeThis is the command that runs your code. For a compiled C++ executable, you run it using the./command and the executable’s name.dateThis just prints the date and time that the code finishes. This is useful for checking timing of your jobs and determining how long they are taking.
slurmscriptpython.sh
#!/bin/bash
#
#SBATCH --job-name=testpy # Assign a name to the job
#SBATCH --partition=defq # Which partition to use
#SBATCH --nodes=1 # Number of nodes
#SBATCH --output=testpy%j.log # Output that would print to the screen
# can be saved here
#SBATCH --error=err_testpy%j.log # Errors that arise will be saved here
pwd; hostname; date
module load anaconda
python mycode.py
dateFor all the #SBATCH commands, this slurm script is the same at the top. Here are the things that are different when running a python code:
module load anacondaWhen working with Python, you will likely be using special libraries that have been written for Python. In this group, we will almost always be using numpy, scipy, and pandas. The module anaconda contains all these libraries, and you have to load them before you can run the code.python mycode.pyThis is the command that runs your code for Python. Instead of the./command, we use thepythoncommand. Since Python doesn’t require compilation, you use the name of the python script including the .py extension.
Write and submit SLURM scripts
Your next task is to create your own SLURM scripts for the C++ and the Python versions of the Ising Model. You can create these in a text file on your computer and use GitHub or scp to copy them to Leavitt or you can use a text editor in Leavitt to do it in-place (Leavitt supports both emacs and vi).
✅
Write and submit your scripts. When they are finished running, send me the error and output files (everything with a .log extension) via slack.
After you have submitted a job, you can check it’s status with the command squeue. If the cluster is busy, it might help to just check your own jobs, which you can do with
squeue -u yourBatesusernameCopying to Etna
The output for any job you submit will be written in the folder you submitted from (unless you have specified otherwise in your code). Since Leavitt is not backed up and does not connect to our Metis Jupyter server directly, you will have to copy the data to Etna in order to work with it.
cp -r datafolder/ /usr/netapp/etna/Scholarship/Faculty\ Name/Students/Student\ Name❗
Important: those back slashes between the first and last name are crucial — it’s so that the spaces are included in the file name. If they are not, you will get an error message saying e.g. cp: target 'xxxx/xxxx/' is not a directory where the xxx is part of your filepath that comes after a space
Once the data is copied to Etna, you can access it in Metis and work with it through JupyterLab.