SLURM with LAMMPS

SLURM with LAMMPS#

executorlib extends the Executor interface from the Python standard library’s concurrent.futures to distribute Python functions as jobs on an HPC cluster. This notebook couples executorlib with pylammpsmpi to run an interactive, MPI-parallel LAMMPS molecular dynamics simulation inside a single persistent SLURM allocation. See the pylammpsmpi integration guide for background.

Based on the cmti and cmmg clusters hosted at the MPCDF for the MPI for Sustainable Materials.

from ase.build import bulk
from executorlib import SlurmClusterExecutor
from jinja2 import Template
from lammpsparser import get_potential_dataframe
from pylammpsmpi import LammpsASELibrary, init_function

The imports combine ASE for building the atomic structure, executorlib’s SlurmClusterExecutor for submitting the SLURM job, Jinja2 for templating LAMMPS input commands, lammpsparser for looking up interatomic potentials, and pylammpsmpi’s LammpsASELibrary together with init_function for driving an MPI-parallel LAMMPS instance interactively from Python.

structure = bulk("Au", cubic=True).repeat((10,10,10))
element_lst = structure.get_chemical_symbols()
element_lst[0] = "Cu"
structure.set_chemical_symbols(element_lst)
structure
Atoms(symbols='Au3999Cu', pbc=True, cell=[40.8, 40.8, 40.8])

Using ASE, a bulk gold (Au) FCC unit cell is built and repeated 10×10×10 to create a 4000-atom supercell. One atom is then substituted with copper (Cu) to introduce a single substitutional defect, giving an Au₃₉₉₉Cu structure.

df_pot = get_potential_dataframe(structure)
df_pot
Config Filename Model Name Species Citations
3 [pair_style eam, pair_coeff 1 1 /cmmc/ptmp/pyi... [potential_LAMMPS/1986--Foiles-S-M--Ag-Au-Cu-N... NISTiprpy 1986--Foiles-S-M--Ag-Au-Cu-Ni-Pd-Pt--LAMMPS--ipr1 [Ag, Au, Cu, Ni, Pd, Pt] [{'Foiles_1986': {'title': 'Embedded-atom-meth...
21 [pair_style eam, pair_coeff 1 1 /cmmc/ptmp/pyi... [potential_LAMMPS/1989--Adams-J-B--Ag-Au-Cu-Ni... NISTiprpy 1989--Adams-J-B--Ag-Au-Cu-Ni-Pd-Pt--LAMMPS--ipr1 [Ag, Au, Cu, Ni, Pd, Pt] [{'Adams_1989': {'title': 'Self-diffusion and ...
31 [pair_style eam/fs, pair_coeff * * /cmmc/ptmp/... [potential_LAMMPS/1990--Ackland-G-J--Cu-Ag-Au-... NISTiprpy 1990--Ackland-G-J--Cu-Ag-Au--LAMMPS--ipr1 [Cu, Ag, Au] [{'Ackland_1990': {'title': 'Many-body potenti...
94 [pair_style eam/alloy, pair_coeff * * /cmmc/pt... [potential_LAMMPS/2004--Zhou-X-W--Cu-Ag-Au--LA... NISTiprpy 2004--Zhou-X-W--Cu-Ag-Au--LAMMPS--ipr2 [Cu, Ag, Au] [{'Zhou_2004': {'title': 'Misfit-energy-increa...
513 [/cmmc/ptmp/pyironhb/mambaforge/envs//pyiron_m... [] OPENKIM EAM_Dynamo_GolaPastewka_2018_CuAu__MO_42640331... [Cu, Au] [{'Adrien_2018': {'title': 'Embedded atom meth...
594 [/cmmc/ptmp/pyironhb/mambaforge/envs//pyiron_m... [] OPENKIM EAM_Dynamo_ZhouJohnsonWadley_2004NISTretabulat... [Cu, Ag, Au] [{'W._2004': {'title': 'Misfit-energy-increasi...
654 [/cmmc/ptmp/pyironhb/mambaforge/envs//pyiron_m... [] OPENKIM EMT_Asap_Standard_JacobsenStoltzeNorskov_1996_... [Al, Ag, Au, Cu, Ni, Pd, Pt] [{'Jacobsen_1996': {'title': 'A semi-empirical...
905 [/cmmc/ptmp/pyironhb/mambaforge/envs//pyiron_m... [] OPENKIM Sim_ASAP_EMT_Rasmussen_AgAuCu__SM_847706399649... [Ag, Au, Cu] [{'Jacobsen_1996': {'title': 'A semi-empirical...

get_potential_dataframe queries the NIST and OpenKIM interatomic potential databases for LAMMPS potentials compatible with the elements present in structure (Au and Cu), returning their pair_style/pair_coeff configuration alongside metadata such as the model name and citation.

potential = "1990--Ackland-G-J--Cu-Ag-Au--LAMMPS--ipr1"
df_pot[df_pot["Name"] == potential]["Species"].values[0], df_pot[df_pot["Name"] == potential]["Config"].values[0]
(['Cu', 'Ag', 'Au'],
 ['pair_style eam/fs',
  'pair_coeff * * /cmmc/ptmp/pyironhb/mambaforge/envs//pyiron_mpie_cmti_2026-06-17/share/iprpy/potential_LAMMPS/1990--Ackland-G-J--Cu-Ag-Au--LAMMPS--ipr1/CuAgAu.eam.fs Cu Ag Au'])

A specific EAM potential is selected from the results, and its Config entry is extracted — these are the raw LAMMPS pair_style/pair_coeff commands that will be issued to the interactive LAMMPS session below.

LAMMPS_template = """\
thermo {{thermo}}
thermo_style custom step temp pe etotal pxx pxy pxz pyy pyz pzz vol
thermo_modify format float %20.15g
timestep {{timestep}}
velocity all create $({{velocity_rescale_factor}} * {{ temp }}) {{seed}} dist {{dist}}
fix ensemble all nvt temp {{Tstart}} {{Tstop}} {{Tdamp}}
"""

LAMMPS_template is a Jinja2 template for the remaining LAMMPS input commands: thermo output frequency and formatting, the MD timestep, initial velocities drawn from a Gaussian distribution at the target temperature, and an NVT thermostat (fix ensemble).

template = Template(LAMMPS_template)
lmp_str = template.render(
    thermo=100,
    timestep=0.001,
    velocity_rescale_factor=2.0,
    temp=300.0,
    seed=12345,
    dist="gaussian",
    Tstart=300.0,
    Tstop=300.0,
    Tdamp=0.1,
)
lmp_str
'thermo 100\nthermo_style custom step temp pe etotal pxx pxy pxz pyy pyz pzz vol\nthermo_modify format float %20.15g\ntimestep 0.001\nvelocity all create $(2.0 * 300.0) 12345 dist gaussian\nfix ensemble all nvt temp 300.0 300.0 0.1'

Rendering the template with concrete values (100-step thermo output, 1 fs timestep, 300 K target temperature, NVT damping of 0.1) produces lmp_str, the literal block of LAMMPS commands that will be sent to the interactive session one line at a time.

submission_template = """\
#!/bin/bash
#SBATCH --output=time.out
#SBATCH --job-name={{job_name}}
#SBATCH --chdir={{working_directory}}
#SBATCH --get-user-env=L
#SBATCH --partition={{partition}}
{%- if run_time_max %}
#SBATCH --time={{ [1, run_time_max // 60]|max }}
{%- endif %}
{%- if dependency %}
#SBATCH --dependency=afterok:{{ dependency | join(',') }}
{%- endif %}
{%- if memory_max %}
#SBATCH --mem={{memory_max}}G
{%- endif %}
#SBATCH --ntasks={{cores}}

{{command}}
"""

This is the same Jinja2 sbatch submission template used for plain SLURM submission: #SBATCH --ntasks={{cores}} maps executorlib’s cores resource directly onto the number of SLURM tasks (MPI ranks) requested for the job.

SlurmClusterExecutor is created with block_allocation=True, which keeps a persistent pool of worker processes alive in a single SLURM allocation instead of submitting a new job per task, and init_function=init_function, which runs once per worker to set up the MPI communicator that pylammpsmpi needs. pmi_mode="pmix" launches the workers via srun --mpi=pmix across the requested cores=80. LammpsASELibrary(executor=exe, cores=80) then uses executorlib as the parallel backend for pylammpsmpi, so every interactive_* call below is dispatched as an MPI-parallel LAMMPS command inside that persistent allocation rather than spawning a new job. The structure, potential, and thermostat settings assembled above are applied interactively, 100 MD steps are run, and the resulting potential energy is printed before the session is closed. See the SlurmClusterExecutor API reference for the full set of executor options.

with SlurmClusterExecutor( 
    max_workers=1, 
    block_allocation=True,
    resource_dict={
        "submission_template": submission_template, 
        # "run_time_max": 180,  # in seconds  
        "partition": "p.cmfe",
        "cores": 80,
        "threads_per_core": 1,
    },
    init_function=init_function,
    pmi_mode="pmix",
) as exe:
    lmp = LammpsASELibrary(executor=exe, cores=80)
    lmp.interactive_structure_setter(
        structure=structure,
        units="metal",
        dimension=3,
        boundary=" ".join(["p" if coord else "f" for coord in structure.pbc]),
        atom_style="atomic",
        el_eam_lst=df_pot[df_pot["Name"] == potential]["Species"].values[0],
        calc_md=True,
    )
    for c in df_pot[df_pot["Name"] == potential]["Config"].values[0]:
        lmp.interactive_lib_command(c)
    if lmp_str is not None:
        for line in lmp_str.split("\n"):
            lmp.interactive_lib_command(line)

    lmp.interactive_lib_command("run 100")
    print(lmp.interactive_energy_pot_getter())
    lmp.close()
/cmmc/ptmp/pyironhb/mambaforge/envs/pyiron_mpie_cmti_2026-06-17/lib/python3.12/site-packages/executorlib/executor/slurm.py:192: UserWarning: The following keys are not recognized and cannot be validated: ['partition']
  validate_resource_dict_with_optional_keys(resource_dict=resource_dict)
-14956.417260034283