From 5321f7d26c6c6ebfd63470ea380c94152b7d135b Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Wed, 5 Jun 2024 16:35:42 +0200 Subject: [PATCH 1/4] Implement lammps reader --- src/gemdat/trajectory.py | 90 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/src/gemdat/trajectory.py b/src/gemdat/trajectory.py index 181edf7f..49b9a4ae 100644 --- a/src/gemdat/trajectory.py +++ b/src/gemdat/trajectory.py @@ -12,7 +12,7 @@ from typing import TYPE_CHECKING, Collection, Optional import numpy as np -from pymatgen.core import Lattice +from pymatgen.core import Element, Lattice from pymatgen.core.trajectory import Trajectory as PymatgenTrajectory from pymatgen.io import vasp @@ -249,6 +249,94 @@ def from_vasprun( return obj + @classmethod + def from_lammps( + cls, + *, + coords_file: Path | str, + box_file: Path | str, + temperature: float, + time_step: float, + coords_format: str = 'xyz', + atom_style: str = 'atomic', + cache: Optional[str | Path] = None, + constant_lattice: bool = True, + ) -> Trajectory: + """Load data from LAMMPS. + + Parameters + ---------- + coords_file : ... + LAMMPS coords file with trajectory data + box_file : ... + LAMMPS data format, contains the lattice + temperature : float + Temperature of simulation in K + time_step : float + Time step of the simulation in fs + coords_format: str + Format of the coords file + atom_style : str + Atom style for box file + cache : Optional[Path], optional + Path to cache data for vasprun.xml + constant_lattice : bool + Whether the lattice changes during the simulation, + such as in an NPT MD simulation. + + Returns + ------- + trajectory : Trajectory + Output trajectory + """ + from MDAnalysis import Universe + from pymatgen.io.lammps.data import LammpsData + + if not cache: + kwargs = { + 'coords_file': coords_file, + 'box_file': box_file, + 'temperature': temperature, + 'time_step': time_step, + } + serialized = json.dumps(kwargs, sort_keys=True).encode() + hashid = hashlib.sha1(serialized).hexdigest()[:8] + cache = Path(coords_file).with_suffix(f'.{coords_format}.{hashid}.cache') + + if Path(cache).exists(): + try: + return cls.from_cache(cache) + except Exception as e: + print(e) + print(f'Error reading from cache, reading {coords_file!r}') + + if not constant_lattice: + raise NotImplementedError('Lammps reader does not support NPT simulations') + + lammps_data = LammpsData.from_file(filename=box_file, atom_style=atom_style) + lattice = lammps_data.structure.lattice + + utraj = Universe(coords_file, format=coords_format) + coords = utraj.trajectory.timeseries() + coords = lattice.get_fractional_coords(coords) + + species = [Element(sp) for sp in utraj.atoms.elements] + + obj = cls( + species=species, + coords=coords, + lattice=lattice, + time_step=time_step, + constant_lattice=constant_lattice, + metadata={'temperature': temperature}, + ) + obj.to_positions() + + if cache: + obj.to_cache(cache) + + return obj + def get_lattice(self, idx: int | None = None) -> Lattice: """Get lattice. From c26d605294ecedb64a7b0a54421497d39fcd7a92 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Wed, 5 Jun 2024 16:50:10 +0200 Subject: [PATCH 2/4] Add tests --- docs/notebooks | 2 +- src/gemdat/trajectory.py | 3 +++ tests/data | 2 +- tests/trajectory_test.py | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/notebooks b/docs/notebooks index 933d0c35..d2e03e51 160000 --- a/docs/notebooks +++ b/docs/notebooks @@ -1 +1 @@ -Subproject commit 933d0c353f08bc53e1cc404a47436c56fb91c820 +Subproject commit d2e03e51c861d7df9bf5d1622ae2a7bc5938264a diff --git a/src/gemdat/trajectory.py b/src/gemdat/trajectory.py index 49b9a4ae..2d244161 100644 --- a/src/gemdat/trajectory.py +++ b/src/gemdat/trajectory.py @@ -292,6 +292,9 @@ def from_lammps( from MDAnalysis import Universe from pymatgen.io.lammps.data import LammpsData + coords_file = str(coords_file) + box_file = str(box_file) + if not cache: kwargs = { 'coords_file': coords_file, diff --git a/tests/data b/tests/data index f8443540..9b1f3372 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit f8443540c65e87e251d1dda435c001247262d011 +Subproject commit 9b1f3372aec61a42689bdcbb5d1ce30bd9d5585a diff --git a/tests/trajectory_test.py b/tests/trajectory_test.py index dc4b8e42..4c4f12d3 100644 --- a/tests/trajectory_test.py +++ b/tests/trajectory_test.py @@ -158,3 +158,19 @@ def test_mean_squared_displacement(trajectory): assert_allclose(msd[0], [0.0, 0.0525, 0.19, 0.425, 0.81]) assert isinstance(msd, np.ndarray) assert_allclose(msd.mean(), 0.073875) + + +def test_from_lammps(): + from pathlib import Path + + data_dir = Path(__file__).parent / 'data' / 'lammps' + + traj = Trajectory.from_lammps( + coords_file=data_dir / 'lammps_coords.xyz', + box_file=data_dir / 'lammps_data.txt', + temperature=700, + time_step=2, + ) + + assert traj.positions.shape == (4, 80, 3) + assert len(traj.species) == 80 From 28aecdd82f03227855ffea5acd458e027c350b57 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Wed, 5 Jun 2024 16:53:37 +0200 Subject: [PATCH 3/4] Rename box_file to data_file --- src/gemdat/trajectory.py | 12 ++++++------ tests/trajectory_test.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gemdat/trajectory.py b/src/gemdat/trajectory.py index 2d244161..88344214 100644 --- a/src/gemdat/trajectory.py +++ b/src/gemdat/trajectory.py @@ -254,7 +254,7 @@ def from_lammps( cls, *, coords_file: Path | str, - box_file: Path | str, + data_file: Path | str, temperature: float, time_step: float, coords_format: str = 'xyz', @@ -268,8 +268,8 @@ def from_lammps( ---------- coords_file : ... LAMMPS coords file with trajectory data - box_file : ... - LAMMPS data format, contains the lattice + data_file : ... + LAMMPS data file with the lattice temperature : float Temperature of simulation in K time_step : float @@ -293,12 +293,12 @@ def from_lammps( from pymatgen.io.lammps.data import LammpsData coords_file = str(coords_file) - box_file = str(box_file) + data_file = str(data_file) if not cache: kwargs = { 'coords_file': coords_file, - 'box_file': box_file, + 'data_file': data_file, 'temperature': temperature, 'time_step': time_step, } @@ -316,7 +316,7 @@ def from_lammps( if not constant_lattice: raise NotImplementedError('Lammps reader does not support NPT simulations') - lammps_data = LammpsData.from_file(filename=box_file, atom_style=atom_style) + lammps_data = LammpsData.from_file(filename=data_file, atom_style=atom_style) lattice = lammps_data.structure.lattice utraj = Universe(coords_file, format=coords_format) diff --git a/tests/trajectory_test.py b/tests/trajectory_test.py index 4c4f12d3..a34fccec 100644 --- a/tests/trajectory_test.py +++ b/tests/trajectory_test.py @@ -167,7 +167,7 @@ def test_from_lammps(): traj = Trajectory.from_lammps( coords_file=data_dir / 'lammps_coords.xyz', - box_file=data_dir / 'lammps_data.txt', + data_file=data_dir / 'lammps_data.txt', temperature=700, time_step=2, ) From c14d6bc35ad644a2eec2265cad386345b3ee6a40 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Wed, 5 Jun 2024 16:54:26 +0200 Subject: [PATCH 4/4] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 003de4f0..ae688c62 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Gemdat is a Python library for the analysis of diffusion in solid-state electrol With Gemdat, you can: - Explore your MD simulation via an easy-to-use Python API -- Load and analyze trajectories from VASP simulation data +- Load and analyze trajectories from VASP and LAMMPS simulation data - Find jumps and transitions between sites - Effortlessly calculate tracer and jump diffusivity - Characterize and visualize diffusion pathways