diff --git a/.github/workflows/ci-python.yaml b/.github/workflows/ci-python.yaml index 87d9eba..773e814 100644 --- a/.github/workflows/ci-python.yaml +++ b/.github/workflows/ci-python.yaml @@ -44,7 +44,7 @@ jobs: run: | set -e pip install moyopy --no-index --find-links dist - pip install -r moyopy/examples/requirements.txt + pip install moyopy[interface] python moyopy/examples/basic.py python moyopy/examples/pymatgen_structure.py diff --git a/moyopy/README.md b/moyopy/README.md index 0567de5..6a0c806 100644 --- a/moyopy/README.md +++ b/moyopy/README.md @@ -6,6 +6,14 @@ Python interface of Moyo +## Installation + +```shell +pip install moyopy +# If you want to convert structures into Pymatgen or ASE objects +pip install moyopy[interface] +``` + ## Examples See [example directory](examples) diff --git a/moyopy/examples/pymatgen_structure.py b/moyopy/examples/pymatgen_structure.py index 265b700..0f86790 100644 --- a/moyopy/examples/pymatgen_structure.py +++ b/moyopy/examples/pymatgen_structure.py @@ -1,28 +1,10 @@ from __future__ import annotations import numpy as np -from pymatgen.core import Element, Structure +from pymatgen.core import Structure import moyopy - - -class MoyoAdapter: - @staticmethod - def get_structure(cell: moyopy.Cell) -> Structure: - species = [Element.from_Z(number) for number in cell.numbers] - return Structure(lattice=cell.basis, species=species, coords=cell.positions) - - @staticmethod - def get_moyo_cell(structure: Structure) -> moyopy.Cell: - basis = structure.lattice.matrix - positions = structure.frac_coords - numbers = [site.specie.Z for site in structure] - - return moyopy.Cell( - basis=basis.tolist(), - positions=positions.tolist(), - numbers=numbers, - ) +from moyopy.interface import MoyoAdapter class MoyoSpacegroupAnalyzer: @@ -33,7 +15,7 @@ def __init__( angle_tolerance: float | None = None, setting: moyopy.Setting | None = None, ): - self._cell = MoyoAdapter.get_moyo_cell(structure) + self._cell = MoyoAdapter.from_structure(structure) self._dataset = moyopy.MoyoDataset( cell=self._cell, symprec=symprec, diff --git a/moyopy/examples/requirements.txt b/moyopy/examples/requirements.txt deleted file mode 100644 index aac465e..0000000 --- a/moyopy/examples/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -numpy<2 -pymatgen diff --git a/moyopy/pyproject.toml b/moyopy/pyproject.toml index f9a3ad6..d6c7c9c 100644 --- a/moyopy/pyproject.toml +++ b/moyopy/pyproject.toml @@ -30,10 +30,15 @@ classifiers = [ ] [project.optional-dependencies] +interface = [ + "numpy<2", # pymatgen seems to be still imcompatible with numpy>=2 + "pymatgen", + "ase>=3.23", +] dev = [ + "moyopy[interface]", "pytest", "pre-commit", - "numpy", ] [tool.maturin] diff --git a/moyopy/python/moyopy/interface.py b/moyopy/python/moyopy/interface.py new file mode 100644 index 0000000..6cf7dfd --- /dev/null +++ b/moyopy/python/moyopy/interface.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +try: + import ase + from pymatgen.core import Element, Structure +except ImportError: + raise ImportError("Try installing dependencies with `pip install moyopy[interface]`") + +import moyopy + + +class MoyoAdapter: + @staticmethod + def get_structure(cell: moyopy.Cell) -> Structure: + species = [Element.from_Z(number) for number in cell.numbers] + return Structure(lattice=cell.basis, species=species, coords=cell.positions) + + @staticmethod + def get_atoms(cell: moyopy.Cell) -> ase.Atoms: + atoms = ase.Atoms( + cell=cell.basis, + scaled_positions=cell.positions, + numbers=cell.numbers, + pbc=True, + ) + return atoms + + @staticmethod + def from_structure(structure: Structure) -> moyopy.Cell: + basis = structure.lattice.matrix + positions = structure.frac_coords + numbers = [site.specie.Z for site in structure] + + return moyopy.Cell( + basis=basis.tolist(), + positions=positions.tolist(), + numbers=numbers, + ) + + @staticmethod + def from_atoms(atoms: ase.Atoms) -> moyopy.Cell: + basis = list(atoms.cell) + positions = atoms.get_scaled_positions() + numbers = atoms.get_atomic_numbers() + + return moyopy.Cell( + basis=basis, + positions=positions, + numbers=numbers, + ) diff --git a/moyopy/python/tests/conftest.py b/moyopy/python/tests/conftest.py index 55d8e0a..5a0f8bd 100644 --- a/moyopy/python/tests/conftest.py +++ b/moyopy/python/tests/conftest.py @@ -25,7 +25,7 @@ def wurtzite() -> moyopy.Cell: [1 / 3, 2 / 3, z2_2b], [2 / 3, 1 / 3, z2_2b + 0.5], ] - numbers = [0, 0, 1, 1] + numbers = [1, 1, 2, 2] cell = moyopy.Cell(basis, positions, numbers) return cell diff --git a/moyopy/python/tests/test_interface.py b/moyopy/python/tests/test_interface.py new file mode 100644 index 0000000..53d1740 --- /dev/null +++ b/moyopy/python/tests/test_interface.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +import numpy as np + +import moyopy +from moyopy.interface import MoyoAdapter + + +def test_pymatgen_moyopy(wurtzite: moyopy.Cell): + structure = MoyoAdapter.get_structure(wurtzite) + cell = MoyoAdapter.from_structure(structure) + assert np.allclose(cell.basis, wurtzite.basis) + assert np.allclose(cell.positions, wurtzite.positions) + assert cell.numbers == wurtzite.numbers + + +def test_ase_moyopy(wurtzite: moyopy.Cell): + atoms = MoyoAdapter.get_atoms(wurtzite) + cell = MoyoAdapter.from_atoms(atoms) + assert np.allclose(cell.basis, wurtzite.basis) + assert np.allclose(cell.positions, wurtzite.positions) + assert cell.numbers == wurtzite.numbers