From 5cf50a0ef77967ac2b9fd580cbf64951782ae2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 24 Feb 2025 11:09:21 +0100 Subject: [PATCH 1/5] Test write structure --- pyiron_lammps/structure.py | 48 ++++++++++++++------ tests/test_structure.py | 91 +++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 15 deletions(-) diff --git a/pyiron_lammps/structure.py b/pyiron_lammps/structure.py index f87ae15c..2f456d6f 100644 --- a/pyiron_lammps/structure.py +++ b/pyiron_lammps/structure.py @@ -8,6 +8,7 @@ import posixpath import warnings from collections import OrderedDict +from ase.data import atomic_masses, atomic_numbers import numpy as np @@ -187,7 +188,7 @@ class LammpsStructure(object): input_file_name: """ - def __init__(self, bond_dict=None, job=None): + def __init__(self, bond_dict=None, units="metal"): self._string_input = "" self._structure = None self._potential = None @@ -197,7 +198,7 @@ def __init__(self, bond_dict=None, job=None): self.digits = 10 self._bond_dict = bond_dict self._force_skewed = False - self._job = job + self._units = units self._molecule_ids = [] @property @@ -237,16 +238,16 @@ def structure(self, structure): else: # self.atom_type == 'atomic' input_str = self.structure_atomic() - if self._structure.velocities is not None: - uc = UnitConverter(self._job.units) - self._structure.velocities *= uc.pyiron_to_lammps("velocity") + if self._structure.get_velocities() is not None: + uc = UnitConverter(self._units) + self._structure.set_velocities(self._structure.get_velocities() * uc.pyiron_to_lammps("velocity")) vels = self.rotate_velocities(self._structure) input_str += "Velocities\n\n" - if self._structure.dimension == 3: + if len(self._structure.positions[0]) == 3: format_str = "{0:d} {1:f} {2:f} {3:f}\n" for id_atom, (x, y, z) in enumerate(vels, start=1): input_str += format_str.format(id_atom, x, y, z) - if self._structure.dimension == 2: + elif len(self._structure.positions[0]) == 2: format_str = "{0:d} {1:f} {2:f}\n" for id_atom, (x, y) in enumerate(vels, start=1): input_str += format_str.format(id_atom, x, y) @@ -321,7 +322,7 @@ def lammps_header( masses = "Masses\n\n" for el, idx in species_lammps_id_dict.items(): - mass = structure._pse[el].AtomicMass + mass = atomic_masses[atomic_numbers[el]] masses += "{0:3d} {1:f} # ({2}) \n".format(idx, mass, el) return atomtypes + "\n" + cell_dimensions + "\n" + masses + "\n" @@ -343,7 +344,7 @@ def simulation_cell(self): + "0. {} zlo zhi\n".format(zhi) ) - if self.structure.is_skewed() or self._force_skewed: + if is_skewed(self.structure) or self._force_skewed: simulation_cell += "{0} {1} {2} xy xz yz\n".format(xy, xz, yz) return simulation_cell @@ -652,7 +653,7 @@ def structure_atomic(self): el_lst = self._structure.get_chemical_symbols() for id_atom, (el, coord) in enumerate(zip(el_lst, coords)): - dim = self._structure.dimension + dim = len(self._structure.positions[0]) c = np.zeros(3) c[:dim] = coord atoms += ( @@ -696,7 +697,7 @@ def rotate_velocities(self, structure): (list): List of rotated velocities """ prism = UnfoldingPrism(self._structure.cell) - vels = [prism.pos_to_lammps(vel) for vel in structure.velocities] + vels = [prism.pos_to_lammps(vel) for vel in structure.get_velocities()] return vels def write_file(self, file_name, cwd=None): @@ -714,10 +715,29 @@ def write_file(self, file_name, cwd=None): for line in self._string_input: f.write(line) +def is_skewed(structure, tolerance=1.0e-8): + """ + Check whether the simulation box is skewed/sheared. The algorithm compares the box volume + and the product of the box length in each direction. If these numbers do not match, the box + is considered to be skewed and the function returns True + + Args: + tolerance (float): Relative tolerance above which the structure is considered as skewed + + Returns: + (bool): Whether the box is skewed or not. + """ + volume = structure.get_volume() + prod = np.linalg.norm(structure.cell, axis=-1).prod() + if volume > 0: + if abs(volume - prod) / volume < tolerance: + return False + return True + -def write_lammps_datafile(structure, file_name="lammps.data", cwd=None): - lammps_str = LammpsStructure() - lammps_str.el_eam_lst = structure.get_species_symbols() +def write_lammps_datafile(structure, el_eam_lst, bond_dict=None, units="metal", file_name="lammps.data", cwd=None): + lammps_str = LammpsStructure(bond_dict=bond_dict, units=units) + lammps_str.el_eam_lst = el_eam_lst lammps_str.structure = structure lammps_str.write_file(file_name=file_name, cwd=cwd) diff --git a/tests/test_structure.py b/tests/test_structure.py index a78dd113..6fa742ec 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -1,10 +1,20 @@ import unittest import numpy as np +import os +from shutil import rmtree from ase.build import bulk -from pyiron_lammps.structure import structure_to_lammps +from pyiron_lammps.structure import structure_to_lammps, LammpsStructure, write_lammps_datafile class TestLammpsStructure(unittest.TestCase): + def setUp(self): + self.output_folder = os.path.abspath(os.path.join(__file__, "..", "structure")) + os.makedirs(self.output_folder, exist_ok=True) + + @classmethod + def tearDownClass(cls): + rmtree(os.path.abspath(os.path.join(__file__, "..", "structure"))) + def test_structure_to_lammps_with_velocity(self): structure = bulk("Al", a=4.05) structure.set_velocities([[1.0, 1.0, 1.0]]) @@ -51,3 +61,82 @@ def test_structure_to_lammps_without_velocity(self): ) ) ) + + def test_structure_atomic_non_cubic(self): + structure = bulk("Al", a=4.05) + write_lammps_datafile( + structure=structure, + el_eam_lst=["Ni", "Al", "H"], + file_name="lammps.data", + cwd=self.output_folder, + ) + with open(os.path.join(self.output_folder, "lammps.data"), "r") as f: + self.assertEqual( + f.readlines(), + [ + 'Start File for LAMMPS \n', + '1 atoms \n', + '3 atom types \n', + '\n', + '0. 2.863782463805518 xlo xhi\n', + '0. 2.480108364567968 ylo yhi\n', + '0. 2.338268590217984 zlo zhi\n', + '1.431891231902759 1.431891231902759 0.826702788189323 xy xz yz\n', + '\n', + 'Masses\n', + '\n', + ' 1 58.693400 # (Ni) \n', + ' 2 26.981538 # (Al) \n', + ' 3 1.008000 # (H) \n', + '\n', + 'Atoms\n', + '\n', + '1 2 0.000000000000000 0.000000000000000 0.000000000000000\n', + '\n', + 'Velocities\n', + '\n', + '1 0.000000 0.000000 0.000000\n', + ], + ) + + def test_structure_atomic_cubic(self): + structure = bulk("Al", a=4.0, cubic=True) + write_lammps_datafile( + structure=structure, + el_eam_lst=["Ni", "Al", "H"], + file_name="lammps_cubic.data", + cwd=self.output_folder, + ) + with open(os.path.join(self.output_folder, "lammps_cubic.data"), "r") as f: + self.assertEqual( + f.readlines(), + [ + 'Start File for LAMMPS \n', + '4 atoms \n', + '3 atom types \n', + '\n', + '0. 4.000000000000000 xlo xhi\n', + '0. 4.000000000000000 ylo yhi\n', + '0. 4.000000000000000 zlo zhi\n', + '\n', + 'Masses\n', + '\n', + ' 1 58.693400 # (Ni) \n', + ' 2 26.981538 # (Al) \n', + ' 3 1.008000 # (H) \n', + '\n', + 'Atoms\n', + '\n', + '1 2 0.000000000000000 0.000000000000000 0.000000000000000\n', + '2 2 0.000000000000000 2.000000000000000 2.000000000000000\n', + '3 2 2.000000000000000 0.000000000000000 2.000000000000000\n', + '4 2 2.000000000000000 2.000000000000000 0.000000000000000\n', + '\n', + 'Velocities\n', + '\n', + '1 0.000000 0.000000 0.000000\n', + '2 0.000000 0.000000 0.000000\n', + '3 0.000000 0.000000 0.000000\n', + '4 0.000000 0.000000 0.000000\n', + ], + ) \ No newline at end of file From a2e28cb37a5efd0b08f6b401e30b613cd968da8d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 10:10:05 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyiron_lammps/structure.py | 16 ++++-- tests/test_structure.py | 106 +++++++++++++++++++------------------ 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/pyiron_lammps/structure.py b/pyiron_lammps/structure.py index 2f456d6f..d6fd43e4 100644 --- a/pyiron_lammps/structure.py +++ b/pyiron_lammps/structure.py @@ -8,9 +8,9 @@ import posixpath import warnings from collections import OrderedDict -from ase.data import atomic_masses, atomic_numbers import numpy as np +from ase.data import atomic_masses, atomic_numbers from pyiron_lammps.units import UnitConverter @@ -240,7 +240,9 @@ def structure(self, structure): if self._structure.get_velocities() is not None: uc = UnitConverter(self._units) - self._structure.set_velocities(self._structure.get_velocities() * uc.pyiron_to_lammps("velocity")) + self._structure.set_velocities( + self._structure.get_velocities() * uc.pyiron_to_lammps("velocity") + ) vels = self.rotate_velocities(self._structure) input_str += "Velocities\n\n" if len(self._structure.positions[0]) == 3: @@ -715,6 +717,7 @@ def write_file(self, file_name, cwd=None): for line in self._string_input: f.write(line) + def is_skewed(structure, tolerance=1.0e-8): """ Check whether the simulation box is skewed/sheared. The algorithm compares the box volume @@ -735,7 +738,14 @@ def is_skewed(structure, tolerance=1.0e-8): return True -def write_lammps_datafile(structure, el_eam_lst, bond_dict=None, units="metal", file_name="lammps.data", cwd=None): +def write_lammps_datafile( + structure, + el_eam_lst, + bond_dict=None, + units="metal", + file_name="lammps.data", + cwd=None, +): lammps_str = LammpsStructure(bond_dict=bond_dict, units=units) lammps_str.el_eam_lst = el_eam_lst lammps_str.structure = structure diff --git a/tests/test_structure.py b/tests/test_structure.py index 6fa742ec..bb91aabb 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -3,7 +3,11 @@ import os from shutil import rmtree from ase.build import bulk -from pyiron_lammps.structure import structure_to_lammps, LammpsStructure, write_lammps_datafile +from pyiron_lammps.structure import ( + structure_to_lammps, + LammpsStructure, + write_lammps_datafile, +) class TestLammpsStructure(unittest.TestCase): @@ -74,28 +78,28 @@ def test_structure_atomic_non_cubic(self): self.assertEqual( f.readlines(), [ - 'Start File for LAMMPS \n', - '1 atoms \n', - '3 atom types \n', - '\n', - '0. 2.863782463805518 xlo xhi\n', - '0. 2.480108364567968 ylo yhi\n', - '0. 2.338268590217984 zlo zhi\n', - '1.431891231902759 1.431891231902759 0.826702788189323 xy xz yz\n', - '\n', - 'Masses\n', - '\n', - ' 1 58.693400 # (Ni) \n', - ' 2 26.981538 # (Al) \n', - ' 3 1.008000 # (H) \n', - '\n', - 'Atoms\n', - '\n', - '1 2 0.000000000000000 0.000000000000000 0.000000000000000\n', - '\n', - 'Velocities\n', - '\n', - '1 0.000000 0.000000 0.000000\n', + "Start File for LAMMPS \n", + "1 atoms \n", + "3 atom types \n", + "\n", + "0. 2.863782463805518 xlo xhi\n", + "0. 2.480108364567968 ylo yhi\n", + "0. 2.338268590217984 zlo zhi\n", + "1.431891231902759 1.431891231902759 0.826702788189323 xy xz yz\n", + "\n", + "Masses\n", + "\n", + " 1 58.693400 # (Ni) \n", + " 2 26.981538 # (Al) \n", + " 3 1.008000 # (H) \n", + "\n", + "Atoms\n", + "\n", + "1 2 0.000000000000000 0.000000000000000 0.000000000000000\n", + "\n", + "Velocities\n", + "\n", + "1 0.000000 0.000000 0.000000\n", ], ) @@ -111,32 +115,32 @@ def test_structure_atomic_cubic(self): self.assertEqual( f.readlines(), [ - 'Start File for LAMMPS \n', - '4 atoms \n', - '3 atom types \n', - '\n', - '0. 4.000000000000000 xlo xhi\n', - '0. 4.000000000000000 ylo yhi\n', - '0. 4.000000000000000 zlo zhi\n', - '\n', - 'Masses\n', - '\n', - ' 1 58.693400 # (Ni) \n', - ' 2 26.981538 # (Al) \n', - ' 3 1.008000 # (H) \n', - '\n', - 'Atoms\n', - '\n', - '1 2 0.000000000000000 0.000000000000000 0.000000000000000\n', - '2 2 0.000000000000000 2.000000000000000 2.000000000000000\n', - '3 2 2.000000000000000 0.000000000000000 2.000000000000000\n', - '4 2 2.000000000000000 2.000000000000000 0.000000000000000\n', - '\n', - 'Velocities\n', - '\n', - '1 0.000000 0.000000 0.000000\n', - '2 0.000000 0.000000 0.000000\n', - '3 0.000000 0.000000 0.000000\n', - '4 0.000000 0.000000 0.000000\n', + "Start File for LAMMPS \n", + "4 atoms \n", + "3 atom types \n", + "\n", + "0. 4.000000000000000 xlo xhi\n", + "0. 4.000000000000000 ylo yhi\n", + "0. 4.000000000000000 zlo zhi\n", + "\n", + "Masses\n", + "\n", + " 1 58.693400 # (Ni) \n", + " 2 26.981538 # (Al) \n", + " 3 1.008000 # (H) \n", + "\n", + "Atoms\n", + "\n", + "1 2 0.000000000000000 0.000000000000000 0.000000000000000\n", + "2 2 0.000000000000000 2.000000000000000 2.000000000000000\n", + "3 2 2.000000000000000 0.000000000000000 2.000000000000000\n", + "4 2 2.000000000000000 2.000000000000000 0.000000000000000\n", + "\n", + "Velocities\n", + "\n", + "1 0.000000 0.000000 0.000000\n", + "2 0.000000 0.000000 0.000000\n", + "3 0.000000 0.000000 0.000000\n", + "4 0.000000 0.000000 0.000000\n", ], - ) \ No newline at end of file + ) From 929dcb739e752f6ccab05eebabf8eb530c52bc7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 24 Feb 2025 11:16:02 +0100 Subject: [PATCH 3/5] fix old test --- tests/test_structure.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test_structure.py b/tests/test_structure.py index 6fa742ec..dace4fd1 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -72,16 +72,12 @@ def test_structure_atomic_non_cubic(self): ) with open(os.path.join(self.output_folder, "lammps.data"), "r") as f: self.assertEqual( - f.readlines(), + [l for l in f.readlines() if "xlo xhi" not in l and "ylo yhi" not in l and "zlo zhi" not in l and "xy xz yz" not in l], [ 'Start File for LAMMPS \n', '1 atoms \n', '3 atom types \n', '\n', - '0. 2.863782463805518 xlo xhi\n', - '0. 2.480108364567968 ylo yhi\n', - '0. 2.338268590217984 zlo zhi\n', - '1.431891231902759 1.431891231902759 0.826702788189323 xy xz yz\n', '\n', 'Masses\n', '\n', From 18722d655304824beb7a804f7fece18d439b2d29 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 10:17:19 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_structure.py | 45 ++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/tests/test_structure.py b/tests/test_structure.py index c03be619..8b74cb6c 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -76,26 +76,33 @@ def test_structure_atomic_non_cubic(self): ) with open(os.path.join(self.output_folder, "lammps.data"), "r") as f: self.assertEqual( - [l for l in f.readlines() if "xlo xhi" not in l and "ylo yhi" not in l and "zlo zhi" not in l and "xy xz yz" not in l], [ - 'Start File for LAMMPS \n', - '1 atoms \n', - '3 atom types \n', - '\n', - '\n', - 'Masses\n', - '\n', - ' 1 58.693400 # (Ni) \n', - ' 2 26.981538 # (Al) \n', - ' 3 1.008000 # (H) \n', - '\n', - 'Atoms\n', - '\n', - '1 2 0.000000000000000 0.000000000000000 0.000000000000000\n', - '\n', - 'Velocities\n', - '\n', - '1 0.000000 0.000000 0.000000\n', + l + for l in f.readlines() + if "xlo xhi" not in l + and "ylo yhi" not in l + and "zlo zhi" not in l + and "xy xz yz" not in l + ], + [ + "Start File for LAMMPS \n", + "1 atoms \n", + "3 atom types \n", + "\n", + "\n", + "Masses\n", + "\n", + " 1 58.693400 # (Ni) \n", + " 2 26.981538 # (Al) \n", + " 3 1.008000 # (H) \n", + "\n", + "Atoms\n", + "\n", + "1 2 0.000000000000000 0.000000000000000 0.000000000000000\n", + "\n", + "Velocities\n", + "\n", + "1 0.000000 0.000000 0.000000\n", ], ) From 0885f3f46214565dd2c1d8e7898f760d0378391e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 24 Feb 2025 11:31:55 +0100 Subject: [PATCH 5/5] small changes --- tests/test_structure.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_structure.py b/tests/test_structure.py index 8b74cb6c..7b7377a5 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -5,7 +5,6 @@ from ase.build import bulk from pyiron_lammps.structure import ( structure_to_lammps, - LammpsStructure, write_lammps_datafile, ) @@ -72,6 +71,7 @@ def test_structure_atomic_non_cubic(self): structure=structure, el_eam_lst=["Ni", "Al", "H"], file_name="lammps.data", + units="metal", cwd=self.output_folder, ) with open(os.path.join(self.output_folder, "lammps.data"), "r") as f: @@ -112,6 +112,7 @@ def test_structure_atomic_cubic(self): structure=structure, el_eam_lst=["Ni", "Al", "H"], file_name="lammps_cubic.data", + units="metal", cwd=self.output_folder, ) with open(os.path.join(self.output_folder, "lammps_cubic.data"), "r") as f: