Run Molecular Dynamics with ASE#

Any trained xnn model can drive ASE through XNNCalculator (requires the ase extra installed).

Attach the calculator#

import torch
from ase.io import read
from xnn.common.deploy import XNNCalculator
from xnn.common.models import build_model

ckpt = torch.load("runs/argon_mace/best.pt", weights_only=False)
model = build_model(ckpt["cfg"].model)
model.load_state_dict(ckpt["model"])

atoms = read("liquid_argon.xyz")
atoms.calc = XNNCalculator(model, cutoff=ckpt["cfg"].model.cutoff)

print(atoms.get_potential_energy(), atoms.get_forces().shape)

The calculator handles molecular and periodic cells alike: it builds the same PBC-aware neighbor list used in training, so energies, forces, and stresses are consistent with the training setup.

Run NPT dynamics#

With the calculator attached, the model works in any ASE dynamics driver. For example, liquid-argon NPT (the workflow of the *_argon_density_md.ipynb example notebooks):

from ase import units
from ase.md.npt import NPT
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution

MaxwellBoltzmannDistribution(atoms, temperature_K=94.4)

dyn = NPT(
    atoms,
    timestep=2.0 * units.fs,
    temperature_K=94.4,
    externalstress=1.0 * units.bar,
    ttime=25 * units.fs,
    pfactor=(75 * units.fs) ** 2 * units.GPa,
)
dyn.run(10_000)

Tip

The notebooks examples/gnn/{mace,nequip,allegro}/*_argon_density_md.ipynb run this exact pipeline with both xnn and the corresponding reference implementation and compare the resulting mass densities; with identical weights the difference is essentially zero.