From 1919063fd9a8ca6cd32b79c74ac0c0713832e741 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Sun, 11 Aug 2024 18:12:40 -0700 Subject: [PATCH 01/10] Add static calculation feature to matcalc/relaxation.py In the original relaxation.py, users are allowed to do cell relaxation or atoms only relaxation. Static calculation is an important feature itself and also part of some complex applications (eg. QHA). As MatCalc provides a universal interface for different uMLIPs, how about we add this feature to RelaxCalc? The default is still cell relaxation, and user can set "relax_atoms" and "relax_cell" to False to do static calculation. Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- matcalc/relaxation.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/matcalc/relaxation.py b/matcalc/relaxation.py index 34723e5..ba242f1 100644 --- a/matcalc/relaxation.py +++ b/matcalc/relaxation.py @@ -79,6 +79,7 @@ def __init__( traj_file: str | None = None, interval: int = 1, fmax: float = 0.1, + relax_atoms: bool = True, relax_cell: bool = True, cell_filter: Filter = FrechetCellFilter, ) -> None: @@ -90,6 +91,7 @@ def __init__( interval (int): The step interval for saving the trajectories. Defaults to 1. fmax (float): Total force tolerance for relaxation convergence. fmax is a sum of force and stress forces. Defaults to 0.1 (eV/A). + relax_atoms (bool): Whether to relax the atoms (or just static calculation). relax_cell (bool): Whether to relax the cell (or just atoms). cell_filter (Filter): The ASE Filter used to relax the cell. Default is FrechetCellFilter. @@ -103,6 +105,7 @@ def __init__( self.interval = interval self.max_steps = max_steps self.traj_file = traj_file + self.relax_atoms = relax_atoms self.relax_cell = relax_cell self.cell_filter = cell_filter @@ -113,8 +116,8 @@ def calc(self, structure: Structure) -> dict: structure: Pymatgen structure. Returns: { - final_structure: final_structure, - energy: trajectory observer final energy in eV, + final_structure: final structure, + energy: static energy or trajectory observer final energy in eV, volume: lattice.volume in A^3, a: lattice.a in A, b: lattice.b in A, @@ -126,26 +129,30 @@ def calc(self, structure: Structure) -> dict: """ atoms = AseAtomsAdaptor.get_atoms(structure) atoms.calc = self.calculator - stream = io.StringIO() - with contextlib.redirect_stdout(stream): - obs = TrajectoryObserver(atoms) + if self.relax_atoms: + stream = io.StringIO() + with contextlib.redirect_stdout(stream): + obs = TrajectoryObserver(atoms) + if self.relax_cell: + atoms = self.cell_filter(atoms) + optimizer = self.optimizer(atoms) + optimizer.attach(obs, interval=self.interval) + optimizer.run(fmax=self.fmax, steps=self.max_steps) + if self.traj_file is not None: + obs() + obs.save(self.traj_file) if self.relax_cell: - atoms = self.cell_filter(atoms) - optimizer = self.optimizer(atoms) - optimizer.attach(obs, interval=self.interval) - optimizer.run(fmax=self.fmax, steps=self.max_steps) - if self.traj_file is not None: - obs() - obs.save(self.traj_file) - if self.relax_cell: - atoms = atoms.atoms - + atoms = atoms.atoms + energy = obs.energies[-1] + else: + energy = atoms.get_potential_energy() + final_structure = AseAtomsAdaptor.get_structure(atoms) lattice = final_structure.lattice return { "final_structure": final_structure, - "energy": obs.energies[-1], + "energy": energy, "a": lattice.a, "b": lattice.b, "c": lattice.c, From 690c60a45898c81b42516fa0b26a6ce90a64faa5 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Sun, 11 Aug 2024 18:25:21 -0700 Subject: [PATCH 02/10] fix the ruff Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- matcalc/relaxation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matcalc/relaxation.py b/matcalc/relaxation.py index ba242f1..14bc219 100644 --- a/matcalc/relaxation.py +++ b/matcalc/relaxation.py @@ -146,7 +146,7 @@ def calc(self, structure: Structure) -> dict: energy = obs.energies[-1] else: energy = atoms.get_potential_energy() - + final_structure = AseAtomsAdaptor.get_structure(atoms) lattice = final_structure.lattice From ac83ed8a06d7076273ea374100aecb3f55765432 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:17:39 -0700 Subject: [PATCH 03/10] Calculate forces and stress Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- matcalc/relaxation.py | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/matcalc/relaxation.py b/matcalc/relaxation.py index 14bc219..7a6fbca 100644 --- a/matcalc/relaxation.py +++ b/matcalc/relaxation.py @@ -105,8 +105,8 @@ def __init__( self.interval = interval self.max_steps = max_steps self.traj_file = traj_file - self.relax_atoms = relax_atoms self.relax_cell = relax_cell + self.relax_atoms = relax_atoms self.cell_filter = cell_filter def calc(self, structure: Structure) -> dict: @@ -116,8 +116,10 @@ def calc(self, structure: Structure) -> dict: structure: Pymatgen structure. Returns: { - final_structure: final structure, + final_structure: final_structure, energy: static energy or trajectory observer final energy in eV, + forces: forces in eV/A, + stress: stress in eV/A^3, volume: lattice.volume in A^3, a: lattice.a in A, b: lattice.b in A, @@ -144,20 +146,27 @@ def calc(self, structure: Structure) -> dict: if self.relax_cell: atoms = atoms.atoms energy = obs.energies[-1] + final_structure = AseAtomsAdaptor.get_structure(atoms) + lattice = final_structure.lattice + + return { + "final_structure": final_structure, + "energy": energy, + "a": lattice.a, + "b": lattice.b, + "c": lattice.c, + "alpha": lattice.alpha, + "beta": lattice.beta, + "gamma": lattice.gamma, + "volume": lattice.volume, + } else: energy = atoms.get_potential_energy() - - final_structure = AseAtomsAdaptor.get_structure(atoms) - lattice = final_structure.lattice - - return { - "final_structure": final_structure, - "energy": energy, - "a": lattice.a, - "b": lattice.b, - "c": lattice.c, - "alpha": lattice.alpha, - "beta": lattice.beta, - "gamma": lattice.gamma, - "volume": lattice.volume, - } + forces = atoms.get_forces() + stresses = atoms.get_stress() + + return { + "energy": energy, + "forces": forces, + "stress": stresses, + } From e9b745ae82576ac9de83c6b5f52be6d0a7cf4d52 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:24:14 -0700 Subject: [PATCH 04/10] fix the ruff Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- matcalc/relaxation.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/matcalc/relaxation.py b/matcalc/relaxation.py index 7a6fbca..25429f1 100644 --- a/matcalc/relaxation.py +++ b/matcalc/relaxation.py @@ -160,13 +160,13 @@ def calc(self, structure: Structure) -> dict: "gamma": lattice.gamma, "volume": lattice.volume, } - else: - energy = atoms.get_potential_energy() - forces = atoms.get_forces() - stresses = atoms.get_stress() - return { - "energy": energy, - "forces": forces, - "stress": stresses, - } + energy = atoms.get_potential_energy() + forces = atoms.get_forces() + stresses = atoms.get_stress() + + return { + "energy": energy, + "forces": forces, + "stress": stresses, + } From 4709a61f8a960c6cb35c9b372d32683d589793e8 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:37:46 -0700 Subject: [PATCH 05/10] Add unittests for relaxation.py Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- tests/test_relaxation.py | 45 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/test_relaxation.py b/tests/test_relaxation.py index a4dcc98..c30b993 100644 --- a/tests/test_relaxation.py +++ b/tests/test_relaxation.py @@ -16,14 +16,15 @@ @pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.291071), (FrechetCellFilter, 3.288585)]) -def test_relax_calc_single( +def test_relax_calc_relax_cell( Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, cell_filter: Filter, expected_a: float ) -> None: relax_calc = RelaxCalc( - M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", optimizer="FIRE", cell_filter=cell_filter + M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", optimizer="FIRE", cell_filter=cell_filter, relax_atoms=True, relax_cell=True ) result = relax_calc.calc(Li2O) final_struct: Structure = result["final_structure"] + energy: float = result["energy"] missing_keys = {*final_struct.lattice.params_dict} - {*result} assert len(missing_keys) == 0, f"{missing_keys=}" a, b, c, alpha, beta, gamma = final_struct.lattice.parameters @@ -35,8 +36,48 @@ def test_relax_calc_single( assert beta == pytest.approx(60, abs=0.5) assert gamma == pytest.approx(60, abs=0.5) assert final_struct.volume == pytest.approx(a * b * c / 2**0.5, abs=0.1) + assert isinstance(energy, float) +@pytest.mark.parametrize("expected_a", [3.288585]) +def test_relax_calc_relax_atoms( + Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, cell_filter: Filter, expected_a: float +) -> None: + relax_calc = RelaxCalc( + M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", optimizer="FIRE", relax_atoms=True, relax_cell=False + ) + result = relax_calc.calc(Li2O) + final_struct: Structure = result["final_structure"] + energy: float = result["energy"] + missing_keys = {*final_struct.lattice.params_dict} - {*result} + assert len(missing_keys) == 0, f"{missing_keys=}" + a, b, c, alpha, beta, gamma = final_struct.lattice.parameters + + assert a == pytest.approx(expected_a, rel=1e-3) + assert b == pytest.approx(expected_a, rel=1e-3) + assert c == pytest.approx(expected_a, rel=1e-3) + assert alpha == pytest.approx(60, abs=0.5) + assert beta == pytest.approx(60, abs=0.5) + assert gamma == pytest.approx(60, abs=0.5) + assert final_struct.volume == pytest.approx(a * b * c / 2**0.5, abs=0.1) + assert isinstance(energy, float) + +def test_static_calc( + Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, cell_filter: Filter, expected_a: float +) -> None: + relax_calc = RelaxCalc( + M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", relax_atoms=False, relax_cell=False + ) + result = relax_calc.calc(Li2O) + + energy = result["energy"] + forces = result["forces"] + stresses = result["stress"] + + assert isinstance(forces, float) + assert list(forces.shape) == [3, 3] + assert list(stresses.shape) == [6] + @pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.291071), (FrechetCellFilter, 3.288585)]) def test_relax_calc_many(Li2O: Structure, M3GNetCalc: M3GNetCalculator, cell_filter: Filter, expected_a: float) -> None: relax_calc = RelaxCalc(M3GNetCalc, optimizer="FIRE", cell_filter=cell_filter) From a48f0c038b238f01d8d98a655ae5de5c8dce11b0 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:53:06 -0700 Subject: [PATCH 06/10] fix the ruff Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- tests/test_relaxation.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_relaxation.py b/tests/test_relaxation.py index c30b993..829db62 100644 --- a/tests/test_relaxation.py +++ b/tests/test_relaxation.py @@ -12,6 +12,7 @@ from ase.filters import Filter from matgl.ext.ase import M3GNetCalculator + from numpy.typing import ArrayLike from pymatgen.core import Structure @@ -41,7 +42,7 @@ def test_relax_calc_relax_cell( @pytest.mark.parametrize("expected_a", [3.288585]) def test_relax_calc_relax_atoms( - Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, cell_filter: Filter, expected_a: float + Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, expected_a: float ) -> None: relax_calc = RelaxCalc( M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", optimizer="FIRE", relax_atoms=True, relax_cell=False @@ -63,16 +64,16 @@ def test_relax_calc_relax_atoms( assert isinstance(energy, float) def test_static_calc( - Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, cell_filter: Filter, expected_a: float + Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path ) -> None: relax_calc = RelaxCalc( M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", relax_atoms=False, relax_cell=False ) result = relax_calc.calc(Li2O) - energy = result["energy"] - forces = result["forces"] - stresses = result["stress"] + energy: float = result["energy"] + forces: ArrayLike = result["forces"] + stresses: ArrayLike = result["stress"] assert isinstance(forces, float) assert list(forces.shape) == [3, 3] From 266da494232a7a386a351425ab5bd48d843c2f12 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:59:56 -0700 Subject: [PATCH 07/10] fix the ruff Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- tests/test_relaxation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_relaxation.py b/tests/test_relaxation.py index 829db62..d42c349 100644 --- a/tests/test_relaxation.py +++ b/tests/test_relaxation.py @@ -75,7 +75,7 @@ def test_static_calc( forces: ArrayLike = result["forces"] stresses: ArrayLike = result["stress"] - assert isinstance(forces, float) + assert isinstance(energy, float) assert list(forces.shape) == [3, 3] assert list(stresses.shape) == [6] From a2a03764b7d19adc01ca9502e81f4b3d44fb86b6 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:00:03 -0700 Subject: [PATCH 08/10] assert efs based on value Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- tests/test_relaxation.py | 68 ++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/tests/test_relaxation.py b/tests/test_relaxation.py index d42c349..96256b9 100644 --- a/tests/test_relaxation.py +++ b/tests/test_relaxation.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING +import numpy as np import pytest from ase.filters import ExpCellFilter, FrechetCellFilter @@ -12,16 +13,29 @@ from ase.filters import Filter from matgl.ext.ase import M3GNetCalculator - from numpy.typing import ArrayLike + from nuampy.typing import ArrayLike from pymatgen.core import Structure -@pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.291071), (FrechetCellFilter, 3.288585)]) +@pytest.mark.parametrize( + ("cell_filter", "expected_a", "expected_energy"), + [(ExpCellFilter, 3.288585, -14.176882), (FrechetCellFilter, 3.291071, -14.176743)], +) def test_relax_calc_relax_cell( - Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, cell_filter: Filter, expected_a: float + Li2O: Structure, + M3GNetCalc: M3GNetCalculator, + tmp_path: Path, + cell_filter: Filter, + expected_a: float, + expected_energy: float, ) -> None: relax_calc = RelaxCalc( - M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", optimizer="FIRE", cell_filter=cell_filter, relax_atoms=True, relax_cell=True + M3GNetCalc, + traj_file=f"{tmp_path}/li2o_relax.txt", + optimizer="FIRE", + cell_filter=cell_filter, + relax_atoms=True, + relax_cell=True, ) result = relax_calc.calc(Li2O) final_struct: Structure = result["final_structure"] @@ -30,6 +44,7 @@ def test_relax_calc_relax_cell( assert len(missing_keys) == 0, f"{missing_keys=}" a, b, c, alpha, beta, gamma = final_struct.lattice.parameters + assert energy == pytest.approx(expected_energy, rel=1e-3) assert a == pytest.approx(expected_a, rel=1e-3) assert b == pytest.approx(expected_a, rel=1e-3) assert c == pytest.approx(expected_a, rel=1e-3) @@ -37,12 +52,11 @@ def test_relax_calc_relax_cell( assert beta == pytest.approx(60, abs=0.5) assert gamma == pytest.approx(60, abs=0.5) assert final_struct.volume == pytest.approx(a * b * c / 2**0.5, abs=0.1) - assert isinstance(energy, float) -@pytest.mark.parametrize("expected_a", [3.288585]) +@pytest.mark.parametrize(("expected_a", "expected_energy"), [(3.291071, -14.1767423)]) def test_relax_calc_relax_atoms( - Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, expected_a: float + Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, expected_a: float, expected_energy: float ) -> None: relax_calc = RelaxCalc( M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", optimizer="FIRE", relax_atoms=True, relax_cell=False @@ -54,6 +68,7 @@ def test_relax_calc_relax_atoms( assert len(missing_keys) == 0, f"{missing_keys=}" a, b, c, alpha, beta, gamma = final_struct.lattice.parameters + assert energy == pytest.approx(expected_energy, rel=1e-3) assert a == pytest.approx(expected_a, rel=1e-3) assert b == pytest.approx(expected_a, rel=1e-3) assert c == pytest.approx(expected_a, rel=1e-3) @@ -61,25 +76,46 @@ def test_relax_calc_relax_atoms( assert beta == pytest.approx(60, abs=0.5) assert gamma == pytest.approx(60, abs=0.5) assert final_struct.volume == pytest.approx(a * b * c / 2**0.5, abs=0.1) - assert isinstance(energy, float) + +@pytest.mark.parametrize( + ("expected_energy", "expected_forces", "expected_stress"), + [ + ( + -14.176743, + np.array( + [ + [-4.252263e-03, -3.029412e-03, -7.360560e-03], + [4.272716e-03, 3.017864e-03, 7.360807e-03], + [-2.035008e-05, 1.152878e-05, -2.714805e-07], + ], + dtype=np.float32, + ), + np.array([0.003945, 0.004185, 0.003000, -0.000584, -0.000826, -0.000337], dtype=np.float32), + ), + ], +) def test_static_calc( - Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path + Li2O: Structure, + M3GNetCalc: M3GNetCalculator, + tmp_path: Path, + expected_energy: float, + expected_forces: ArrayLike, + expected_stresses: ArrayLike, ) -> None: - relax_calc = RelaxCalc( - M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", relax_atoms=False, relax_cell=False - ) + relax_calc = RelaxCalc(M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", relax_atoms=False, relax_cell=False) result = relax_calc.calc(Li2O) energy: float = result["energy"] forces: ArrayLike = result["forces"] stresses: ArrayLike = result["stress"] - assert isinstance(energy, float) - assert list(forces.shape) == [3, 3] - assert list(stresses.shape) == [6] + assert energy == pytest.approx(expected_energy, rel=1e-3) + assert np.allclose(forces, expected_forces, rtol=1e-3) + assert np.allclose(stresses, expected_stresses, rtol=1e-3) + -@pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.291071), (FrechetCellFilter, 3.288585)]) +@pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.288585), (FrechetCellFilter, 3.291071)]) def test_relax_calc_many(Li2O: Structure, M3GNetCalc: M3GNetCalculator, cell_filter: Filter, expected_a: float) -> None: relax_calc = RelaxCalc(M3GNetCalc, optimizer="FIRE", cell_filter=cell_filter) results = list(relax_calc.calc_many([Li2O] * 2)) From 26a45b2032bf04a37ff2853c3dfb4da42f72216e Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:08:06 -0700 Subject: [PATCH 09/10] fix the pytest Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- tests/test_relaxation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_relaxation.py b/tests/test_relaxation.py index 96256b9..b678d24 100644 --- a/tests/test_relaxation.py +++ b/tests/test_relaxation.py @@ -79,7 +79,7 @@ def test_relax_calc_relax_atoms( @pytest.mark.parametrize( - ("expected_energy", "expected_forces", "expected_stress"), + ("expected_energy", "expected_forces", "expected_stresses"), [ ( -14.176743, From 2e3b2c3ba15a54b0f61708a07ab72433a81c4010 Mon Sep 17 00:00:00 2001 From: Runze Liu <146490083+rul048@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:54:07 -0700 Subject: [PATCH 10/10] fix the pytest Signed-off-by: Runze Liu <146490083+rul048@users.noreply.github.com> --- tests/test_relaxation.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/test_relaxation.py b/tests/test_relaxation.py index b678d24..7b2cbfc 100644 --- a/tests/test_relaxation.py +++ b/tests/test_relaxation.py @@ -19,7 +19,7 @@ @pytest.mark.parametrize( ("cell_filter", "expected_a", "expected_energy"), - [(ExpCellFilter, 3.288585, -14.176882), (FrechetCellFilter, 3.291071, -14.176743)], + [(ExpCellFilter, 3.288585, -14.176867), (FrechetCellFilter, 3.291072, -14.176713)], ) def test_relax_calc_relax_cell( Li2O: Structure, @@ -54,7 +54,7 @@ def test_relax_calc_relax_cell( assert final_struct.volume == pytest.approx(a * b * c / 2**0.5, abs=0.1) -@pytest.mark.parametrize(("expected_a", "expected_energy"), [(3.291071, -14.1767423)]) +@pytest.mark.parametrize(("expected_a", "expected_energy"), [(3.291072, -14.176713)]) def test_relax_calc_relax_atoms( Li2O: Structure, M3GNetCalc: M3GNetCalculator, tmp_path: Path, expected_a: float, expected_energy: float ) -> None: @@ -82,28 +82,27 @@ def test_relax_calc_relax_atoms( ("expected_energy", "expected_forces", "expected_stresses"), [ ( - -14.176743, + -14.176713, np.array( [ - [-4.252263e-03, -3.029412e-03, -7.360560e-03], - [4.272716e-03, 3.017864e-03, 7.360807e-03], - [-2.035008e-05, 1.152878e-05, -2.714805e-07], + [6.577218e-06, 1.851469e-06, -7.080846e-06], + [-4.507415e-03, -3.310852e-03, -7.090813e-03], + [4.500971e-03, 3.309000e-03, 7.097944e-03], ], dtype=np.float32, ), - np.array([0.003945, 0.004185, 0.003000, -0.000584, -0.000826, -0.000337], dtype=np.float32), + np.array([0.003883, 0.004126, 0.003089, -0.000617, -0.000839, -0.000391], dtype=np.float32), ), ], ) def test_static_calc( Li2O: Structure, M3GNetCalc: M3GNetCalculator, - tmp_path: Path, expected_energy: float, expected_forces: ArrayLike, expected_stresses: ArrayLike, ) -> None: - relax_calc = RelaxCalc(M3GNetCalc, traj_file=f"{tmp_path}/li2o_relax.txt", relax_atoms=False, relax_cell=False) + relax_calc = RelaxCalc(M3GNetCalc, relax_atoms=False, relax_cell=False) result = relax_calc.calc(Li2O) energy: float = result["energy"] @@ -115,7 +114,7 @@ def test_static_calc( assert np.allclose(stresses, expected_stresses, rtol=1e-3) -@pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.288585), (FrechetCellFilter, 3.291071)]) +@pytest.mark.parametrize(("cell_filter", "expected_a"), [(ExpCellFilter, 3.288585), (FrechetCellFilter, 3.291072)]) def test_relax_calc_many(Li2O: Structure, M3GNetCalc: M3GNetCalculator, cell_filter: Filter, expected_a: float) -> None: relax_calc = RelaxCalc(M3GNetCalc, optimizer="FIRE", cell_filter=cell_filter) results = list(relax_calc.calc_many([Li2O] * 2))