"""Run a short NVT molecular-dynamics trajectory with eSEN.""" from __future__ import annotations import argparse import os os.environ.setdefault( "ONESCIENCE_ESEN_JD_PATH", os.path.join(os.path.dirname(__file__), "weight", "Jd.pt"), ) import numpy as np from ase import units from ase.build import bulk from ase.io import read from ase.io.trajectory import Trajectory from ase.md.langevin import Langevin from ase.md.velocitydistribution import MaxwellBoltzmannDistribution, Stationary from onescience.utils.esen import eSENCalculator def default_checkpoint() -> str: return os.path.join(os.path.dirname(__file__), "weight", "esen_30m_mptrj.pt") def load_structure(path: str | None, repeat: tuple[int, int, int] | None): if path: atoms = read(path) else: atoms = bulk("Si", "diamond", a=5.43).repeat((2, 2, 2)) return atoms.repeat(repeat) if repeat else atoms def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--checkpoint", default=default_checkpoint()) parser.add_argument("--input", help="CIF, POSCAR, XYZ, or another ASE-readable structure") parser.add_argument( "--repeat", type=int, nargs=3, metavar=("NX", "NY", "NZ"), help="repeat the input structure along its three cell vectors", ) parser.add_argument("--steps", type=int, default=10) parser.add_argument("--temperature", type=float, default=300.0) parser.add_argument("--timestep", type=float, default=1.0, help="time step in fs") parser.add_argument( "--friction", type=float, default=0.01, help="Langevin friction in 1/fs" ) parser.add_argument("--seed", type=int, default=0) parser.add_argument("--output", default="md.traj") parser.add_argument("--device", default="cuda") args = parser.parse_args() repeat = tuple(args.repeat) if args.repeat else None atoms = load_structure(args.input, repeat) atoms.calc = eSENCalculator.from_checkpoint(args.checkpoint, device=args.device) rng = np.random.default_rng(args.seed) MaxwellBoltzmannDistribution(atoms, temperature_K=args.temperature, rng=rng) Stationary(atoms) dynamics = Langevin( atoms, timestep=args.timestep * units.fs, temperature_K=args.temperature, friction=args.friction / units.fs, ) trajectory = Trajectory(args.output, "w", atoms) dynamics.attach(trajectory.write, interval=1) dynamics.run(args.steps) trajectory.close() print("formula:", atoms.get_chemical_formula()) print("atoms:", len(atoms)) print("steps:", dynamics.nsteps) print("energy (eV):", atoms.get_potential_energy()) if __name__ == "__main__": main()