From 4d87d1b88a3992a27834ab973d0a73df53bb9707 Mon Sep 17 00:00:00 2001 From: Lauri Himanen Date: Fri, 21 Feb 2025 22:56:53 +0200 Subject: [PATCH 1/2] Added support for numpy>2.0, and spglib>2.0, fixed warnings with docstring. --- docs/assets/conventional_cell_comparison.py | 6 +- matid/symmetry/symmetryanalyzer.py | 57 +++++++++++-------- .../query_conventional_transform_info.py | 4 +- .../query_space_group_info.py | 6 +- pyproject.toml | 8 +-- tests/clustering/test_sbc.py | 2 + 6 files changed, 48 insertions(+), 35 deletions(-) diff --git a/docs/assets/conventional_cell_comparison.py b/docs/assets/conventional_cell_comparison.py index d50cd464..7e3c5c12 100644 --- a/docs/assets/conventional_cell_comparison.py +++ b/docs/assets/conventional_cell_comparison.py @@ -14,9 +14,9 @@ def get_spglib_conventional(system): dataset = spglib.get_symmetry_dataset(cell) return Atoms( - symbols=dataset["std_types"], - scaled_positions=dataset["std_positions"], - cell=dataset["std_lattice"], + symbols=dataset.std_types, + scaled_positions=dataset.std_positions, + cell=dataset.std_lattice, ) # Lets define two variants of NaCl in rocksalt structure diff --git a/matid/symmetry/symmetryanalyzer.py b/matid/symmetry/symmetryanalyzer.py index 2b44b38d..9518b25f 100644 --- a/matid/symmetry/symmetryanalyzer.py +++ b/matid/symmetry/symmetryanalyzer.py @@ -18,6 +18,12 @@ from ase import Atoms +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + + class SymmetryAnalyzer(object): """A base class for getting symmetry related properties of unit cells.""" @@ -144,7 +150,7 @@ def get_space_group_number(self): int: The space group number. """ dataset = self.get_symmetry_dataset() - value = dataset["number"] + value = dataset.number return value @@ -154,7 +160,7 @@ def get_space_group_international_short(self): str: The international space group short symbol. """ dataset = self.get_symmetry_dataset() - value = dataset["international"] + value = dataset.international return value @@ -164,7 +170,7 @@ def get_hall_symbol(self): str: The Hall symbol. """ dataset = self.get_symmetry_dataset() - value = dataset["hall"] + value = dataset.hall return value @@ -174,7 +180,7 @@ def get_hall_number(self): int: The Hall number. """ dataset = self.get_symmetry_dataset() - value = dataset["hall_number"] + value = dataset.hall_number return value @@ -186,7 +192,7 @@ def get_point_group(self): str: point group symbol """ dataset = self.get_symmetry_dataset() - value = dataset["pointgroup"] + value = dataset.pointgroup return value @@ -367,7 +373,7 @@ def get_conventional_system(self): # The index of the originally non-periodic dimension may not correspond # to the one in the normalized system, because the normalized system # may use a different coordinate system. - transformation_matrix = self.get_symmetry_dataset()["transformation_matrix"] + transformation_matrix = self.get_symmetry_dataset().transformation_matrix nonperiodic_axis = None prec = 1e-8 for i_axis, axis in enumerate(transformation_matrix): @@ -448,7 +454,7 @@ def get_rotations(self): np.ndarray: Rotation matrices. """ dataset = self.get_symmetry_dataset() - value = dataset["rotations"] + value = dataset.rotations return value @@ -461,7 +467,7 @@ def get_translations(self): np.ndarray: Translation vectors. """ dataset = self.get_symmetry_dataset() - value = dataset["translations"] + value = dataset.translations return value @@ -472,7 +478,7 @@ def get_choice(self): settings. """ dataset = self.get_symmetry_dataset() - value = dataset["choice"] + value = dataset.choice return value @@ -595,6 +601,11 @@ def get_symmetry_dataset(self): if symmetry_dataset is None: raise CellNormalizationError("Spglib error when finding symmetry dataset.") + # Prior to spglib 2.5.0 the dataset is returned as a dictionary: this + # provides backwards compatibility + if isinstance(symmetry_dataset, dict): + symmetry_dataset = AttrDict(symmetry_dataset) + self._symmetry_dataset = symmetry_dataset return symmetry_dataset @@ -610,9 +621,9 @@ def _get_spglib_conventional_system(self): return self._spglib_conventional_system dataset = self.get_symmetry_dataset() - cell = dataset["std_lattice"] - pos = dataset["std_positions"] - num = dataset["std_types"] + cell = dataset.std_lattice + pos = dataset.std_positions + num = dataset.std_types spg_conv_sys = self._spglib_description_to_system((cell, pos, num)) self._spglib_conventional_system = spg_conv_sys @@ -624,7 +635,7 @@ def _get_spglib_wyckoff_letters_original(self): list of str: Wyckoff letters for the atoms in the original system. """ dataset = self.get_symmetry_dataset() - value = np.array(dataset["wyckoffs"]) + value = np.array(dataset.wyckoffs) return value @@ -640,7 +651,7 @@ def _get_spglib_equivalent_atoms_original(self): # equivalent atoms reported by spglib are based on the symmetry of the # original cell. Equivalence in crystallographic_orbits is instead # based on the primitive cell/conventional cell which is what we want. - value = dataset["crystallographic_orbits"] + value = dataset.crystallographic_orbits return value @@ -653,7 +664,7 @@ def _get_spglib_wyckoff_letters_conventional(self): if self._spglib_wyckoff_letters_conventional is None: wyckoff_letters_primitive = self._get_spglib_wyckoff_letters_primitive() dataset = self.get_symmetry_dataset() - mapping = dataset["std_mapping_to_primitive"] + mapping = dataset.std_mapping_to_primitive self._spglib_wyckoff_letters_conventional = wyckoff_letters_primitive[ mapping ] @@ -668,7 +679,7 @@ def _get_spglib_equivalent_atoms_conventional(self): if self._spglib_equivalent_atoms_conventional is None: equivalent_atoms_primitive = self._get_spglib_equivalent_atoms_primitive() dataset = self.get_symmetry_dataset() - mapping = dataset["std_mapping_to_primitive"] + mapping = dataset.std_mapping_to_primitive self._spglib_equivalent_atoms_conventional = equivalent_atoms_primitive[ mapping ] @@ -690,7 +701,7 @@ def _get_spglib_origin_shift(self): 3*1 np.ndarray: The shift of the origin as a vector. """ dataset = self.get_symmetry_dataset() - value = dataset["origin_shift"] + value = dataset.origin_shift return value @@ -707,8 +718,8 @@ def get_symmetry_operations(self): """ dataset = self.get_symmetry_dataset() operations = { - "rotations": dataset["rotations"], - "translations": dataset["translations"], + "rotations": dataset.rotations, + "translations": dataset.translations, } return operations @@ -728,7 +739,7 @@ def _get_spglib_transformation_matrix(self): 3x3 np.ndarray: """ dataset = self.get_symmetry_dataset() - value = dataset["transformation_matrix"] + value = dataset.transformation_matrix return value @@ -802,7 +813,7 @@ def _get_spglib_primitive_to_original_mapping(self): """ if self._spglib_primitive_to_original_mapping is None: dataset = self.get_symmetry_dataset() - mapping = dataset["mapping_to_primitive"] + mapping = dataset.mapping_to_primitive _, indices = np.unique(mapping, return_index=True) self._spglib_primitive_to_original_mapping = indices @@ -896,7 +907,7 @@ def _get_primitive_system( # Keep one occurrence for each atom that should be within the cell and # wrap it's position to tbe inside the primitive cell. conv_num = conv_system.get_atomic_numbers() - conv_to_prim_map = self._symmetry_dataset["std_mapping_to_primitive"] + conv_to_prim_map = self._symmetry_dataset.std_mapping_to_primitive _, inside_mask = np.unique(conv_to_prim_map, return_index=True) prim_pos = prim_pos[inside_mask] prim_num = conv_num[inside_mask] @@ -1204,7 +1215,7 @@ def _get_wyckoff_sets( precision, return_parameters, ): - """Used to get detailed information about about the sets of equivalent + r"""Used to get detailed information about about the sets of equivalent atoms. The detected Wyckoff set variables (x, y, z) are reported consistenly by selecting the variable sets that has lowest x value, then lowest y and finally lowest z. diff --git a/matid/utils/symmetry_info_generation/query_conventional_transform_info.py b/matid/utils/symmetry_info_generation/query_conventional_transform_info.py index 8b26ed01..a8813034 100644 --- a/matid/utils/symmetry_info_generation/query_conventional_transform_info.py +++ b/matid/utils/symmetry_info_generation/query_conventional_transform_info.py @@ -15,7 +15,7 @@ for hall_number in range(1, 531): dataset = spglib.get_spacegroup_type(hall_number) - number = dataset["number"] + number = dataset.number space_hall_map[number].append(hall_number) degenerate_spgs = [] @@ -26,7 +26,7 @@ degenerate_spgs.append(key) first_hall = value[0] dataset = spglib.get_spacegroup_type(first_hall) - choice = dataset["choice"] + choice = dataset.choice # try: # origin = int(choice) diff --git a/matid/utils/symmetry_info_generation/query_space_group_info.py b/matid/utils/symmetry_info_generation/query_space_group_info.py index 5fe80b5f..b7c7cb5b 100644 --- a/matid/utils/symmetry_info_generation/query_space_group_info.py +++ b/matid/utils/symmetry_info_generation/query_space_group_info.py @@ -12,8 +12,8 @@ for hall_number in range(1, 531): dataset = spglib.get_spacegroup_type(hall_number) - number = dataset["number"] - international_short = dataset["international_short"] + number = dataset.number + international_short = dataset.international_short # Check that the spglib data has no two different international symbols for # the same space group number @@ -28,7 +28,7 @@ # Point group. There actually seeems to be a bug in spglib 1.9.4, where # the Hermann-Mauguin point group symbol is in the plalce of Schonflies # data and vice versa. - pointgroup = dataset["pointgroup_schoenflies"] + pointgroup = dataset.pointgroup_schoenflies space_group_database[number]["pointgroup"] = pointgroup # Crystal system diff --git a/pyproject.toml b/pyproject.toml index 5eb75ce9..34356f9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,19 @@ [build-system] -requires = ["setuptools", "wheel", "pybind11~=2.11.1"] +requires = ["setuptools", "wheel", "pybind11~=2.13.6"] build-backend = "setuptools.build_meta" [project] name = 'matid' -version = '2.1.4' +version = '2.1.5' description = 'MatID is a Python package for identifying and analyzing atomistic systems based on their structure.' readme = "README.md" authors = [{ name = "Lauri Himanen" }] license = { file = "LICENSE" } requires-python = ">=3.8" dependencies = [ - "numpy<2.0.0", + "numpy", "ase", - "spglib>=1.15.0", + "spglib>=2.0.0", "scikit-learn", "networkx>=2.4", ] diff --git a/tests/clustering/test_sbc.py b/tests/clustering/test_sbc.py index ea07f7cd..9dc8c95d 100644 --- a/tests/clustering/test_sbc.py +++ b/tests/clustering/test_sbc.py @@ -10,6 +10,8 @@ from conftest import surface, stack, rattle, assert_topology, create_graphene, create_fe from matid.clustering import SBC, Cluster +import numpy as np +# np._set_promotion_state("weak_and_warn") surface_fcc = surface(bulk("Cu", "fcc", a=3.6, cubic=True), [1, 0, 0], vacuum=10) surface_rocksalt = surface( From 8229da4130c19d31d9d9dbb8a832ac34cf5d3e3b Mon Sep 17 00:00:00 2001 From: Lauri Himanen Date: Fri, 21 Feb 2025 23:06:19 +0200 Subject: [PATCH 2/2] Remove unused imports. --- tests/clustering/test_sbc.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/clustering/test_sbc.py b/tests/clustering/test_sbc.py index 9dc8c95d..ea07f7cd 100644 --- a/tests/clustering/test_sbc.py +++ b/tests/clustering/test_sbc.py @@ -10,8 +10,6 @@ from conftest import surface, stack, rattle, assert_topology, create_graphene, create_fe from matid.clustering import SBC, Cluster -import numpy as np -# np._set_promotion_state("weak_and_warn") surface_fcc = surface(bulk("Cu", "fcc", a=3.6, cubic=True), [1, 0, 0], vacuum=10) surface_rocksalt = surface(