Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ASE #181

Merged
merged 7 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ pre-commit install # install pre-commit hooks
pytest -v # discover and run all tests
```

Manually updating ASE via https://gitlab.com/ase/ase is strongly recommended, as tags are no longer regularly published. For example:

```shell
pip install git+https://gitlab.com/ase/ase.git@b31569210d739bd12c8ad2b6ec0290108e049eea
```

To prevent poetry downgrading ASE when installing in future, add the commit to pyproject.toml:

```shell
poetry add git+https://gitlab.com:ase/ase.git#b31569210d739bd12c8ad2b6ec0290108e049eea
```
> [!NOTE]
> Manually updating ASE via https://gitlab.com/ase/ase is strongly recommended, as tags may not regularly be published. For example:
> ```shell
> pip install git+https://gitlab.com/ase/ase.git@master
> ```
>
> To prevent poetry downgrading ASE when installing in future, add the repository to pyproject.toml:
>
> ```shell
> poetry add git+https://gitlab.com:ase/ase.git#master
> ```

## Examples

Expand Down
28 changes: 9 additions & 19 deletions janus_core/calculations/geom_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,12 @@
from typing import Any, Callable, Optional, Union
import warnings

from ase import Atoms
from ase import Atoms, filters
from ase.filters import FrechetCellFilter
from ase.io import read, write
import ase.optimize
from ase.optimize import LBFGS
from ase.optimize.optimize import Optimizer

try:
from ase import filters
from ase.filters import FrechetCellFilter as DefaultFilter
except ImportError:
import ase.constraints as filters
from ase.constraints import ExpCellFilter as DefaultFilter

from numpy import linalg

from janus_core.helpers.janus_types import ASEOptArgs, ASEWriteArgs
Expand All @@ -36,8 +29,7 @@ def _set_functions(
optimizer : Union[Callable, str]
Optimization function, or name of function from ase.optimize.
filter_func : Optional[Union[Callable], str]]
ASE filter function, or name of function from ase.filters or ase.constraints.
Default is None.
ASE filter function, or name of function from ase.filters. Default is None.

Returns
-------
Expand All @@ -61,7 +53,7 @@ def _set_functions(

def set_optimizer(
struct: Atoms,
filter_func: Optional[Union[Callable, str]] = DefaultFilter,
filter_func: Optional[Union[Callable, str]] = FrechetCellFilter,
filter_kwargs: Optional[dict[str, Any]] = None,
optimizer: Union[Callable, str] = LBFGS,
opt_kwargs: Optional[ASEOptArgs] = None,
Expand All @@ -75,9 +67,8 @@ def set_optimizer(
struct : Atoms
Atoms object to optimize geometry for.
filter_func : Optional[Union[Callable, str]]
Filter function, or name of function from ase.filters or ase.constraints, to
apply constraints to atoms. Default is `FrechetCellFilter` if available
otherwise `ExpCellFilter`.
Filter function, or name of function from ase.filters to apply constraints to
atoms. Default is `FrechetCellFilter`.
filter_kwargs : Optional[dict[str, Any]]
Keyword arguments to pass to filter_func. Default is {}.
optimizer : Union[Callable, str]
Expand Down Expand Up @@ -125,7 +116,7 @@ def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-bra
steps: int = 1000,
symmetry_tolerance: float = 0.001,
angle_tolerance: float = -1.0,
filter_func: Optional[Callable] = DefaultFilter,
filter_func: Optional[Callable] = FrechetCellFilter,
filter_kwargs: Optional[dict[str, Any]] = None,
optimizer: Callable = LBFGS,
opt_kwargs: Optional[ASEOptArgs] = None,
Expand Down Expand Up @@ -153,9 +144,8 @@ def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-bra
Angle precision for spglib symmetry determination, in degrees. Default is -1.0,
which means an internally optimized routine is used to judge symmetry.
filter_func : Optional[Union[Callable, str]]
Filter function, or name of function from ase.filters or ase.constraints, to
apply constraints to atoms. Default is `FrechetCellFilter` if available
otherwise `ExpCellFilter`.
Filter function, or name of function from ase.filters to apply constraints to
atoms. Default is `FrechetCellFilter`.
filter_kwargs : Optional[dict[str, Any]]
Keyword arguments to pass to filter_func. Default is {}.
optimizer : Union[Callable, str]
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ janus = "janus_core.cli.janus:app"

[tool.poetry.dependencies]
python = "^3.9"
ase = "3.22.1"
ase = "^3.23"
mace-torch = "^0.3.4"
pyyaml = "^6.0.1"
typer = "^0.9.0"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_eos_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_eos(tmp_path):
assert lines[0] == "#Lattice Scalar | Energy [eV] | Volume [Å^3] \n"
assert lines[4].split()[0] == "1.0"
assert float(lines[4].split()[1]) == pytest.approx(-27.046359959669214)
assert float(lines[4].split()[2]) == pytest.approx(184.28932483484286)
assert float(lines[4].split()[2]) == pytest.approx(184.05884033013012)

# Check contents of fitted data file
with open(eos_fit_path, encoding="utf8") as eos_fit_file:
Expand Down
29 changes: 25 additions & 4 deletions tests/test_geom_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,22 @@ def test_hydrostatic_strain():
single_point_2.struct, filter_kwargs={"hydrostatic_strain": False}
)

expected_1 = [5.69139709, 5.69139709, 5.69139709, 89.0, 90.0, 90.0]
expected_2 = [5.68834069, 5.68893345, 5.68932555, 89.75938298, 90.0, 90.0]
expected_1 = [
5.687545288920282,
5.687545288920282,
5.687545288920282,
89.0,
90.0,
90.0,
]
expected_2 = [
5.688268799219085,
5.688750772505896,
5.688822747326383,
89.26002493790229,
90.0,
90.0,
]
assert struct_1.cell.cellpar() == pytest.approx(expected_1)
assert struct_2.cell.cellpar() == pytest.approx(expected_2)

Expand Down Expand Up @@ -175,16 +189,23 @@ def test_restart(tmp_path):

init_energy = single_point.run("energy")["energy"]

# Check unconverged warning
with pytest.warns(UserWarning):
optimize(
single_point.struct, steps=2, opt_kwargs={"restart": tmp_path / "NaCl.pkl"}
single_point.struct,
steps=2,
opt_kwargs={"restart": tmp_path / "NaCl.pkl"},
fmax=0.0001,
)

intermediate_energy = single_point.run("energy")["energy"]
assert intermediate_energy < init_energy

optimize(
single_point.struct, steps=2, opt_kwargs={"restart": tmp_path / "NaCl.pkl"}
single_point.struct,
steps=2,
opt_kwargs={"restart": tmp_path / "NaCl.pkl"},
fmax=0.0001,
)
final_energy = single_point.run("energy")["energy"]
assert final_energy < intermediate_energy
Expand Down
20 changes: 17 additions & 3 deletions tests/test_geomopt_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def test_traj(tmp_path):
)
assert result.exit_code == 0
atoms = read(traj_path)
assert "forces" in atoms.arrays
assert "forces" in atoms.calc.results


def test_fully_opt(tmp_path):
Expand Down Expand Up @@ -136,7 +136,14 @@ def test_fully_opt(tmp_path):
)

atoms = read(results_path)
expected = [5.68834069, 5.68893345, 5.68932555, 89.75938298, 90.0, 90.0]
expected = [
5.688268799219085,
5.688750772505896,
5.688822747326383,
89.26002493790229,
90.0,
90.0,
]
assert atoms.cell.cellpar() == pytest.approx(expected)


Expand Down Expand Up @@ -167,7 +174,14 @@ def test_fully_opt_and_vectors(tmp_path):
assert_log_contains(log_path, includes=["Using filter", "hydrostatic_strain: True"])

atoms = read(results_path)
expected = [5.69139709, 5.69139709, 5.69139709, 89.0, 90.0, 90.0]
expected = [
5.687545288920282,
5.687545288920282,
5.687545288920282,
89.0,
90.0,
90.0,
]
assert atoms.cell.cellpar() == pytest.approx(expected)


Expand Down
8 changes: 4 additions & 4 deletions tests/test_single_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,13 @@ def test_single_point_write():
architecture="mace",
calc_kwargs={"model": MODEL_PATH},
)
assert "forces" not in single_point.struct.arrays
assert "forces" not in single_point.struct.calc.results

single_point.run(write_results=True)

atoms = read_atoms(results_path)
assert atoms.get_potential_energy() is not None
assert "forces" in atoms.arrays
assert "forces" in atoms.calc.results


def test_single_point_write_kwargs(tmp_path):
Expand All @@ -123,12 +123,12 @@ def test_single_point_write_kwargs(tmp_path):
architecture="mace",
calc_kwargs={"model": MODEL_PATH},
)
assert "forces" not in single_point.struct.arrays
assert "forces" not in single_point.struct.calc.results

single_point.run(write_results=True, write_kwargs={"filename": results_path})
atoms = read(results_path)
assert atoms.get_potential_energy() is not None
assert "forces" in atoms.arrays
assert "forces" in atoms.calc.results


def test_single_point_write_nan(tmp_path):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_singlepoint_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_singlepoint(tmp_path):
atoms = read_atoms(results_path)
assert result.exit_code == 0
assert atoms.get_potential_energy() is not None
assert "forces" in atoms.arrays
assert "forces" in atoms.calc.results


def test_properties(tmp_path):
Expand Down