Skip to main content

Available models

All integrated pretrained potentials are registered in MLIPEnum. After installation you can inspect which models were loaded successfully:
from mlip_arena.models import MLIPEnum

print(list(MLIPEnum.__members__.keys()))
# e.g. ['MACE-MP(M)', 'CHGNet', 'M3GNet', 'MatterSim', 'ORBv2', 'SevenNet',
#        'eqV2(OMat)', 'MACE-MPA', 'eSEN', 'MACE-OFF(M)', 'ANI2x', 'ALIGNN',
#        'DeepMD', 'ORB', ...]

Run a single model

The helper get_calculator constructs an ASE-compatible calculator for any entry in MLIPEnum, with optional D3 dispersion correction via torch_dftd.
from ase.build import bulk
from ase import units

from mlip_arena.models import MLIPEnum
from mlip_arena.tasks import MD
from mlip_arena.tasks.utils import get_calculator

atoms = bulk("Cu", "fcc", a=3.6) * (5, 5, 5)

result = MD(
    atoms=atoms,
    calculator=get_calculator(
        MLIPEnum["MACE-MP(M)"],
        calculator_kwargs={},
        dispersion=True,
        dispersion_kwargs={
            "damping": "bj",
            "xc": "pbe",
            "cutoff": 40.0 * units.Bohr,
        },
    ),
    ensemble="nvt",          # "nve", "nvt", or "npt"
    dynamics="langevin",      # any ASE Dynamics class name
    total_time=1e3,           # ps — 1 ps = 1e3 fs
    time_step=2,              # fs
)
get_calculator also accepts a raw ASE Calculator instance or a class, so you are not limited to models registered in MLIPEnum.

Loop over all models

Iterate over MLIPEnum to run the same task against every installed model:
from mlip_arena.models import MLIPEnum
from mlip_arena.tasks import MD
from mlip_arena.tasks.utils import get_calculator
from ase.build import bulk

atoms = bulk("Cu", "fcc", a=3.6) * (5, 5, 5)

results = []
for model in MLIPEnum:
    result = MD(
        atoms=atoms,
        calculator=get_calculator(model, calculator_kwargs={}),
        ensemble="nvt",
        dynamics="langevin",
        total_time=1e3,
        time_step=2,
    )
    results.append(result)

Parallelize with Prefect

All tasks in MLIP Arena are decorated with @prefect.task. Call .submit() instead of a direct invocation and wrap everything in a @flow to dispatch tasks concurrently to Prefect workers.
from prefect import flow
from ase.build import bulk
from mlip_arena.models import MLIPEnum
from mlip_arena.tasks import MD
from mlip_arena.tasks.utils import get_calculator

atoms = bulk("Cu", "fcc", a=3.6) * (5, 5, 5)

@flow
def benchmark_all_models():
    futures = []
    for model in MLIPEnum:
        future = MD.submit(
            atoms=atoms,
            calculator=get_calculator(model, calculator_kwargs={}),
            ensemble="nvt",
            dynamics="langevin",
            total_time=1e3,
            time_step=2,
        )
        futures.append(future)

    return [f.result(raise_on_failure=False) for f in futures]

if __name__ == "__main__":
    results = benchmark_all_models()
For HPC usage see the MD stability benchmark notebook for an end-to-end Prefect + Dask example on a SLURM cluster.

Available tasks

All tasks live under mlip_arena.tasks and are importable directly:
from mlip_arena.tasks import OPT, EOS, MD, PHONON, NEB, NEB_FROM_ENDPOINTS, ELASTICITY
PHONON requires phonopy to be installed. If phonopy is missing the wildcard import from mlip_arena.tasks import * will log a warning but the other tasks will still load.

OPT — Structure optimization

Relax atomic positions and/or unit cell using any ASE Optimizer and Filter:
from ase.build import bulk
from mlip_arena.tasks import OPT
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum

atoms = bulk("Fe", "bcc", a=2.87)

result = OPT(
    atoms=atoms,
    calculator=get_calculator(MLIPEnum["MACE-MP(M)"], calculator_kwargs={}),
    optimizer="BFGSLineSearch",  # any ASE Optimizer name
    filter="FrechetCell",        # relax cell shape and volume
    criterion={"fmax": 0.01},    # convergence threshold in eV/Å
)
# result["atoms"] — relaxed Atoms; result["converged"] — bool; result["steps"] — int

EOS — Equation of state

Compute the energy–volume curve and fit a Birch–Murnaghan EOS to extract bulk modulus and equilibrium volume:
from ase.build import bulk
from mlip_arena.tasks import EOS
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum

atoms = bulk("Si", "diamond", a=5.43)

result = EOS(
    atoms=atoms,
    calculator=get_calculator(MLIPEnum["CHGNet"], calculator_kwargs={}),
    max_abs_strain=0.1,  # ±10 % volume range
    npoints=11,          # number of EV sample points
)
# result["K"] — bulk modulus (GPa); result["v0"] — eq. volume (ų); result["e0"] — eq. energy (eV)

MD — Molecular dynamics

Flexible NVE / NVT / NPT simulation with temperature and pressure scheduling:
from ase.build import bulk
from mlip_arena.tasks import MD
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum

atoms = bulk("Cu", "fcc", a=3.6) * (4, 4, 4)

result = MD(
    atoms=atoms,
    calculator=get_calculator(MLIPEnum["MACE-MP(M)"], calculator_kwargs={}),
    ensemble="nvt",
    dynamics="langevin",
    total_time=10_000,  # fs — 10 ps
    time_step=2,        # fs
    temperature=600,    # K  (scalar or array for annealing)
    traj_file="cu_nvt.traj",
    traj_interval=10,
)
# result["atoms"], result["n_steps"], result["runtime"]

PHONON — Phonon calculation

Finite-displacement phonon calculation powered by phonopy:
from ase.build import bulk
from mlip_arena.tasks import PHONON
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum

atoms = bulk("Al", "fcc", a=4.05)

result = PHONON(
    atoms=atoms,
    calculator=get_calculator(MLIPEnum["M3GNet"], calculator_kwargs={}),
    supercell_matrix=[2, 2, 2],
    t_min=0,
    t_max=1000,
    t_step=10,
)
# result["phonon"]  — a phonopy.Phonopy object

NEB — Nudged elastic band

Minimum energy path calculation from a list of pre-built images:
from ase.build import bulk, make_supercell
from mlip_arena.tasks import NEB
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum

# Provide start, intermediate (empty), and end images
images = [initial_atoms] + [initial_atoms.copy() for _ in range(5)] + [final_atoms]

result = NEB(
    images=images,
    calculator=get_calculator(MLIPEnum["SevenNet"], calculator_kwargs={}),
    optimizer="MDMin",
    climb=True,           # climbing-image NEB
    interpolation="idpp", # or "linear"
    criterion={"fmax": 0.05},
)
# result["barrier"], result["images"], result["forcefit"]

NEB_FROM_ENDPOINTS — NEB with automatic interpolation

Convenience wrapper that handles image interpolation from just two endpoint structures:
from mlip_arena.tasks import NEB_FROM_ENDPOINTS
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum

result = NEB_FROM_ENDPOINTS(
    start=initial_atoms,
    end=final_atoms,
    n_images=7,
    calculator=get_calculator(MLIPEnum["SevenNet"], calculator_kwargs={}),
    relax_end_points=True,  # relax start/end before NEB
    interpolation="idpp",
    climb=True,
    criterion={"fmax": 0.05},
)

ELASTICITY — Elastic tensor

Compute the full elastic tensor by applying symmetry-adapted normal and shear strains:
from ase.build import bulk
from mlip_arena.tasks import ELASTICITY
from mlip_arena.tasks.utils import get_calculator
from mlip_arena.models import MLIPEnum
import numpy as np

atoms = bulk("W", "bcc", a=3.16)

result = ELASTICITY(
    atoms=atoms,
    calculator=get_calculator(MLIPEnum["MACE-MP(M)"], calculator_kwargs={}),
    filter="FrechetCell",
    normal_strains=np.linspace(-0.01, 0.01, 4),
    shear_strains=np.linspace(-0.06, 0.06, 4),
)
# result contains the elastic tensor and derived moduli

Next steps

Benchmarks

View live benchmark results on the MLIP Arena leaderboard.

Contributing models

Add your own pretrained potential as an external ASE calculator or a HuggingFace model.

Prefect docs

Learn how to write Prefect tasks and flows to orchestrate large-scale benchmarks.

GitHub

Source code, issue tracker, and contribution guidelines.