From 3b162cef4708458e0421653dfade2b59a9d7b813 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 15 Nov 2021 13:42:38 +0100 Subject: [PATCH 01/19] Use paths based off file location and inherit from our testing class --- tests/atomistics/job/test_atomistic.py | 36 +++++++++++--------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/tests/atomistics/job/test_atomistic.py b/tests/atomistics/job/test_atomistic.py index 084123db7..67b38a54f 100644 --- a/tests/atomistics/job/test_atomistic.py +++ b/tests/atomistics/job/test_atomistic.py @@ -6,34 +6,31 @@ import numpy as np import os import shutil -from pyiron_atomistics.project import Project +from pathlib import Path from pyiron_base import ProjectHDFio +from pyiron_base._tests import TestWithCleanProject from pyiron_atomistics.atomistics.job.atomistic import AtomisticGenericJob from pyiron_atomistics.atomistics.structure.atoms import Atoms, CrystalStructure import warnings -class TestAtomisticGenericJob(unittest.TestCase): +class TestAtomisticGenericJob(TestWithCleanProject): @classmethod def setUpClass(cls): + super().setUpClass() cls.execution_path = os.path.dirname(os.path.abspath(__file__)) - cls.project = Project(os.path.join(cls.execution_path, "test_job")) - cls.job = AtomisticGenericJob( - project=ProjectHDFio(project=cls.project, file_name="test_job"), + + def setUp(self) -> None: + super().setUp() + self.job = AtomisticGenericJob( + project=ProjectHDFio(project=self.project, file_name="test_job"), job_name="test_job", ) - cls.job.structure = CrystalStructure( + self.job.structure = CrystalStructure( element="Al", bravais_basis="fcc", lattice_constants=4 ).repeat(4) - @classmethod - def tearDownClass(cls): - cls.execution_path = os.path.dirname(os.path.abspath(__file__)) - project = Project(os.path.join(cls.execution_path, "test_job")) - project.remove_jobs_silently(recursive=True) - project.remove(enable=True) - def test_attributes(self): self.assertIsInstance(self.job.structure, Atoms) @@ -77,19 +74,16 @@ def test_get_structure(self): # tested here with lammps as a concrete instantiation of AtomisticGenericJob # have to do extra tango because Project.unpack is weird right now cwd = os.curdir - to_dir = os.path.join(self.project.path, "..") - shutil.copy("tests/static/lammps_test_files/get_structure_test.tar.gz", to_dir) - shutil.copy("tests/static/lammps_test_files/export.csv", to_dir) - os.chdir(to_dir) + tests_loc = Path(__file__).parents[2] + shutil.copy(os.path.join(tests_loc, "static/lammps_test_files/get_structure_test.tar.gz"), cwd) + shutil.copy(os.path.join(tests_loc, "static/lammps_test_files/export.csv"), cwd) self.project.unpack("get_structure_test") job = self.project.load("inter_calculator") - os.chdir(cwd) + os.unlink("export.csv") + os.unlink("get_structure_test.tar.gz") for i, struct in enumerate(job.iter_structures()): # breakpoint() self.assertTrue(np.allclose(job.output.positions[i], struct.positions)) self.assertTrue(np.allclose(job.output.cells[i], struct.cell.array)) self.assertTrue(np.allclose(job.output.indices[i], struct.indices)) - -if __name__ == "__main__": - unittest.main() From 6c6cbae4744b43280666341c595ace4b4b99303a Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 15 Nov 2021 14:39:01 +0100 Subject: [PATCH 02/19] Refactor: extract state management --- tests/atomistics/structure/test_potentials.py | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/tests/atomistics/structure/test_potentials.py b/tests/atomistics/structure/test_potentials.py index 9b1e8a32d..694dfd414 100644 --- a/tests/atomistics/structure/test_potentials.py +++ b/tests/atomistics/structure/test_potentials.py @@ -6,47 +6,72 @@ import unittest from pyiron_atomistics.lammps.potential import LammpsPotentialFile from pyiron_atomistics.vasp.potential import VaspPotential +from pyiron_base import state +from abc import ABC -class TestLammpsPotentialFile(unittest.TestCase): +class _PotentialTester(unittest.TestCase, ABC): + """Overrides the settings so that the tests/static directory is used as the resources, then refreshes afterwards""" + + @classmethod + def setUpClass(cls): + state.update({'resource_paths': os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../static")}) + + @classmethod + def tearDownClass(cls) -> None: + state.update() + + +class TestLammpsPotentialFile(_PotentialTester): @classmethod def setUpClass(cls): + super().setUpClass() cls.kim = LammpsPotentialFile() - cls.potential_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "../../static/lammps/potentials" - ) def test_find(self): - Fe_lst = ["Fe_C_Becquart_eam", "Fe_C_Hepburn_Ackland_eam"] - - self.assertEqual(sorted(list(self.kim.find("Fe")["Name"])), sorted(Fe_lst)) - AlMg_lst = ["Al_Mg_Mendelev_eam"] - self.assertEqual(sorted(list(self.kim.find({"Al", "Mg"})["Name"])), AlMg_lst) + Fe_desired = ["Fe_C_Becquart_eam", "Fe_C_Hepburn_Ackland_eam"] + Fe_available = list(self.kim.find("Fe")["Name"]) + for potl in Fe_desired: + self.assertIn( + potl, Fe_available, + msg=f"Failed to find {potl}, which is expected since it is in the tests/static resources" + ) + self.assertIn( + "Al_Mg_Mendelev_eam", list(self.kim.find({"Al", "Mg"})["Name"]), + msg="Failed to find Al_Mg_Mendelev_eam, which is expected since it is in the tests/static resources" + ) def test_pythonic_functions(self): self.assertEqual( - list(self.kim.find("Fe")["Name"]), list(self.kim["Fe"].list()["Name"]) + list(self.kim.find("Fe")["Name"]), list(self.kim["Fe"].list()["Name"]), + msg="List conversion method failed." ) self.assertEqual( - list(self.kim.find("Fe")["Name"]), list(self.kim.Fe.list()["Name"]) + list(self.kim.find("Fe")["Name"]), list(self.kim.Fe.list()["Name"]), + msg="Element symbol attribute does not find element." ) self.assertEqual( list(self.kim.find({"Al", "Mg"})["Name"]), list(self.kim["Al"]["Mg"].list()["Name"]), + msg="Double find not equivalent to nested dictionary access." ) self.assertEqual( list(self.kim.find({"Al", "Mg"})["Name"]), + list(self.kim.Al.Mg.list()["Name"]), + msg="Nested attribute access failed" + ) + self.assertEqual( list(self.kim.Mg.Al.list()["Name"]), + list(self.kim.Al.Mg.list()["Name"]), + msg="Elemental pairs should be commutative" ) -class TestVaspPotential(unittest.TestCase): +class TestVaspPotential(_PotentialTester): @classmethod def setUpClass(cls): + super().setUpClass() cls.vasp = VaspPotential() - cls.potential_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "../../static/vasp/potentials" - ) def test_find(self): self.assertEqual( From 06561e8a0a4c7b565834a5bbb89ccf3a31c5b25a Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 15 Nov 2021 14:39:28 +0100 Subject: [PATCH 03/19] Remove tail --- tests/atomistics/structure/test_potentials.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/atomistics/structure/test_potentials.py b/tests/atomistics/structure/test_potentials.py index 694dfd414..4374cfbef 100644 --- a/tests/atomistics/structure/test_potentials.py +++ b/tests/atomistics/structure/test_potentials.py @@ -126,7 +126,3 @@ def test_pythonic_functions(self): "Fe_sv_GW-gga-pbe", ], ) - - -if __name__ == "__main__": - unittest.main() From 709da7f36f5c7812165f8a282dddad623508d9c7 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 15 Nov 2021 15:06:52 +0100 Subject: [PATCH 04/19] Update Gpaw tests --- tests/gpaw/test_gpaw.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/gpaw/test_gpaw.py b/tests/gpaw/test_gpaw.py index a918f97ad..11f896c92 100644 --- a/tests/gpaw/test_gpaw.py +++ b/tests/gpaw/test_gpaw.py @@ -2,33 +2,38 @@ # Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department # Distributed under the terms of "New BSD License", see the LICENSE file. -import unittest import os import numpy as np from pyiron_base import Project, ProjectHDFio from pyiron_atomistics.gpaw.gpaw import Gpaw from pyiron_atomistics.atomistics.structure.atoms import Atoms +from pyiron_base._tests import TestWithProject -class TestGpaw(unittest.TestCase): +class TestGpaw(TestWithProject): @classmethod def setUpClass(cls): + super().setUpClass() cls.execution_path = os.path.dirname(os.path.abspath(__file__)) cls.project = Project(os.path.join(cls.execution_path, "gpaw")) atoms = Atoms("Fe1", positions=np.zeros((1, 3)), cell=np.eye(3)) job = Gpaw( - project=ProjectHDFio(project=cls.project, file_name="gpaw"), + project=ProjectHDFio(project=cls.project, file_name=cls.project.path), job_name="gpaw", ) job.structure = atoms job.encut = 300 job.set_kpoints([5, 5, 5]) - job.to_hdf() - cls.job = Gpaw( - project=ProjectHDFio(project=cls.project, file_name="gpaw"), + cls.job = job + + def test_serialization(self): + self.job.to_hdf() + loaded = Gpaw( + project=ProjectHDFio(project=self.project, file_name=self.project.path), job_name="gpaw", ) - cls.job.from_hdf() + loaded.from_hdf() + self.assertEqual(self.job.encut, loaded.encut) def test_encut(self): self.assertEqual(self.job.encut, 300) From bed2e90f32f1fbbc69635ad707353280cd10e3e8 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 15 Nov 2021 21:18:48 +0100 Subject: [PATCH 05/19] Update lammps tests --- tests/lammps/test_base.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index f43fa0d6a..91056b780 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -7,19 +7,21 @@ import pandas as pd import os import re -from pyiron_base import Project, ProjectHDFio +from pyiron_base import state, Project, ProjectHDFio from pyiron_atomistics.atomistics.structure.atoms import Atoms from pyiron_atomistics.lammps.lammps import Lammps from pyiron_atomistics.lammps.base import LammpsStructure, UnfoldingPrism from pyiron_atomistics.lammps.units import LAMMPS_UNIT_CONVERSIONS, UnitConverter import ase.units as units +from pyiron_base._tests import TestWithProject -class TestLammps(unittest.TestCase): +class TestLammps(TestWithProject): @classmethod def setUpClass(cls): + super().setUpClass() cls.execution_path = os.path.dirname(os.path.abspath(__file__)) - cls.project = Project(os.path.join(cls.execution_path, "lammps")) + state.update({'resource_paths': os.path.join(os.path.dirname(os.path.abspath(__file__)), "../static")}) cls.job = Lammps( project=ProjectHDFio(project=cls.project, file_name="lammps"), job_name="lammps", @@ -71,10 +73,8 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - cls.execution_path = os.path.dirname(os.path.abspath(__file__)) - project = Project(os.path.join(cls.execution_path, "lammps")) - project.remove_jobs_silently(recursive=True) - project.remove(enable=True) + super().tearDownClass() + state.update() def test_selective_dynamics(self): atoms = Atoms("Fe8", positions=np.zeros((8, 3)), cell=np.eye(3)) From cc046da323c2dffd5bd31645cd3dd0fc7e77b5c6 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 15 Nov 2021 21:23:18 +0100 Subject: [PATCH 06/19] Tidy gpaw tests I biffed a couple things on the first pass --- tests/gpaw/test_gpaw.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/gpaw/test_gpaw.py b/tests/gpaw/test_gpaw.py index 11f896c92..cbf46aa05 100644 --- a/tests/gpaw/test_gpaw.py +++ b/tests/gpaw/test_gpaw.py @@ -4,7 +4,7 @@ import os import numpy as np -from pyiron_base import Project, ProjectHDFio +from pyiron_base import ProjectHDFio from pyiron_atomistics.gpaw.gpaw import Gpaw from pyiron_atomistics.atomistics.structure.atoms import Atoms from pyiron_base._tests import TestWithProject @@ -15,10 +15,9 @@ class TestGpaw(TestWithProject): def setUpClass(cls): super().setUpClass() cls.execution_path = os.path.dirname(os.path.abspath(__file__)) - cls.project = Project(os.path.join(cls.execution_path, "gpaw")) atoms = Atoms("Fe1", positions=np.zeros((1, 3)), cell=np.eye(3)) job = Gpaw( - project=ProjectHDFio(project=cls.project, file_name=cls.project.path), + project=ProjectHDFio(project=cls.project, file_name="gpaw"), job_name="gpaw", ) job.structure = atoms @@ -29,7 +28,7 @@ def setUpClass(cls): def test_serialization(self): self.job.to_hdf() loaded = Gpaw( - project=ProjectHDFio(project=self.project, file_name=self.project.path), + project=ProjectHDFio(project=self.project, file_name="gpaw"), job_name="gpaw", ) loaded.from_hdf() From b07a13a192315d37ef9c9512141b61af678d9015 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 16 Nov 2021 09:54:15 +0100 Subject: [PATCH 07/19] Update resources --- tests/vasp/test_potential.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/vasp/test_potential.py b/tests/vasp/test_potential.py index b1fcb52ca..8e078cc33 100644 --- a/tests/vasp/test_potential.py +++ b/tests/vasp/test_potential.py @@ -5,13 +5,18 @@ import unittest import os from pyiron_atomistics.vasp.potential import get_enmax_among_potentials, strip_xc_from_potential_name +from pyiron_base import state class TestPotential(unittest.TestCase): @classmethod def setUpClass(cls): - cls.file_location = os.path.dirname(os.path.abspath(__file__)) + state.update({'resource_paths': os.path.join(os.path.dirname(os.path.abspath(__file__)), "../static")}) + + @classmethod + def tearDownClass(cls) -> None: + state.update() def test_get_enmax_among_potentials(self): float_out = get_enmax_among_potentials('Fe', return_list=False) @@ -25,7 +30,3 @@ def test_get_enmax_among_potentials(self): def test_strip_xc_from_potential_name(self): self.assertEqual(strip_xc_from_potential_name('X_pv-gga-pbe'), 'X_pv') - - -if __name__ == "__main__": - unittest.main() From 343776a97978ecaeb571181fe630cfaeb31a6bae Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 16 Nov 2021 09:55:05 +0100 Subject: [PATCH 08/19] Update resources --- tests/vasp/test_vasp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/vasp/test_vasp.py b/tests/vasp/test_vasp.py index a9b9b727e..201db7737 100644 --- a/tests/vasp/test_vasp.py +++ b/tests/vasp/test_vasp.py @@ -7,7 +7,7 @@ import posixpath from pyiron_atomistics.atomistics.structure.atoms import CrystalStructure from pyiron_atomistics.vasp.base import Input, Output -from pyiron_base import ProjectHDFio, Project +from pyiron_base import state, ProjectHDFio, Project from pyiron_atomistics.vasp.potential import VaspPotentialSetter from pyiron_atomistics.vasp.vasp import Vasp from pyiron_atomistics.vasp.metadyn import VaspMetadyn @@ -24,6 +24,7 @@ class TestVasp(unittest.TestCase): @classmethod def setUpClass(cls): + state.update({'resource_paths': os.path.join(os.path.dirname(os.path.abspath(__file__)), "../static")}) cls.execution_path = os.path.dirname(os.path.abspath(__file__)) cls.project = Project(os.path.join(cls.execution_path, "test_vasp")) cls.job = cls.project.create_job("Vasp", "trial") @@ -52,6 +53,7 @@ def tearDownClass(cls): project = Project(os.path.join(cls.execution_path, "test_vasp")) project.remove_jobs_silently(recursive=True) project.remove(enable=True) + state.update() def setUp(self): self.job.structure = None From 613c13c68e4349fda4a2ae7e4eadd30d6c497744 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 29 Nov 2021 14:26:03 +0100 Subject: [PATCH 09/19] Use state in sphinx --- pyiron_atomistics/sphinx/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyiron_atomistics/sphinx/base.py b/pyiron_atomistics/sphinx/base.py index cd8728efe..1cd90fe81 100644 --- a/pyiron_atomistics/sphinx/base.py +++ b/pyiron_atomistics/sphinx/base.py @@ -27,7 +27,7 @@ from pyiron_atomistics.sphinx.potential import find_potential_file \ as find_potential_file_jth from pyiron_atomistics.sphinx.volumetric_data import SphinxVolumetricData -from pyiron_base import DataContainer, job_status_successful_lst, deprecate +from pyiron_base import state, DataContainer, job_status_successful_lst, deprecate __author__ = "Osamu Waseda, Jan Janssen" __copyright__ = ( @@ -1647,7 +1647,7 @@ def compress(self, files_to_compress=None): def check_vasp_potentials(): return any([os.path.exists(os.path.join( p, 'vasp', 'potentials', 'potpaw', 'Fe', 'POTCAR' - )) for p in s.resource_paths]) + )) for p in state.settings.resource_paths]) class InputWriter(object): @@ -1778,10 +1778,10 @@ def write_spin_constraints( spins_list (list): the input to write, if no input is given the default input will be written. (optional) """ - s.logger.debug(f"Writing {file_name}") + state.logger.debug(f"Writing {file_name}") if spins_list is None or len(spins_list) == 0: spins_list = [] - s.logger.debug("Getting magnetic moments via \ + state.logger.debug("Getting magnetic moments via \ get_initial_magnetic_moments") if any([ m is not None @@ -1814,7 +1814,7 @@ def write_spin_constraints( with open(file_name, "w") as f: f.write(spins_str) else: - s.logger.debug("No magnetic moments") + state.logger.debug("No magnetic moments") class Group(DataContainer): From c44014a6795cb69361e2b39371cc0d431162edee Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 29 Nov 2021 19:54:06 +0100 Subject: [PATCH 10/19] Merge master --- pyiron_atomistics/atomistics/structure/atoms.py | 6 +++--- pyiron_atomistics/lammps/base.py | 4 +--- tests/atomistics/structure/test_atoms.py | 8 ++++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/pyiron_atomistics/atomistics/structure/atoms.py b/pyiron_atomistics/atomistics/structure/atoms.py index 8405c7d36..174591754 100644 --- a/pyiron_atomistics/atomistics/structure/atoms.py +++ b/pyiron_atomistics/atomistics/structure/atoms.py @@ -2029,9 +2029,6 @@ def __dir__(self): # return len(self.indices) def __repr__(self): - return self.__str__() - - def __str__(self): if len(self) == 0: return "[]" out_str = "" @@ -2050,6 +2047,9 @@ def __str__(self): out_str += str(self.cell) + "\n" return out_str + def __str__(self): + return self.get_chemical_formula() + def __setitem__(self, key, value): if isinstance(key, (int, np.integer)): old_el = self.species[self.indices[key]] diff --git a/pyiron_atomistics/lammps/base.py b/pyiron_atomistics/lammps/base.py index f4ecc9bae..60cd3ea65 100644 --- a/pyiron_atomistics/lammps/base.py +++ b/pyiron_atomistics/lammps/base.py @@ -484,13 +484,11 @@ def collect_h5md_file(self, file_name="dump.h5", cwd=None): np.eye(3) * np.array(cell_i.tolist()) for cell_i in h5md["/particles/all/box/edges/value"] ] - indices = [indices_i.tolist() for indices_i in h5md["/particles/all/indices/value"]] with self.project_hdf5.open("output/generic") as h5_file: h5_file["forces"] = uc.convert_array_to_pyiron_units(np.array(forces), "forces") h5_file["positions"] = uc.convert_array_to_pyiron_units(np.array(positions), "positions") h5_file["steps"] = uc.convert_array_to_pyiron_units(np.array(steps), "steps") - h5_file["cells"] = uc.convert_array_to_pyiron_units(cell, "cells") - h5_file["indices"] = uc.convert_array_to_pyiron_units(self.remap_indices(indices), "indices") + h5_file["cells"] = uc.convert_array_to_pyiron_units(np.array(cell), "cells") def remap_indices(self, lammps_indices): """ diff --git a/tests/atomistics/structure/test_atoms.py b/tests/atomistics/structure/test_atoms.py index a0e9ee4f8..51a04492f 100644 --- a/tests/atomistics/structure/test_atoms.py +++ b/tests/atomistics/structure/test_atoms.py @@ -1558,6 +1558,14 @@ def test_set_dihedral(): structure = ase_to_pyiron(molecule('H2COH')) structure.set_dihedral(4, 0, 1, 2, angle=90) + def test_str_repr(self): + H2 = Atoms(positions=[3*[0], 3*[0.5]], cell=np.eye(3), elements=2*['H'], pbc=True) + self.assertEqual( + repr(H2), + 'H: [0. 0. 0.]\nH: [0.5 0.5 0.5]\npbc: [ True True True]\ncell: \nCell([1.0, 1.0, 1.0])\n' + ) + self.assertEqual(str(H2), 'H2') + def test_cached_speed(self): """ Creating atoms should be faster after the first time, due to caches in periodictable/mendeleev. From 4c17b4dd3b7c17634d038e6f9a057d1e20f12adf Mon Sep 17 00:00:00 2001 From: liamhuber Date: Mon, 29 Nov 2021 19:55:44 +0100 Subject: [PATCH 11/19] Remove unused import --- tests/lammps/test_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index 91056b780..68f791cfc 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -7,7 +7,7 @@ import pandas as pd import os import re -from pyiron_base import state, Project, ProjectHDFio +from pyiron_base import state, ProjectHDFio from pyiron_atomistics.atomistics.structure.atoms import Atoms from pyiron_atomistics.lammps.lammps import Lammps from pyiron_atomistics.lammps.base import LammpsStructure, UnfoldingPrism From f4d49f285d78dd08229cbfd824b16d060e06d37e Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:26:05 +0100 Subject: [PATCH 12/19] Oops I rolled this change back --- pyiron_atomistics/atomistics/job/atomistic.py | 27 ++++++++++++------- .../atomistics/structure/neighbors.py | 17 +++++++++++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/pyiron_atomistics/atomistics/job/atomistic.py b/pyiron_atomistics/atomistics/job/atomistic.py index 382d241ef..4c1903b1f 100644 --- a/pyiron_atomistics/atomistics/job/atomistic.py +++ b/pyiron_atomistics/atomistics/job/atomistic.py @@ -927,7 +927,7 @@ def unwrapped_positions(self): if unwrapped_positions is not None: return unwrapped_positions else: - return self._job.structure.positions+self.total_displacements + return self._job.structure.positions + self.total_displacements @property def volume(self): @@ -942,11 +942,16 @@ def displacements(self): """ Output for 3-d displacements between successive snapshots, with minimum image convention. For the total displacements from the initial configuration, use total_displacements - This algorithm collapses if: - - the ID's are not consistent (i.e. you can also not change the number of atoms) - - there are atoms which move by more than half a box length in any direction within two snapshots (due to - periodic boundary conditions) + This algorithm collapses if (if `unwrapped_positions` is not available in output): + - the ID's are not consistent (i.e. you can also not change the number of atoms) + - there are atoms which move by more than half a box length in any direction within + two snapshots (due to periodic boundary conditions) """ + unwrapped_positions = self._job["output/generic/unwrapped_positions"] + if unwrapped_positions is not None: + return np.diff( + np.append([self._job.structure.positions], unwrapped_positions, axis=0), axis=0 + ) return self.get_displacements(self._job.structure, self.positions, self.cells) @staticmethod @@ -984,11 +989,15 @@ def get_displacements(structure, positions, cells): def total_displacements(self): """ Output for 3-d total displacements from the initial configuration, with minimum image convention. - For the diplacements for the successive snapshots, use displacements - This algorithm collapses if: - - the ID's are not consistent (i.e. you can also not change the number of atoms) - - there are atoms which move by more than half a box length in any direction within two snapshots (due to periodic boundary conditions) + For the displacements for the successive snapshots, use displacements + This algorithm collapses if (if `unwrapped_positions` is not available in the output): + - the ID's are not consistent (i.e. you can also not change the number of atoms) + - there are atoms which move by more than half a box length in any direction within + two snapshots (due to periodic boundary conditions) """ + unwrapped_positions = self._job["output/generic/unwrapped_positions"] + if unwrapped_positions is not None: + return unwrapped_positions - self._job.structure.positions return np.cumsum(self.displacements, axis=0) def __dir__(self): diff --git a/pyiron_atomistics/atomistics/structure/neighbors.py b/pyiron_atomistics/atomistics/structure/neighbors.py index 2fb041f7b..586b28bf4 100644 --- a/pyiron_atomistics/atomistics/structure/neighbors.py +++ b/pyiron_atomistics/atomistics/structure/neighbors.py @@ -1034,6 +1034,7 @@ def __init__(self, init=None, has_structure=None, num_neighbors=12, table_name=" self._flat_store.add_array("indices", dtype=np.int64, shape=(num_neighbors,), per="element") self._flat_store.add_array("distances", dtype=np.float64, shape=(num_neighbors,), per="element") self._flat_store.add_array("vecs", dtype=np.float64, shape=(num_neighbors, 3), per="element") + self._flat_store.add_array("shells", dtype=np.int64, shape=(num_neighbors,), per="element") self._neighbor_indices = None self._neighbor_distances = None self._neighbor_vectors = None @@ -1076,6 +1077,18 @@ def vecs(self): """ return self._flat_store.get_array_filled("vecs") + @property + def shells(self): + """ + Neighbor shell indices (excluding itself) of each atom computed using the get_neighbors_traj() method. + + For trajectories with non constant amount of particles this array may contain -1 for invalid values, i.e. + + Returns: + ndarray: An int array of dimension N_steps / stride x N_atoms x N_neighbors x 3 + """ + return self._flat_store.get_array_filled("shells") + @property def num_neighbors(self): """ @@ -1100,9 +1113,11 @@ def _get_neighbors(store, has_structure, num_neighbors=20, **kwargs): # Change the `allow_ragged` based on the changes in get_neighbors() neigh = struct.get_neighbors(num_neighbors=num_neighbors, allow_ragged=False, **kwargs) if i >= len(store): - store.add_chunk(len(struct), indices=neigh.indices, distances=neigh.distances, vecs=neigh.vecs) + store.add_chunk(len(struct), + indices=neigh.indices, distances=neigh.distances, vecs=neigh.vecs, shells=neigh.shells) else: store.set_array("indices", i, neigh.indices) store.set_array("distances", i, neigh.distances) store.set_array("vecs", i, neigh.vecs) + store.set_array("shells", i, neigh.shells) return store.get_array_filled('indices'), store.get_array_filled('distances'), store.get_array_filled('vecs') From ca733ab00311647e310531afe6d78ace7d1de90e Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:28:52 +0100 Subject: [PATCH 13/19] Exploit TestWithProject in lammps tests I'm not totally happy with this. There is some serious hijinks going on when we explicitly instantiate a class compared to when we create it with one of the tool kits and the JobType wrapper. Everything winds up in the right place (because the underlying ProjectHDFio are the same) but the actual project instance was getting decoupled. I fought with this for waaay too long and now I give up and just manually reconnect the project instance -- everything works beautifully after that. We really need to do some deep dives in pyiron_base though, because the code is riddled with docstrings that say `project` arguments are type `Project`, but they're lying and the type is actually `ProjectHDFio`. I'm not fixing that in this PR though. --- tests/lammps/test_base.py | 357 ++++++++++++++++++-------------------- 1 file changed, 165 insertions(+), 192 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index 68f791cfc..d83588cfc 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -13,69 +13,41 @@ from pyiron_atomistics.lammps.base import LammpsStructure, UnfoldingPrism from pyiron_atomistics.lammps.units import LAMMPS_UNIT_CONVERSIONS, UnitConverter import ase.units as units -from pyiron_base._tests import TestWithProject +from pyiron_base._tests import TestWithCleanProject -class TestLammps(TestWithProject): +class TestLammps(TestWithCleanProject): @classmethod def setUpClass(cls): super().setUpClass() cls.execution_path = os.path.dirname(os.path.abspath(__file__)) state.update({'resource_paths': os.path.join(os.path.dirname(os.path.abspath(__file__)), "../static")}) - cls.job = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="lammps", - ) - cls.job_water = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps_water"), - job_name="lammps_water", - ) - cls.job_water_dump = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps_water_dump"), - job_name="lammps_water_dump", - ) - cls.job_dump = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps_dump_static"), - job_name="lammps_dump_static", - ) - cls.job_vcsgc_input = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps_vcsgc_input"), - job_name="lammps_vcsgc_input", - ) - cls.minimize_job = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="minimize_lammps", - ) - cls.minimize_control_job = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="minimize_control_lammps", - ) - cls.md_job = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="md_lammps", - ) - cls.md_control_job = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="md_control_lammps", - ) - cls.job_read_restart = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="read_restart", - ) - cls.job_average = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="average", - ) - cls.job_fail = Lammps( - project=ProjectHDFio(project=cls.project, file_name="lammps"), - job_name="fail", - ) @classmethod def tearDownClass(cls): super().tearDownClass() state.update() + def setUp(self) -> None: + super().setUp() + self.job = Lammps( + project=ProjectHDFio(project=self.project, file_name="lammps"), + job_name="lammps", + ) + self.ref = Lammps( + project=ProjectHDFio(project=self.project, file_name="ref"), + job_name="ref", + ) + # Creating jobs this way puts them at the right spot, but decouples them from our self.project instance. + # I still don't understand what's happening as deeply as I'd like (at all!) but I've been fighting with it too + # long, so for now I will just force the issue by redefining the project attribute(s). -Liam Huber + self.project = self.job.project + self.ref_project = self.ref.project + + def tearDown(self) -> None: + super().tearDown() + self.ref_project.remove_jobs_silently(recursive=True, progress=False) # cf. comment in setUp + def test_selective_dynamics(self): atoms = Atoms("Fe8", positions=np.zeros((8, 3)), cell=np.eye(3)) atoms.add_tag(selective_dynamics=[True, True, True]) @@ -212,18 +184,18 @@ def test_lammps_water(self): water = Atoms( elements=["H", "H", "O"], positions=[r_H1, r_H2, r_O], cell=unit_cell, pbc=True) water.set_repeat([n, n, n]) - self.job_water.structure = water + self.job.structure = water with self.assertWarns(UserWarning): - self.job_water.potential = "H2O_tip3p" + self.job.potential = "H2O_tip3p" with self.assertRaises(ValueError): - self.job_water.calc_md(temperature=350, seed=0) + self.job.calc_md(temperature=350, seed=0) with self.assertRaises(ValueError): - self.job_water.calc_md(temperature=[0, 100]) + self.job.calc_md(temperature=[0, 100]) with self.assertRaises(ValueError): - self.job_water.calc_md(pressure=0) + self.job.calc_md(pressure=0) with self.assertRaises(ValueError): - self.job_water.calc_md(temperature=[0, 100, 200]) - self.job_water.calc_md( + self.job.calc_md(temperature=[0, 100, 200]) + self.job.calc_md( temperature=350, initial_temperature=350, time_step=1, @@ -233,15 +205,16 @@ def test_lammps_water(self): file_directory = os.path.join( self.execution_path, "..", "static", "lammps_test_files" ) - self.job_water.restart_file_list.append( + self.job.restart_file_list.append( os.path.join(file_directory, "dump.out") ) - self.job_water.restart_file_list.append( + self.job.restart_file_list.append( os.path.join(file_directory, "log.lammps") ) - self.job_water.run(run_mode="manual") - self.job_water.status.collect = True - self.job_water.run() + self.job.run(run_mode="manual") + self.job.status.collect = True + # self.job.save() + self.job.run() nodes = [ "positions", "temperature", @@ -254,19 +227,19 @@ def test_lammps_water(self): "pressures", "unwrapped_positions", ] - with self.job_water.project_hdf5.open("output/generic") as h_gen: + with self.job.project_hdf5.open("output/generic") as h_gen: hdf_nodes = h_gen.list_nodes() self.assertTrue(all([node in hdf_nodes for node in nodes])) self.assertTrue( - np.array_equal(self.job_water["output/generic/positions"].shape, (6, 81, 3)) + np.array_equal(self.job["output/generic/positions"].shape, (6, 81, 3)) ) self.assertTrue( np.array_equal( - self.job_water["output/generic/positions"].shape, - self.job_water["output/generic/forces"].shape, + self.job["output/generic/positions"].shape, + self.job["output/generic/forces"].shape, ) ) - self.assertEqual(len(self.job_water["output/generic/steps"]), 6) + self.assertEqual(len(self.job["output/generic/steps"]), 6) def test_dump_parser_water(self): density = 1.0e-24 # g/A^3 @@ -287,10 +260,10 @@ def test_dump_parser_water(self): water = Atoms( elements=["H", "H", "O"], positions=[r_H1, r_H2, r_O], cell=unit_cell, pbc=True) water.set_repeat([n, n, n]) - self.job_water_dump.structure = water + self.job.structure = water with self.assertWarns(UserWarning): - self.job_water_dump.potential = "H2O_tip3p" - self.job_water_dump.calc_md( + self.job.potential = "H2O_tip3p" + self.job.calc_md( temperature=350, initial_temperature=350, time_step=1, @@ -298,85 +271,85 @@ def test_dump_parser_water(self): n_print=200, pressure=0, ) - self.assertFalse('nan' in self.job_water_dump.input.control['fix___ensemble']) + self.assertFalse('nan' in self.job.input.control['fix___ensemble']) file_directory = os.path.join( self.execution_path, "..", "static", "lammps_test_files" ) - self.job_water_dump.restart_file_list.append( + self.job.restart_file_list.append( os.path.join(file_directory, "log.lammps") ) - self.job_water_dump.restart_file_list.append( + self.job.restart_file_list.append( os.path.join(file_directory, "dump.out") ) - self.job_water_dump.run(run_mode="manual") - self.job_water_dump.status.collect = True - self.job_water_dump.run() + self.job.run(run_mode="manual") + self.job.status.collect = True + self.job.run() positions = np.loadtxt(os.path.join(file_directory, "positions_water.dat")) positions = positions.reshape(len(positions), -1, 3) forces = np.loadtxt(os.path.join(file_directory, "forces_water.dat")) forces = forces.reshape(len(forces), -1, 3) self.assertTrue( np.allclose( - self.job_water_dump["output/generic/unwrapped_positions"], positions + self.job["output/generic/unwrapped_positions"], positions ) ) - uc = UnitConverter(self.job_water_dump.input.control["units"]) + uc = UnitConverter(self.job.input.control["units"]) self.assertTrue( - np.allclose(self.job_water_dump["output/generic/forces"], uc.convert_array_to_pyiron_units(forces, + np.allclose(self.job["output/generic/forces"], uc.convert_array_to_pyiron_units(forces, "forces")) ) - self.assertEqual(self.job_water_dump["output/generic/energy_tot"][-1], -5906.46836142123 * + self.assertEqual(self.job["output/generic/energy_tot"][-1], -5906.46836142123 * uc.lammps_to_pyiron("energy")) - self.assertEqual(self.job_water_dump["output/generic/energy_pot"][-1], -5982.82004785158 * + self.assertEqual(self.job["output/generic/energy_pot"][-1], -5982.82004785158 * uc.lammps_to_pyiron("energy")) - self.assertAlmostEqual(self.job_water_dump["output/generic/pressures"][-2][0, 0], 515832.570508186 / + self.assertAlmostEqual(self.job["output/generic/pressures"][-2][0, 0], 515832.570508186 / uc.pyiron_to_lammps("pressure"), 2) - self.job_water_dump.write_traj(filename="test.xyz", + self.job.write_traj(filename="test.xyz", file_format="xyz") - atom_indices = self.job_water_dump.structure.select_index("H") + atom_indices = self.job.structure.select_index("H") snap_indices = [1, 3, 4] - orig_pos = self.job_water_dump.output.positions - self.job_water_dump.write_traj(filename="test.xyz", + orig_pos = self.job.output.positions + self.job.write_traj(filename="test.xyz", file_format="xyz", atom_indices=atom_indices, snapshot_indices=snap_indices) - self.job_water_dump.write_traj(filename="test.xyz", + self.job.write_traj(filename="test.xyz", file_format="xyz", atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=np.zeros_like(orig_pos)) - self.assertRaises(ValueError, self.job_water_dump.write_traj, filename="test.xyz", + self.assertRaises(ValueError, self.job.write_traj, filename="test.xyz", file_format="xyz", atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=np.zeros_like(orig_pos)[:-1]) - self.job_water_dump.write_traj(filename="test.xyz", + self.job.write_traj(filename="test.xyz", file_format="xyz", atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=np.zeros_like(orig_pos), - overwrite_cells=self.job_water_dump.trajectory()._cells) - self.job_water_dump.write_traj(filename="test.xyz", + overwrite_cells=self.job.trajectory()._cells) + self.job.write_traj(filename="test.xyz", file_format="xyz", atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=np.zeros_like(orig_pos)[:-1], - overwrite_cells=self.job_water_dump.trajectory()._cells[:-1]) - self.assertRaises(ValueError, self.job_water_dump.write_traj, filename="test.xyz", + overwrite_cells=self.job.trajectory()._cells[:-1]) + self.assertRaises(ValueError, self.job.write_traj, filename="test.xyz", file_format="xyz", atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=np.zeros_like(orig_pos), - overwrite_cells=self.job_water_dump.trajectory()._cells[:-1]) + overwrite_cells=self.job.trajectory()._cells[:-1]) os.remove("test.xyz") - self.assertTrue(np.array_equal(self.job_water_dump.trajectory()._positions, + self.assertTrue(np.array_equal(self.job.trajectory()._positions, orig_pos)) - self.assertTrue(np.array_equal(self.job_water_dump.trajectory(stride=2)._positions, + self.assertTrue(np.array_equal(self.job.trajectory(stride=2)._positions, orig_pos[::2])) self.assertTrue(np.array_equal( - self.job_water_dump.trajectory(atom_indices=atom_indices, + self.job.trajectory(atom_indices=atom_indices, snapshot_indices=snap_indices)._positions, orig_pos[snap_indices][:, atom_indices, :])) @@ -384,49 +357,49 @@ def test_dump_parser_water(self): random_array = np.random.rand(nx, ny, nz) random_cell = np.random.rand(nx, 3, 3) self.assertTrue(np.array_equal( - self.job_water_dump.trajectory(atom_indices=atom_indices, + self.job.trajectory(atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=random_array)._positions, random_array[snap_indices][:, atom_indices, :])) self.assertTrue(np.array_equal( - self.job_water_dump.trajectory(atom_indices=atom_indices, + self.job.trajectory(atom_indices=atom_indices, snapshot_indices=snap_indices, overwrite_positions=random_array, overwrite_cells=random_cell)._cells, random_cell[snap_indices])) - self.assertIsInstance(self.job_water_dump.get_structure(-1), Atoms) + self.assertIsInstance(self.job.get_structure(-1), Atoms) # Test for clusters - with self.job_water_dump.project_hdf5.open("output/generic") as h_out: + with self.job.project_hdf5.open("output/generic") as h_out: h_out["cells"] = None self.assertTrue(np.array_equal( - self.job_water_dump.trajectory(atom_indices=atom_indices, + self.job.trajectory(atom_indices=atom_indices, snapshot_indices=snap_indices)._positions, orig_pos[snap_indices][:, atom_indices, :])) - with self.job_water_dump.project_hdf5.open("output/generic") as h_out: + with self.job.project_hdf5.open("output/generic") as h_out: h_out["cells"] = np.repeat([np.array(water.cell)], len(h_out["positions"]), axis=0) self.assertTrue(np.array_equal( - self.job_water_dump.trajectory(atom_indices=atom_indices, + self.job.trajectory(atom_indices=atom_indices, snapshot_indices=snap_indices)._positions, orig_pos[snap_indices][:, atom_indices, :])) - neigh_traj_obj = self.job_water_dump.get_neighbors() + neigh_traj_obj = self.job.get_neighbors() self.assertTrue(np.allclose(np.linalg.norm(neigh_traj_obj.vecs, axis=-1), neigh_traj_obj.distances)) - h_indices = self.job_water_dump.structure.select_index("H") - o_indices = self.job_water_dump.structure.select_index("O") + h_indices = self.job.structure.select_index("H") + o_indices = self.job.structure.select_index("O") self.assertLessEqual(neigh_traj_obj.distances[:, o_indices, :2].max(), 1.2) self.assertGreaterEqual(neigh_traj_obj.distances[:, o_indices, :2].min(), 0.8) self.assertTrue(np.alltrue([np.in1d(np.unique(ind_mat.flatten()), h_indices) for ind_mat in neigh_traj_obj.indices[:, o_indices, :2]])) - neigh_traj_obj_snaps = self.job_water_dump.get_neighbors_snapshots(snapshot_indices=[2, 3, 4]) + neigh_traj_obj_snaps = self.job.get_neighbors_snapshots(snapshot_indices=[2, 3, 4]) self.assertTrue(np.allclose(neigh_traj_obj.vecs[2:], neigh_traj_obj_snaps.vecs)) - neigh_traj_obj.to_hdf(self.job_water_dump.project_hdf5) - neigh_traj_obj_loaded = self.job_water_dump["neighbors_traj"].to_object() + neigh_traj_obj.to_hdf(self.job.project_hdf5) + neigh_traj_obj_loaded = self.job["neighbors_traj"].to_object() # self.assertEqual(neigh_traj_obj._init_structure, neigh_traj_obj_loaded._init_structure) self.assertEqual(neigh_traj_obj._num_neighbors, neigh_traj_obj_loaded._num_neighbors) self.assertTrue(np.allclose(neigh_traj_obj.indices, neigh_traj_obj_loaded.indices)) self.assertTrue(np.allclose(neigh_traj_obj.distances, neigh_traj_obj_loaded.distances)) self.assertTrue(np.allclose(neigh_traj_obj.vecs, neigh_traj_obj_loaded.vecs)) - self.assertTrue(self.job_water_dump.units, "real") + self.assertTrue(self.job.units, "real") def test_dump_parser(self): structure = Atoms( @@ -434,23 +407,23 @@ def test_dump_parser(self): cell=2.78 * np.eye(3), positions=2.78 * np.outer(np.arange(2), np.ones(3)) * 0.5, ) - self.job_dump.structure = structure - self.job_dump.potential = self.job_dump.list_potentials()[0] + self.job.structure = structure + self.job.potential = self.job.list_potentials()[0] file_directory = os.path.join( self.execution_path, "..", "static", "lammps_test_files" ) - self.job_dump.collect_dump_file(cwd=file_directory, file_name="dump_static.out") + self.job.collect_dump_file(cwd=file_directory, file_name="dump_static.out") self.assertTrue( - np.array_equal(self.job_dump["output/generic/forces"].shape, (1, 2, 3)) + np.array_equal(self.job["output/generic/forces"].shape, (1, 2, 3)) ) self.assertTrue( - np.array_equal(self.job_dump["output/generic/positions"].shape, (1, 2, 3)) + np.array_equal(self.job["output/generic/positions"].shape, (1, 2, 3)) ) self.assertTrue( - np.array_equal(self.job_dump["output/generic/cells"].shape, (1, 3, 3)) + np.array_equal(self.job["output/generic/cells"].shape, (1, 3, 3)) ) self.assertTrue( - np.array_equal(self.job_dump["output/generic/indices"].shape, (1, 2)) + np.array_equal(self.job["output/generic/indices"].shape, (1, 2)) ) def test_vcsgc_input(self): @@ -464,41 +437,41 @@ def test_vcsgc_input(self): ], cell=4 * np.eye(3) ) - self.job_vcsgc_input.structure = unit_cell - self.job_vcsgc_input.potential = self.job_vcsgc_input.list_potentials()[0] - symbols = self.job_vcsgc_input.input.potential.get_element_lst() + self.job.structure = unit_cell + self.job.potential = self.job.list_potentials()[0] + symbols = self.job.input.potential.get_element_lst() bad_element = {s: 0. for s in symbols} bad_element.update({'X': 1.}) # Non-existant chemical symbol self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, mu=bad_element, temperature_mc=300. + ValueError, self.job.calc_vcsgc, mu=bad_element, temperature_mc=300. ) self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, target_concentration=bad_element, temperature_mc=300. + ValueError, self.job.calc_vcsgc, target_concentration=bad_element, temperature_mc=300. ) bad_conc = {s: 0. for s in symbols} bad_conc['Al'] = 0.99 self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, target_concentration=bad_conc, temperature_mc=300. + ValueError, self.job.calc_vcsgc, target_concentration=bad_conc, temperature_mc=300. ) self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, window_moves=-1, temperature_mc=300. + ValueError, self.job.calc_vcsgc, window_moves=-1, temperature_mc=300. ) self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, window_moves=1.1, temperature_mc=300. + ValueError, self.job.calc_vcsgc, window_moves=1.1, temperature_mc=300. ) self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, window_size=0.3, temperature_mc=300. + ValueError, self.job.calc_vcsgc, window_size=0.3, temperature_mc=300. ) mu = {s: 0. for s in symbols} mu[symbols[0]] = 1. self.assertRaises( - ValueError, self.job_vcsgc_input.calc_vcsgc, mu=mu, temperature_mc=None, temperature=None + ValueError, self.job.calc_vcsgc, mu=mu, temperature_mc=None, temperature=None ) @@ -521,8 +494,8 @@ def test_vcsgc_input(self): ' '.join([str(args['mu'][symbol] - args['mu'][symbols[0]]) for symbol in symbols[1:]]), args['seed'] ) - self.job_vcsgc_input.calc_vcsgc(**args) - self.assertEqual(self.job_vcsgc_input.input.control['fix___vcsgc'], input_string) + self.job.calc_vcsgc(**args) + self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) args['temperature_mc'] = 100. input_string = 'all sgcmc {0} {1} {2} {3} randseed {4}'.format( @@ -532,8 +505,8 @@ def test_vcsgc_input(self): ' '.join([str(args['mu'][symbol] - args['mu'][symbols[0]]) for symbol in symbols[1:]]), args['seed'] ) - self.job_vcsgc_input.calc_vcsgc(**args) - self.assertEqual(self.job_vcsgc_input.input.control['fix___vcsgc'], input_string) + self.job.calc_vcsgc(**args) + self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) conc = {s: 0. for s in symbols} conc[symbols[0]] = 0.5 @@ -543,66 +516,66 @@ def test_vcsgc_input(self): args['kappa'], ' '.join([str(conc[symbol]) for symbol in symbols[1:]]) ) - self.job_vcsgc_input.calc_vcsgc(**args) - self.assertEqual(self.job_vcsgc_input.input.control['fix___vcsgc'], input_string) + self.job.calc_vcsgc(**args) + self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) args['window_moves'] = 10 input_string += ' window_moves {0}'.format(args['window_moves']) - self.job_vcsgc_input.calc_vcsgc(**args) - self.assertEqual(self.job_vcsgc_input.input.control['fix___vcsgc'], input_string) + self.job.calc_vcsgc(**args) + self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) args['window_size'] = 0.75 input_string += ' window_size {0}'.format(args['window_size']) - self.job_vcsgc_input.calc_vcsgc(**args) - self.assertEqual(self.job_vcsgc_input.input.control['fix___vcsgc'], input_string) + self.job.calc_vcsgc(**args) + self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) - self.job_vcsgc_input.to_hdf() + self.job.to_hdf() for k, v in args.items(): if k not in ("mu", "target_concentration", "mc_step_interval", "swap_fraction", "temperature_mc"): continue - self.assertEqual(self.job_vcsgc_input._generic_input[k], v, + self.assertEqual(self.job._generic_input[k], v, f"Wrong value stored in generic input for parameter {k}!") # decode saved GenericParameters manually... - data = self.job_vcsgc_input["input/generic/data_dict"] + data = self.job["input/generic/data_dict"] self.assertEqual(data["Value"][data["Parameter"].index(k)], str(v), f"Wrong value stored in HDF for parameter {k}!") def test_calc_minimize_input(self): # Ensure that defaults match control defaults atoms = Atoms("Fe8", positions=np.zeros((8, 3)), cell=np.eye(3)) - self.minimize_control_job.structure = atoms - self.minimize_control_job.input.control.calc_minimize() + self.ref.structure = atoms + self.ref.input.control.calc_minimize() - self.minimize_job.sturcture = atoms - self.minimize_job._prism = UnfoldingPrism(atoms.cell) - self.minimize_job.calc_minimize() + self.job.sturcture = atoms + self.job._prism = UnfoldingPrism(atoms.cell) + self.job.calc_minimize() for k in self.job.input.control.keys(): - self.assertEqual(self.minimize_job.input.control[k], self.minimize_control_job.input.control[k]) + self.assertEqual(self.job.input.control[k], self.ref.input.control[k]) # Ensure that pressure inputs are being parsed OK - self.minimize_control_job.calc_minimize(pressure=0) + self.ref.calc_minimize(pressure=0) self.assertEqual( - self.minimize_control_job.input.control['fix___ensemble'], + self.ref.input.control['fix___ensemble'], "all box/relax iso 0.0" ) - self.minimize_control_job.calc_minimize(pressure=[0.0, 0.0, 0.0]) + self.ref.calc_minimize(pressure=[0.0, 0.0, 0.0]) self.assertEqual( - self.minimize_control_job.input.control['fix___ensemble'], + self.ref.input.control['fix___ensemble'], "all box/relax x 0.0 y 0.0 z 0.0 couple none" ) - cnv = LAMMPS_UNIT_CONVERSIONS[self.minimize_control_job.input.control["units"]]["pressure"] + cnv = LAMMPS_UNIT_CONVERSIONS[self.ref.input.control["units"]]["pressure"] - self.minimize_control_job.calc_minimize(pressure=-2.0) + self.ref.calc_minimize(pressure=-2.0) m = re.match(r"all +box/relax +iso +([-\d.]+)$", - self.minimize_control_job.input.control['fix___ensemble'].strip()) + self.ref.input.control['fix___ensemble'].strip()) self.assertTrue(m) self.assertTrue(np.isclose(float(m.group(1)), -2.0 * cnv)) - self.minimize_control_job.calc_minimize(pressure=[1, 2, None, 3., 0., None]) + self.ref.calc_minimize(pressure=[1, 2, None, 3., 0., None]) m = re.match(r"all +box/relax +x +([\d.]+) +y ([\d.]+) +xy +([\d.]+) +xz +([\d.]+) +couple +none$", - self.minimize_control_job.input.control['fix___ensemble'].strip()) + self.ref.input.control['fix___ensemble'].strip()) self.assertTrue(m) self.assertTrue(np.isclose(float(m.group(1)), 1.0 * cnv)) self.assertTrue(np.isclose(float(m.group(2)), 2.0 * cnv)) @@ -612,42 +585,42 @@ def test_calc_minimize_input(self): def test_calc_md_input(self): # Ensure that defaults match control defaults atoms = Atoms("Fe8", positions=np.zeros((8, 3)), cell=np.eye(3)) - self.md_control_job.structure = atoms - self.md_control_job.input.control.calc_md() + self.ref.structure = atoms + self.ref.input.control.calc_md() - self.md_job.sturcture = atoms - self.md_job._prism = UnfoldingPrism(atoms.cell) - self.md_job.calc_md() + self.job.sturcture = atoms + self.job._prism = UnfoldingPrism(atoms.cell) + self.job.calc_md() for k in self.job.input.control.keys(): - self.assertEqual(self.md_job.input.control[k], self.md_control_job.input.control[k]) + self.assertEqual(self.job.input.control[k], self.ref.input.control[k]) # Ensure that pressure inputs are being parsed OK - self.md_control_job.calc_md(temperature=300.0, pressure=0) + self.ref.calc_md(temperature=300.0, pressure=0) self.assertEqual( - self.md_control_job.input.control['fix___ensemble'], + self.ref.input.control['fix___ensemble'], "all npt temp 300.0 300.0 0.1 iso 0.0 0.0 1.0" ) - self.md_control_job.calc_md(temperature=300.0, pressure=[0.0, 0.0, 0.0]) + self.ref.calc_md(temperature=300.0, pressure=[0.0, 0.0, 0.0]) self.assertEqual( - self.md_control_job.input.control['fix___ensemble'], + self.ref.input.control['fix___ensemble'], "all npt temp 300.0 300.0 0.1 x 0.0 0.0 1.0 y 0.0 0.0 1.0 z 0.0 0.0 1.0" ) - cnv = LAMMPS_UNIT_CONVERSIONS[self.md_control_job.input.control["units"]]["pressure"] + cnv = LAMMPS_UNIT_CONVERSIONS[self.ref.input.control["units"]]["pressure"] - self.md_control_job.calc_md(temperature=300.0, pressure=-2.0) + self.ref.calc_md(temperature=300.0, pressure=-2.0) m = re.match(r"all +npt +temp +300.0 +300.0 +0.1 +iso +([-\d.]+) +([-\d.]+) 1.0$", - self.md_control_job.input.control['fix___ensemble'].strip()) + self.ref.input.control['fix___ensemble'].strip()) self.assertTrue(m) self.assertTrue(np.isclose(float(m.group(1)), -2.0 * cnv)) self.assertTrue(np.isclose(float(m.group(2)), -2.0 * cnv)) - self.md_control_job.calc_md(temperature=300.0, pressure=[1, 2, None, 3., 0., None]) + self.ref.calc_md(temperature=300.0, pressure=[1, 2, None, 3., 0., None]) m = re.match(r"all +npt +temp +300.0 +300.0 +0.1 +" r"x +([\d.]+) +([\d.]+) +1.0 +y +([\d.]+) +([\d.]+) +1.0 +" r"xy +([\d.]+) +([\d.]+) +1.0 +xz +([\d.]+) +([\d.]+) +1.0$", - self.md_control_job.input.control['fix___ensemble'].strip()) + self.ref.input.control['fix___ensemble'].strip()) self.assertTrue(m) self.assertTrue(np.isclose(float(m.group(1)), 1.0 * cnv)) self.assertTrue(np.isclose(float(m.group(2)), 1.0 * cnv)) @@ -659,44 +632,44 @@ def test_calc_md_input(self): self.assertTrue(np.isclose(float(m.group(8)), 0.0 * cnv)) def test_read_restart_file(self): - self.job_read_restart.read_restart_file() - self.assertIsNone(self.job_read_restart['dimension']) + self.job.read_restart_file() + self.assertIsNone(self.job['dimension']) def test_write_restart(self): - self.job_read_restart.write_restart_file() - self.assertEqual(self.job_read_restart.input.control['write_restart'], 'restart.out') + self.job.write_restart_file() + self.assertEqual(self.job.input.control['write_restart'], 'restart.out') def test_average(self): a_0 = 2.855312531 atoms = Atoms("Fe2", positions=[3*[0], 3*[0.5*a_0]], cell=a_0*np.eye(3)) - self.job_average.structure = atoms - self.job_average.potential = 'Fe_C_Becquart_eam' + self.job.structure = atoms + self.job.potential = 'Fe_C_Becquart_eam' file_directory = os.path.join( self.execution_path, "..", "static", "lammps_test_files" ) - self.job_average.collect_dump_file(cwd=file_directory, file_name="dump_average.out") - self.job_average.collect_output_log(cwd=file_directory, file_name="log_average.lammps") + self.job.collect_dump_file(cwd=file_directory, file_name="dump_average.out") + self.job.collect_output_log(cwd=file_directory, file_name="log_average.lammps") def test_validate(self): with self.assertRaises(ValueError): - self.job_fail.validate_ready_to_run() + self.job.validate_ready_to_run() a_0 = 2.855312531 atoms = Atoms("Fe2", positions=[3 * [0], 3 * [0.5 * a_0]], cell=a_0 * np.eye(3), pbc=False) - self.job_fail.structure = atoms + self.job.structure = atoms # with self.assertRaises(ValueError): - # self.job_fail.validate_ready_to_run() - self.job_fail.potential = self.job_fail.list_potentials()[-1] - self.job_fail.validate_ready_to_run() - self.job_fail.structure.positions[0, 0] -= 2.855 + # self.job.validate_ready_to_run() + self.job.potential = self.job.list_potentials()[-1] + self.job.validate_ready_to_run() + self.job.structure.positions[0, 0] -= 2.855 with self.assertRaises(ValueError): - self.job_fail.validate_ready_to_run() - self.job_fail.structure.pbc = True - self.job_fail.validate_ready_to_run() - self.job_fail.structure.pbc = [True, True, False] - self.job_fail.validate_ready_to_run() - self.job_fail.structure.pbc = [False, True, True] + self.job.validate_ready_to_run() + self.job.structure.pbc = True + self.job.validate_ready_to_run() + self.job.structure.pbc = [True, True, False] + self.job.validate_ready_to_run() + self.job.structure.pbc = [False, True, True] with self.assertRaises(ValueError): - self.job_fail.validate_ready_to_run() + self.job.validate_ready_to_run() def test_potential_check(self): """ From f6d7ef7b5fadf14859a5ab2e95ba5d082b254f26 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:36:39 +0100 Subject: [PATCH 14/19] Refactor extract method Remove duplicate code --- tests/lammps/test_base.py | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index d83588cfc..31e783655 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -166,7 +166,7 @@ def test_avilable_versions(self): ) self.assertTrue([2018, 3, 16] == self.job._get_executable_version_number()) - def test_lammps_water(self): + def _build_water(self, y0_shift=0): density = 1.0e-24 # g/A^3 n_mols = 27 mol_mass_water = 18.015 # g/mol @@ -181,10 +181,13 @@ def test_lammps_water(self): r_H1 = [dx, dx, 0] r_H2 = [-dx, dx, 0] unit_cell = (a / n) * np.eye(3) - water = Atoms( - elements=["H", "H", "O"], positions=[r_H1, r_H2, r_O], cell=unit_cell, pbc=True) + unit_cell[0][1] += y0_shift + water = Atoms(elements=["H", "H", "O"], positions=[r_H1, r_H2, r_O], cell=unit_cell, pbc=True) water.set_repeat([n, n, n]) - self.job.structure = water + return water + + def test_lammps_water(self): + self.job.structure = self._build_water() with self.assertWarns(UserWarning): self.job.potential = "H2O_tip3p" with self.assertRaises(ValueError): @@ -213,7 +216,6 @@ def test_lammps_water(self): ) self.job.run(run_mode="manual") self.job.status.collect = True - # self.job.save() self.job.run() nodes = [ "positions", @@ -242,24 +244,7 @@ def test_lammps_water(self): self.assertEqual(len(self.job["output/generic/steps"]), 6) def test_dump_parser_water(self): - density = 1.0e-24 # g/A^3 - n_mols = 27 - mol_mass_water = 18.015 # g/mol - # Determining the supercell size size - mass = mol_mass_water * n_mols / units.mol # g - vol_h2o = mass / density # in A^3 - a = vol_h2o ** (1.0 / 3.0) # A - # Constructing the unitcell - n = int(round(n_mols ** (1.0 / 3.0))) - dx = 0.7 - r_O = [0, 0, 0] - r_H1 = [dx, dx, 0] - r_H2 = [-dx, dx, 0] - unit_cell = (a / n) * np.eye(3) - unit_cell[0][1] += 0.01 - water = Atoms( - elements=["H", "H", "O"], positions=[r_H1, r_H2, r_O], cell=unit_cell, pbc=True) - water.set_repeat([n, n, n]) + water = self._build_water(y0_shift=0.01) self.job.structure = water with self.assertWarns(UserWarning): self.job.potential = "H2O_tip3p" From fc111c786d624ccaa0942b48225ae93743d9337f Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:37:10 +0100 Subject: [PATCH 15/19] Don't treat as main Test runners handle things fine without this --- tests/lammps/test_base.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index 31e783655..a2b106845 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -2,7 +2,6 @@ # Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department # Distributed under the terms of "New BSD License", see the LICENSE file. -import unittest import numpy as np import pandas as pd import os @@ -689,7 +688,3 @@ def test_units(self): def setter(x): self.job.units = x self.assertRaises(ValueError, setter, "nonsense") - - -if __name__ == "__main__": - unittest.main() From 1d1aba9e673a3020c2b816eaf6fdf79dbcfdd2ed Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:39:38 +0100 Subject: [PATCH 16/19] Tidy --- tests/lammps/test_base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index a2b106845..b3110131f 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -165,7 +165,7 @@ def test_avilable_versions(self): ) self.assertTrue([2018, 3, 16] == self.job._get_executable_version_number()) - def _build_water(self, y0_shift=0): + def _build_water(self, y0_shift=0.): density = 1.0e-24 # g/A^3 n_mols = 27 mol_mass_water = 18.015 # g/mol @@ -458,7 +458,6 @@ def test_vcsgc_input(self): ValueError, self.job.calc_vcsgc, mu=mu, temperature_mc=None, temperature=None ) - args = dict( mu=mu, target_concentration=None, From 7dcc7d2ec1bb6bae46aaa588e370424e000306fb Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:41:32 +0100 Subject: [PATCH 17/19] Reduce duplication with loop --- tests/lammps/test_base.py | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index b3110131f..a5ac5525e 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -63,27 +63,11 @@ def test_selective_dynamics(self): atoms.selective_dynamics[7] = [False, False, False] self.job.structure = atoms self.job._set_selective_dynamics() - self.assertTrue( - "group___constraintx" in self.job.input.control._dataset["Parameter"] - ) - self.assertTrue( - "group___constrainty" in self.job.input.control._dataset["Parameter"] - ) - self.assertTrue( - "group___constraintz" in self.job.input.control._dataset["Parameter"] - ) - self.assertTrue( - "group___constraintxy" in self.job.input.control._dataset["Parameter"] - ) - self.assertTrue( - "group___constraintyz" in self.job.input.control._dataset["Parameter"] - ) - self.assertTrue( - "group___constraintxz" in self.job.input.control._dataset["Parameter"] - ) - self.assertTrue( - "group___constraintxyz" in self.job.input.control._dataset["Parameter"] - ) + for constraint in ["x", "y", "z", "xy", "yz", "xz", "xyz"]: + self.assertTrue( + f"group___constraint{constraint}" in self.job.input.control._dataset["Parameter"], + msg=f"Failed to find group___constraint{constraint} in control" + ) def test_structure_atomic(self): atoms = Atoms("Fe1", positions=np.zeros((1, 3)), cell=np.eye(3)) From 4f383a1fb4e35cfcddc674a63648571c8715d596 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 20:55:16 +0100 Subject: [PATCH 18/19] Add context to VCSGC tests I'm the one who wrote them, so it seems fair --- tests/lammps/test_base.py | 89 +++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index a5ac5525e..cde04d8ee 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -409,38 +409,26 @@ def test_vcsgc_input(self): self.job.potential = self.job.list_potentials()[0] symbols = self.job.input.potential.get_element_lst() - bad_element = {s: 0. for s in symbols} - bad_element.update({'X': 1.}) # Non-existant chemical symbol - self.assertRaises( - ValueError, self.job.calc_vcsgc, mu=bad_element, temperature_mc=300. - ) - - self.assertRaises( - ValueError, self.job.calc_vcsgc, target_concentration=bad_element, temperature_mc=300. - ) - - bad_conc = {s: 0. for s in symbols} - bad_conc['Al'] = 0.99 - self.assertRaises( - ValueError, self.job.calc_vcsgc, target_concentration=bad_conc, temperature_mc=300. - ) - - self.assertRaises( - ValueError, self.job.calc_vcsgc, window_moves=-1, temperature_mc=300. - ) - self.assertRaises( - ValueError, self.job.calc_vcsgc, window_moves=1.1, temperature_mc=300. - ) - - self.assertRaises( - ValueError, self.job.calc_vcsgc, window_size=0.3, temperature_mc=300. - ) - - mu = {s: 0. for s in symbols} - mu[symbols[0]] = 1. - self.assertRaises( - ValueError, self.job.calc_vcsgc, mu=mu, temperature_mc=None, temperature=None - ) + with self.subTest("Fail when elements outside the periodic table are used"): + bad_element = {s: 0. for s in symbols} + bad_element.update({'X': 1.}) # Non-existant chemical symbol + self.assertRaises(ValueError, self.job.calc_vcsgc, mu=bad_element, temperature_mc=300.) + self.assertRaises(ValueError, self.job.calc_vcsgc, target_concentration=bad_element, temperature_mc=300.) + + with self.subTest("Fail when concentrations don't add to 1"): + bad_conc = {s: 0. for s in symbols} + bad_conc['Al'] = 0.99 + self.assertRaises(ValueError, self.job.calc_vcsgc, target_concentration=bad_conc, temperature_mc=300.) + + with self.subTest("Check window definitions"): + for bad_window in [-1, 1.1]: + self.assertRaises(ValueError, self.job.calc_vcsgc, window_moves=bad_window, temperature_mc=300.) + self.assertRaises(ValueError, self.job.calc_vcsgc, window_size=0.3, temperature_mc=300.) + + with self.subTest("Temperature can't be None"): + mu = {s: 0. for s in symbols} + mu[symbols[0]] = 1. + self.assertRaises(ValueError, self.job.calc_vcsgc, mu=mu, temperature_mc=None, temperature=None) args = dict( mu=mu, @@ -462,7 +450,10 @@ def test_vcsgc_input(self): args['seed'] ) self.job.calc_vcsgc(**args) - self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) + self.assertEqual( + self.job.input.control['fix___vcsgc'], input_string, + msg="Parser did not reproduce expected lammps control syntax" + ) args['temperature_mc'] = 100. input_string = 'all sgcmc {0} {1} {2} {3} randseed {4}'.format( @@ -473,7 +464,10 @@ def test_vcsgc_input(self): args['seed'] ) self.job.calc_vcsgc(**args) - self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) + self.assertEqual( + self.job.input.control['fix___vcsgc'], input_string, + msg="Parser did not reproduce expected lammps control syntax" + ) conc = {s: 0. for s in symbols} conc[symbols[0]] = 0.5 @@ -484,28 +478,41 @@ def test_vcsgc_input(self): ' '.join([str(conc[symbol]) for symbol in symbols[1:]]) ) self.job.calc_vcsgc(**args) - self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) + self.assertEqual( + self.job.input.control['fix___vcsgc'], input_string, + msg="Parser did not reproduce expected lammps control syntax" + ) args['window_moves'] = 10 input_string += ' window_moves {0}'.format(args['window_moves']) self.job.calc_vcsgc(**args) - self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) + self.assertEqual( + self.job.input.control['fix___vcsgc'], input_string, + msg="Parser did not reproduce expected lammps control syntax" + ) args['window_size'] = 0.75 input_string += ' window_size {0}'.format(args['window_size']) self.job.calc_vcsgc(**args) - self.assertEqual(self.job.input.control['fix___vcsgc'], input_string) + self.assertEqual( + self.job.input.control['fix___vcsgc'], input_string, + msg="Parser did not reproduce expected lammps control syntax" + ) self.job.to_hdf() for k, v in args.items(): if k not in ("mu", "target_concentration", "mc_step_interval", "swap_fraction", "temperature_mc"): continue - self.assertEqual(self.job._generic_input[k], v, - f"Wrong value stored in generic input for parameter {k}!") + self.assertEqual( + self.job._generic_input[k], v, + msg=f"Wrong value stored in generic input for parameter {k}!" + ) # decode saved GenericParameters manually... data = self.job["input/generic/data_dict"] - self.assertEqual(data["Value"][data["Parameter"].index(k)], str(v), - f"Wrong value stored in HDF for parameter {k}!") + self.assertEqual( + data["Value"][data["Parameter"].index(k)], str(v), + msg=f"Wrong value stored in HDF for parameter {k}!" + ) def test_calc_minimize_input(self): # Ensure that defaults match control defaults From f7c5d28f1de08d22bfd895fa27012532ccb2d740 Mon Sep 17 00:00:00 2001 From: liamhuber Date: Tue, 30 Nov 2021 22:02:10 +0100 Subject: [PATCH 19/19] Remove progress kwarg CI complains about it. I don't have any idea why as it is totally there in base, but whatever. --- tests/lammps/test_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lammps/test_base.py b/tests/lammps/test_base.py index cde04d8ee..cedb77595 100644 --- a/tests/lammps/test_base.py +++ b/tests/lammps/test_base.py @@ -45,7 +45,7 @@ def setUp(self) -> None: def tearDown(self) -> None: super().tearDown() - self.ref_project.remove_jobs_silently(recursive=True, progress=False) # cf. comment in setUp + self.ref_project.remove_jobs_silently(recursive=True) # cf. comment in setUp def test_selective_dynamics(self): atoms = Atoms("Fe8", positions=np.zeros((8, 3)), cell=np.eye(3))