matid 2.0.0.dev1__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {matid-2.0.0.dev1 → matid-2.0.1}/MANIFEST.in +1 -0
- {matid-2.0.0.dev1/matid.egg-info → matid-2.0.1}/PKG-INFO +11 -7
- {matid-2.0.0.dev1 → matid-2.0.1}/README.md +2 -2
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/classification/classifier.py +2 -2
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/clustering/sbc.py +154 -156
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/core/linkedunits.py +1 -2
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/core/periodicfinder.py +27 -27
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/data/element_data.py +1 -0
- matid-2.0.1/matid/ext/celllist.h +106 -0
- matid-2.0.1/matid/ext/geometry.h +89 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/geometry/geometry.py +3 -2
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/symmetry/symmetryanalyzer.py +3 -3
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/segfault_protect.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/symmetry_info_generation/generate_symmetry_info.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/symmetry_info_generation/query_continuous_translations.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/symmetry_info_generation/query_conventional_transform_info.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/symmetry_info_generation/query_normalizers.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/symmetry_info_generation/query_space_group_info.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/symmetry_info_generation/query_wyckoff_sets.py +1 -0
- {matid-2.0.0.dev1 → matid-2.0.1/matid.egg-info}/PKG-INFO +11 -7
- {matid-2.0.0.dev1 → matid-2.0.1}/matid.egg-info/SOURCES.txt +2 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid.egg-info/requires.txt +2 -1
- matid-2.0.1/pyproject.toml +93 -0
- matid-2.0.0.dev1/pyproject.toml +0 -48
- {matid-2.0.0.dev1 → matid-2.0.1}/LICENSE +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/classification/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/classification/classifications.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/clustering/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/clustering/cluster.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/core/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/core/distances.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/core/lattice.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/core/system.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/data/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/data/alphabet_data.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/data/constants.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/data/symmetry_data.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/ext/celllist.cpp +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/ext/ext.cpp +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/ext/geometry.cpp +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/geometry/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/symmetry/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/symmetry/wyckoffset.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/__init__.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/exceptions.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid/utils/surfacegenerator.py +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid.egg-info/dependency_links.txt +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/matid.egg-info/top_level.txt +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/requirements.txt +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/setup.cfg +0 -0
- {matid-2.0.0.dev1 → matid-2.0.1}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: matid
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: MatID is a Python package for identifying and analyzing atomistic systems based on their structure.
|
|
5
5
|
Author: Lauri Himanen
|
|
6
6
|
License: Apache License
|
|
@@ -214,10 +214,13 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
214
214
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
215
215
|
Classifier: Programming Language :: Python
|
|
216
216
|
Classifier: Programming Language :: Python :: 3
|
|
217
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
218
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
219
217
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
220
|
-
|
|
218
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
219
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
220
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
221
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
222
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
223
|
+
Requires-Python: >=3.8
|
|
221
224
|
Description-Content-Type: text/markdown
|
|
222
225
|
License-File: LICENSE
|
|
223
226
|
Requires-Dist: numpy
|
|
@@ -229,14 +232,15 @@ Requires-Dist: networkx>=2.4
|
|
|
229
232
|
Provides-Extra: dev
|
|
230
233
|
Requires-Dist: coverage; extra == "dev"
|
|
231
234
|
Requires-Dist: pytest; extra == "dev"
|
|
232
|
-
Requires-Dist:
|
|
235
|
+
Requires-Dist: ruff; extra == "dev"
|
|
233
236
|
Requires-Dist: pydoc-markdown; extra == "dev"
|
|
237
|
+
Requires-Dist: genbadge[coverage]; extra == "dev"
|
|
234
238
|
|
|
235
239
|
<img src="https://raw.githubusercontent.com/nomad-coe/matid/main/docs/static/img/logo.png" width="300">
|
|
236
240
|
|
|
237
241
|

|
|
238
|
-
|
|
239
|
-
[
|
|
243
|
+
[](https://github.com/astral-sh/ruff)
|
|
240
244
|
|
|
241
245
|
MatID is a Python package for identifying and analyzing atomistic systems based
|
|
242
246
|
on their structure.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<img src="https://raw.githubusercontent.com/nomad-coe/matid/main/docs/static/img/logo.png" width="300">
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-
|
|
5
|
-
[
|
|
5
|
+
[](https://github.com/astral-sh/ruff)
|
|
6
6
|
|
|
7
7
|
MatID is a Python package for identifying and analyzing atomistic systems based
|
|
8
8
|
on their structure.
|
|
@@ -127,7 +127,7 @@ class Classifier:
|
|
|
127
127
|
self.min_coverage = min_coverage
|
|
128
128
|
|
|
129
129
|
# Check seed position
|
|
130
|
-
if
|
|
130
|
+
if isinstance(seed_position, str):
|
|
131
131
|
if seed_position == "cm":
|
|
132
132
|
pass
|
|
133
133
|
else:
|
|
@@ -251,7 +251,7 @@ class Classifier:
|
|
|
251
251
|
if len(elems) == 0:
|
|
252
252
|
break
|
|
253
253
|
else:
|
|
254
|
-
if
|
|
254
|
+
if isinstance(self.seed_position, int):
|
|
255
255
|
seed_indices = [self.seed_position]
|
|
256
256
|
elif isinstance(self.seed_position, (tuple, list, np.ndarray)):
|
|
257
257
|
seed_indices = self.seed_position
|
|
@@ -19,13 +19,166 @@ class SBC:
|
|
|
19
19
|
will be returned as isolated clusters.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
def
|
|
22
|
+
def get_clusters(
|
|
23
|
+
self,
|
|
24
|
+
system,
|
|
25
|
+
angle_tol=20,
|
|
26
|
+
max_cell_size=6,
|
|
27
|
+
pos_tol=0.7,
|
|
28
|
+
merge_threshold=0.5,
|
|
29
|
+
merge_radius=1,
|
|
30
|
+
bond_threshold=0.65,
|
|
31
|
+
overlap_threshold=-0.1,
|
|
32
|
+
radii="covalent",
|
|
33
|
+
seed=7,
|
|
34
|
+
):
|
|
23
35
|
"""
|
|
36
|
+
Used to detect and return structurally separate clusters within the
|
|
37
|
+
given system.
|
|
38
|
+
|
|
24
39
|
Args:
|
|
40
|
+
system (ase.Atoms): The structure to partition.
|
|
41
|
+
angle_tol (float): angle_tol parameter for PeriodicFinder
|
|
42
|
+
max_cell_size (float): max_cell_size parameter for PeriodicFinder.get_region
|
|
43
|
+
pos_tol (float): pos_tol parameter for PeriodicFinder.get_region
|
|
44
|
+
merge_threshold (float): A threshold for merging two clusters
|
|
45
|
+
together. Give as a fraction of shared atoms. Value of 1 would
|
|
46
|
+
mean that clusters are never merged, value of 0 means that they
|
|
47
|
+
are merged always when at least one atom is shared.
|
|
48
|
+
merge_radius (float): Radius for finding nearby atoms when deciding
|
|
49
|
+
which cluster is closest. The atomic radii are subtracted from
|
|
50
|
+
distances. Given in angstroms.
|
|
51
|
+
bond_threshold(float): Used to control the connectivity threshold
|
|
52
|
+
for defining a chemical connection between atoms. Controls e.g.
|
|
53
|
+
what types of unit cells are accepted and how outliers are
|
|
54
|
+
removed from clusters.
|
|
55
|
+
overlap_threshold(float): Used to exclude non-physical cells by
|
|
56
|
+
checking overlap of atoms. Overlap between two atoms is
|
|
57
|
+
calculated by subtracting atomic radii from the distance between
|
|
58
|
+
the atoms.
|
|
59
|
+
radii(str|np.ndarray): The radii to use for atoms. Use either a preset
|
|
60
|
+
or a custom list of atomic radii for each atom. The available presets are:
|
|
61
|
+
|
|
62
|
+
- covalent: Covalent radii from DOI:10.1039/B801115J
|
|
63
|
+
- vdw: van Der Waals radii from DOI:10.1039/C3DT50599E
|
|
64
|
+
- vdw_covalent: preferably van Der Waals radii, covalent if vdw
|
|
65
|
+
not defined.
|
|
25
66
|
seed(int): The seed that is used for random number generation.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A list of Clusters.
|
|
26
70
|
"""
|
|
71
|
+
# Create a random number gen with custom seed
|
|
27
72
|
self.rng = np.random.default_rng(seed)
|
|
28
73
|
|
|
74
|
+
# Copy the system to avoid mutating the original
|
|
75
|
+
system_copy = system.copy()
|
|
76
|
+
|
|
77
|
+
# Here we ensure that the system has three valid basis vectors which
|
|
78
|
+
# when forming a unit cell contain all of the atoms in the system. This
|
|
79
|
+
# is to ensure that the code that requires scaled positions works
|
|
80
|
+
# correctly.
|
|
81
|
+
pbc = system_copy.get_pbc()
|
|
82
|
+
basis = system_copy.get_cell()
|
|
83
|
+
requires_completion = False
|
|
84
|
+
for i in range(3):
|
|
85
|
+
if not basis[i, :].any():
|
|
86
|
+
if not pbc[i]:
|
|
87
|
+
requires_completion = True
|
|
88
|
+
else:
|
|
89
|
+
raise ValueError(
|
|
90
|
+
"Cannot process system with zero-volume cell and periodic boundaries."
|
|
91
|
+
)
|
|
92
|
+
if requires_completion:
|
|
93
|
+
system_copy.set_cell(ase.geometry.complete_cell(basis))
|
|
94
|
+
if not all(pbc):
|
|
95
|
+
scaled_positions = system_copy.get_scaled_positions()
|
|
96
|
+
new_cell = system_copy.get_cell()
|
|
97
|
+
scale_cell = False
|
|
98
|
+
for i in range(3):
|
|
99
|
+
if not pbc[i]:
|
|
100
|
+
i_pos = scaled_positions[:, i]
|
|
101
|
+
max_pos = i_pos.max()
|
|
102
|
+
min_pos = i_pos.min()
|
|
103
|
+
if max_pos > 1 or min_pos < 0:
|
|
104
|
+
scale_cell = True
|
|
105
|
+
new_cell[i, :] *= (max_pos - min_pos) + 1
|
|
106
|
+
if scale_cell:
|
|
107
|
+
system_copy.set_cell(new_cell)
|
|
108
|
+
system_copy.center()
|
|
109
|
+
|
|
110
|
+
# Positions are wrapped
|
|
111
|
+
system_copy.wrap()
|
|
112
|
+
|
|
113
|
+
atomic_numbers = system.get_atomic_numbers()
|
|
114
|
+
radii = matid.geometry.get_radii(radii, atomic_numbers)
|
|
115
|
+
|
|
116
|
+
# Calculate the distances here once if they have not been provided.
|
|
117
|
+
distances = matid.geometry.get_distances(system_copy, radii)
|
|
118
|
+
|
|
119
|
+
# Iteratively search for new clusters until whole system is covered
|
|
120
|
+
periodic_finder = PeriodicFinder(
|
|
121
|
+
angle_tol=angle_tol, chem_similarity_threshold=0
|
|
122
|
+
)
|
|
123
|
+
indices = set(list(range(len(system_copy))))
|
|
124
|
+
clusters = []
|
|
125
|
+
while len(indices) != 0:
|
|
126
|
+
i_seed = self.rng.choice(list(indices), 1)[0]
|
|
127
|
+
i_grain, mask = periodic_finder.get_region(
|
|
128
|
+
system_copy,
|
|
129
|
+
seed_index=i_seed,
|
|
130
|
+
max_cell_size=max_cell_size,
|
|
131
|
+
pos_tol=pos_tol,
|
|
132
|
+
bond_threshold=bond_threshold,
|
|
133
|
+
overlap_threshold=overlap_threshold,
|
|
134
|
+
distances=distances,
|
|
135
|
+
return_mask=True,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# All neighbours that the periodic finder has tested are removed
|
|
139
|
+
# from the search. This significantly helps with the scaling of the
|
|
140
|
+
# clustering.
|
|
141
|
+
tested_indices = set(np.arange(len(mask))[mask])
|
|
142
|
+
indices -= tested_indices
|
|
143
|
+
|
|
144
|
+
# If a grain is found, it is added as a single cluster and removed
|
|
145
|
+
# from the search
|
|
146
|
+
if i_grain is not None:
|
|
147
|
+
i_indices = {i_seed}
|
|
148
|
+
i_indices.update(i_grain.get_basis_indices())
|
|
149
|
+
i_species = set(atomic_numbers[list(i_indices)])
|
|
150
|
+
clusters.append(
|
|
151
|
+
Cluster(
|
|
152
|
+
i_indices,
|
|
153
|
+
i_species,
|
|
154
|
+
i_grain,
|
|
155
|
+
system=system_copy,
|
|
156
|
+
distances=distances,
|
|
157
|
+
radii=radii,
|
|
158
|
+
bond_threshold=bond_threshold,
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
indices -= i_indices
|
|
162
|
+
|
|
163
|
+
# Check overlaps of the regions. For large overlaps the grains are
|
|
164
|
+
# merged (the real region was probably cut into pieces by unfortunate
|
|
165
|
+
# selection of the seed atom)
|
|
166
|
+
clusters = self._merge_clusters(
|
|
167
|
+
system_copy, clusters, merge_threshold, distances, bond_threshold
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Any remaining overlaps are resolved by assigning atoms to the
|
|
171
|
+
# "nearest" cluster
|
|
172
|
+
clusters = self._localize_clusters(
|
|
173
|
+
system_copy, clusters, merge_radius, distances
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Any atoms that are not chemically connected to the region will be
|
|
177
|
+
# excluded.
|
|
178
|
+
clusters = self._clean_clusters(clusters, bond_threshold)
|
|
179
|
+
|
|
180
|
+
return clusters
|
|
181
|
+
|
|
29
182
|
def _merge_clusters(
|
|
30
183
|
self, system, clusters, merge_threshold, distances, bond_threshold
|
|
31
184
|
):
|
|
@@ -181,158 +334,3 @@ class SBC:
|
|
|
181
334
|
largest_indices = max(dbscan_clusters, key=lambda x: len(x))
|
|
182
335
|
cluster.indices = np.array(cluster.indices)[largest_indices].tolist()
|
|
183
336
|
return clusters
|
|
184
|
-
|
|
185
|
-
def get_clusters(
|
|
186
|
-
self,
|
|
187
|
-
system,
|
|
188
|
-
angle_tol=20,
|
|
189
|
-
max_cell_size=6,
|
|
190
|
-
pos_tol=0.7,
|
|
191
|
-
merge_threshold=0.5,
|
|
192
|
-
merge_radius=1,
|
|
193
|
-
bond_threshold=0.65,
|
|
194
|
-
overlap_threshold=-0.1,
|
|
195
|
-
radii="covalent",
|
|
196
|
-
):
|
|
197
|
-
"""
|
|
198
|
-
Used to detect and return structurally separate clusters within the
|
|
199
|
-
given system.
|
|
200
|
-
|
|
201
|
-
Args:
|
|
202
|
-
system (ase.Atoms): The structure to partition.
|
|
203
|
-
angle_tol (float): angle_tol parameter for PeriodicFinder
|
|
204
|
-
max_cell_size (float): max_cell_size parameter for PeriodicFinder.get_region
|
|
205
|
-
pos_tol (float): pos_tol parameter for PeriodicFinder.get_region
|
|
206
|
-
merge_threshold (float): A threshold for merging two clusters
|
|
207
|
-
together. Give as a fraction of shared atoms. Value of 1 would
|
|
208
|
-
mean that clusters are never merged, value of 0 means that they
|
|
209
|
-
are merged always when at least one atom is shared.
|
|
210
|
-
merge_radius (float): Radius for finding nearby atoms when deciding
|
|
211
|
-
which cluster is closest. The atomic radii are subtracted from
|
|
212
|
-
distances. Given in angstroms.
|
|
213
|
-
bond_threshold(float): Used to control the connectivity threshold
|
|
214
|
-
for defining a chemical connection between atoms. Controls e.g.
|
|
215
|
-
what types of unit cells are accepted and how outliers are
|
|
216
|
-
removed from clusters.
|
|
217
|
-
overlap_threshold(float): Used to exclude non-physical cells by
|
|
218
|
-
checking overlap of atoms. Overlap between two atoms is
|
|
219
|
-
calculated by subtracting atomic radii from the distance between
|
|
220
|
-
the atoms.
|
|
221
|
-
radii(str|np.ndarray): The radii to use for atoms. Use either a preset
|
|
222
|
-
or a custom list of atomic radii for each atom. The available presets are:
|
|
223
|
-
|
|
224
|
-
- covalent: Covalent radii from DOI:10.1039/B801115J
|
|
225
|
-
- vdw: van Der Waals radii from DOI:10.1039/C3DT50599E
|
|
226
|
-
- vdw_covalent: preferably van Der Waals radii, covalent if vdw
|
|
227
|
-
not defined.
|
|
228
|
-
|
|
229
|
-
Returns:
|
|
230
|
-
A list of Clusters.
|
|
231
|
-
"""
|
|
232
|
-
# Copy the system to avoid mutating the original
|
|
233
|
-
system_copy = system.copy()
|
|
234
|
-
|
|
235
|
-
# Here we ensure that the system has three valid basis vectors which
|
|
236
|
-
# when forming a unit cell contain all of the atoms in the system. This
|
|
237
|
-
# is to ensure that the code that requires scaled positions works
|
|
238
|
-
# correctly.
|
|
239
|
-
pbc = system_copy.get_pbc()
|
|
240
|
-
basis = system_copy.get_cell()
|
|
241
|
-
requires_completion = False
|
|
242
|
-
for i in range(3):
|
|
243
|
-
if not basis[i, :].any():
|
|
244
|
-
if not pbc[i]:
|
|
245
|
-
requires_completion = True
|
|
246
|
-
else:
|
|
247
|
-
raise ValueError(
|
|
248
|
-
"Cannot process system with zero-volume cell and periodic boundaries."
|
|
249
|
-
)
|
|
250
|
-
if requires_completion:
|
|
251
|
-
system_copy.set_cell(ase.geometry.complete_cell(basis))
|
|
252
|
-
if not all(pbc):
|
|
253
|
-
scaled_positions = system_copy.get_scaled_positions()
|
|
254
|
-
new_cell = system_copy.get_cell()
|
|
255
|
-
scale_cell = False
|
|
256
|
-
for i in range(3):
|
|
257
|
-
if not pbc[i]:
|
|
258
|
-
i_pos = scaled_positions[:, i]
|
|
259
|
-
max_pos = i_pos.max()
|
|
260
|
-
min_pos = i_pos.min()
|
|
261
|
-
if max_pos > 1 or min_pos < 0:
|
|
262
|
-
scale_cell = True
|
|
263
|
-
new_cell[i, :] *= (max_pos - min_pos) + 1
|
|
264
|
-
if scale_cell:
|
|
265
|
-
system_copy.set_cell(new_cell)
|
|
266
|
-
system_copy.center()
|
|
267
|
-
|
|
268
|
-
# Positions are wrapped
|
|
269
|
-
system_copy.wrap()
|
|
270
|
-
|
|
271
|
-
atomic_numbers = system.get_atomic_numbers()
|
|
272
|
-
radii = matid.geometry.get_radii(radii, atomic_numbers)
|
|
273
|
-
|
|
274
|
-
# Calculate the distances here once if they have not been provided.
|
|
275
|
-
distances = matid.geometry.get_distances(system_copy, radii)
|
|
276
|
-
|
|
277
|
-
# Iteratively search for new clusters until whole system is covered
|
|
278
|
-
periodic_finder = PeriodicFinder(
|
|
279
|
-
angle_tol=angle_tol, chem_similarity_threshold=0
|
|
280
|
-
)
|
|
281
|
-
indices = set(list(range(len(system_copy))))
|
|
282
|
-
clusters = []
|
|
283
|
-
while len(indices) != 0:
|
|
284
|
-
i_seed = self.rng.choice(list(indices), 1)[0]
|
|
285
|
-
i_grain, mask = periodic_finder.get_region(
|
|
286
|
-
system_copy,
|
|
287
|
-
seed_index=i_seed,
|
|
288
|
-
max_cell_size=max_cell_size,
|
|
289
|
-
pos_tol=pos_tol,
|
|
290
|
-
bond_threshold=bond_threshold,
|
|
291
|
-
overlap_threshold=overlap_threshold,
|
|
292
|
-
distances=distances,
|
|
293
|
-
return_mask=True,
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
# All neighbours that the periodic finder has tested are removed
|
|
297
|
-
# from the search. This significantly helps with the scaling of the
|
|
298
|
-
# clustering.
|
|
299
|
-
tested_indices = set(np.arange(len(mask))[mask])
|
|
300
|
-
indices -= tested_indices
|
|
301
|
-
|
|
302
|
-
# If a grain is found, it is added as a single cluster and removed
|
|
303
|
-
# from the search
|
|
304
|
-
if i_grain is not None:
|
|
305
|
-
i_indices = {i_seed}
|
|
306
|
-
i_indices.update(i_grain.get_basis_indices())
|
|
307
|
-
i_species = set(atomic_numbers[list(i_indices)])
|
|
308
|
-
clusters.append(
|
|
309
|
-
Cluster(
|
|
310
|
-
i_indices,
|
|
311
|
-
i_species,
|
|
312
|
-
i_grain,
|
|
313
|
-
system=system_copy,
|
|
314
|
-
distances=distances,
|
|
315
|
-
radii=radii,
|
|
316
|
-
bond_threshold=bond_threshold,
|
|
317
|
-
)
|
|
318
|
-
)
|
|
319
|
-
indices -= i_indices
|
|
320
|
-
|
|
321
|
-
# Check overlaps of the regions. For large overlaps the grains are
|
|
322
|
-
# merged (the real region was probably cut into pieces by unfortunate
|
|
323
|
-
# selection of the seed atom)
|
|
324
|
-
clusters = self._merge_clusters(
|
|
325
|
-
system_copy, clusters, merge_threshold, distances, bond_threshold
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
# Any remaining overlaps are resolved by assigning atoms to the
|
|
329
|
-
# "nearest" cluster
|
|
330
|
-
clusters = self._localize_clusters(
|
|
331
|
-
system_copy, clusters, merge_radius, distances
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
# Any atoms that are not chemically connected to the region will be
|
|
335
|
-
# excluded.
|
|
336
|
-
clusters = self._clean_clusters(clusters, bond_threshold)
|
|
337
|
-
|
|
338
|
-
return clusters
|
|
@@ -69,7 +69,7 @@ class LinkedUnitCollection(dict):
|
|
|
69
69
|
# Transform key to tuple, check length
|
|
70
70
|
try:
|
|
71
71
|
key = tuple(key)
|
|
72
|
-
except:
|
|
72
|
+
except Exception:
|
|
73
73
|
raise TypeError(
|
|
74
74
|
"Could not transform the given key '{}' into tuple.".format(key)
|
|
75
75
|
)
|
|
@@ -311,7 +311,6 @@ class LinkedUnitCollection(dict):
|
|
|
311
311
|
if self._adsorbates is None:
|
|
312
312
|
_, outside_indices = self.get_inside_and_outside_indices()
|
|
313
313
|
basis_elements = set(self.cell.get_atomic_numbers())
|
|
314
|
-
outside_indices = outside_indices
|
|
315
314
|
|
|
316
315
|
# The substitutions have to be removed explicitly from the ouside
|
|
317
316
|
# atoms because sometimes they are outside the tesselation.
|
|
@@ -219,6 +219,14 @@ class PeriodicFinder:
|
|
|
219
219
|
generate a periodic region in the structure.
|
|
220
220
|
|
|
221
221
|
Args:
|
|
222
|
+
system(ase.Atoms):
|
|
223
|
+
seed_index(int):
|
|
224
|
+
possible_spans(np.ndarray):
|
|
225
|
+
neighbour_mask(np.ndarray):
|
|
226
|
+
neighbour_factors(np.ndarray):
|
|
227
|
+
bond_threshold(float):
|
|
228
|
+
overlap_threshold(float):
|
|
229
|
+
pos_tol(float):
|
|
222
230
|
|
|
223
231
|
Returns:
|
|
224
232
|
ase.Atoms: A system representing the best cell that was found
|
|
@@ -288,9 +296,9 @@ class PeriodicFinder:
|
|
|
288
296
|
adjacency_lists_add.append(i_adj_list_add)
|
|
289
297
|
adjacency_lists_sub.append(i_adj_list_sub)
|
|
290
298
|
|
|
291
|
-
#
|
|
292
|
-
#
|
|
293
|
-
periodic_spans = system.get_cell()
|
|
299
|
+
# The lattice vectors are added as possible spans if they are set as
|
|
300
|
+
# periodic and they are shorter than the maximum cell size
|
|
301
|
+
periodic_spans = system.get_cell()[system.get_pbc()]
|
|
294
302
|
periodic_span_lengths = np.linalg.norm(periodic_spans, axis=1)
|
|
295
303
|
periodic_filter = periodic_span_lengths <= self.max_cell_size
|
|
296
304
|
n_periodic_spans = periodic_filter.sum()
|
|
@@ -330,12 +338,19 @@ class PeriodicFinder:
|
|
|
330
338
|
adjacency_lists_add.append(per_adjacency_list_add)
|
|
331
339
|
adjacency_lists_sub.append(per_adjacency_list_sub)
|
|
332
340
|
|
|
333
|
-
#
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
#
|
|
337
|
-
#
|
|
338
|
-
|
|
341
|
+
# Filter the spans based on how well they explain the repeated patterns
|
|
342
|
+
# around the neighbourhood of the seed atom. Spans are accepted if they
|
|
343
|
+
# produce more than 0.75 % of the possible repetitions in the seed
|
|
344
|
+
# neighbourhood OR they explain at least 50% of the maximum repetition
|
|
345
|
+
# that was found. These criteria are important to eliminate directions
|
|
346
|
+
# that are caused by pure chance, or represent directions where there is
|
|
347
|
+
# a periodic substructure that can only explain the structure partially.
|
|
348
|
+
# OLD: valid_span_indices = np.where(metric >= 0.75 * n_neighbours)[0]
|
|
349
|
+
valid_span_indices = np.where(
|
|
350
|
+
(metric >= 0.4 * (0 if len(metric) == 0 else metric.max()))
|
|
351
|
+
| (metric >= 0.75 * n_neighbours)
|
|
352
|
+
)[0]
|
|
353
|
+
|
|
339
354
|
if len(valid_span_indices) == 0:
|
|
340
355
|
return None, None, None
|
|
341
356
|
|
|
@@ -369,9 +384,7 @@ class PeriodicFinder:
|
|
|
369
384
|
seed_nodes, seed_group_index, group_data_pbc = self._find_graphs(
|
|
370
385
|
seed_index,
|
|
371
386
|
numbers,
|
|
372
|
-
dim,
|
|
373
387
|
best_adjacency_lists,
|
|
374
|
-
neighbour_nodes,
|
|
375
388
|
neighbour_indices,
|
|
376
389
|
neighbour_factors,
|
|
377
390
|
)
|
|
@@ -525,9 +538,7 @@ class PeriodicFinder:
|
|
|
525
538
|
self,
|
|
526
539
|
seed_index,
|
|
527
540
|
numbers,
|
|
528
|
-
dim,
|
|
529
541
|
best_adjacency_lists,
|
|
530
|
-
neighbour_nodes,
|
|
531
542
|
neighbour_indices,
|
|
532
543
|
neighbour_factors,
|
|
533
544
|
):
|
|
@@ -836,7 +847,7 @@ class PeriodicFinder:
|
|
|
836
847
|
min_dist_pos = scaled_pos[min_dist_index]
|
|
837
848
|
|
|
838
849
|
# All the other copies are moved periodically to be near the
|
|
839
|
-
# position that is closest to origin
|
|
850
|
+
# position that is closest to origin
|
|
840
851
|
distances = scaled_pos - min_dist_pos
|
|
841
852
|
displacement = np.rint(distances)
|
|
842
853
|
final_pos = scaled_pos - displacement
|
|
@@ -862,6 +873,7 @@ class PeriodicFinder:
|
|
|
862
873
|
cell=best_spans,
|
|
863
874
|
pbc=[True, True, True],
|
|
864
875
|
)
|
|
876
|
+
|
|
865
877
|
offset = proto_cell.get_positions()[seed_group_index]
|
|
866
878
|
|
|
867
879
|
return proto_cell, offset, seed_group_index
|
|
@@ -1052,6 +1064,7 @@ class PeriodicFinder:
|
|
|
1052
1064
|
symbols=averaged_rel_num,
|
|
1053
1065
|
pbc=[True, True, False],
|
|
1054
1066
|
)
|
|
1067
|
+
|
|
1055
1068
|
offset = proto_cell.get_positions()[seed_group_index]
|
|
1056
1069
|
|
|
1057
1070
|
return proto_cell, offset, seed_group_index
|
|
@@ -1275,7 +1288,6 @@ class PeriodicFinder:
|
|
|
1275
1288
|
|
|
1276
1289
|
searched_cell_indices = set()
|
|
1277
1290
|
used_indices = set()
|
|
1278
|
-
used_seed_indices = set()
|
|
1279
1291
|
searched_vacancy_positions = []
|
|
1280
1292
|
queue = deque()
|
|
1281
1293
|
collection = LinkedUnitCollection(
|
|
@@ -1294,8 +1306,6 @@ class PeriodicFinder:
|
|
|
1294
1306
|
self._find_region_rec(
|
|
1295
1307
|
system,
|
|
1296
1308
|
collection,
|
|
1297
|
-
number_to_index_map,
|
|
1298
|
-
number_to_pos_map,
|
|
1299
1309
|
seed_index,
|
|
1300
1310
|
seed_pos,
|
|
1301
1311
|
seed_number,
|
|
@@ -1305,10 +1315,8 @@ class PeriodicFinder:
|
|
|
1305
1315
|
(0, 0, 0),
|
|
1306
1316
|
used_indices,
|
|
1307
1317
|
searched_vacancy_positions,
|
|
1308
|
-
periodic_indices,
|
|
1309
1318
|
queue,
|
|
1310
1319
|
multipliers,
|
|
1311
|
-
used_seed_indices,
|
|
1312
1320
|
)
|
|
1313
1321
|
|
|
1314
1322
|
# Keep searching while new cells are found
|
|
@@ -1327,8 +1335,6 @@ class PeriodicFinder:
|
|
|
1327
1335
|
self._find_region_rec(
|
|
1328
1336
|
system,
|
|
1329
1337
|
collection,
|
|
1330
|
-
number_to_index_map,
|
|
1331
|
-
number_to_pos_map,
|
|
1332
1338
|
queue_seed_index,
|
|
1333
1339
|
queue_seed_pos,
|
|
1334
1340
|
seed_number,
|
|
@@ -1338,10 +1344,8 @@ class PeriodicFinder:
|
|
|
1338
1344
|
queue_index,
|
|
1339
1345
|
used_indices,
|
|
1340
1346
|
searched_vacancy_positions,
|
|
1341
|
-
periodic_indices,
|
|
1342
1347
|
queue,
|
|
1343
1348
|
multipliers,
|
|
1344
|
-
used_seed_indices,
|
|
1345
1349
|
)
|
|
1346
1350
|
|
|
1347
1351
|
return collection
|
|
@@ -1363,8 +1367,6 @@ class PeriodicFinder:
|
|
|
1363
1367
|
self,
|
|
1364
1368
|
system,
|
|
1365
1369
|
collection,
|
|
1366
|
-
number_to_index_map,
|
|
1367
|
-
number_to_pos_map,
|
|
1368
1370
|
seed_index,
|
|
1369
1371
|
seed_pos,
|
|
1370
1372
|
seed_atomic_number,
|
|
@@ -1374,10 +1376,8 @@ class PeriodicFinder:
|
|
|
1374
1376
|
cell_index,
|
|
1375
1377
|
used_indices,
|
|
1376
1378
|
searched_vacancy_positions,
|
|
1377
|
-
periodic_indices,
|
|
1378
1379
|
queue,
|
|
1379
1380
|
multipliers,
|
|
1380
|
-
used_seed_indices,
|
|
1381
1381
|
):
|
|
1382
1382
|
"""
|
|
1383
1383
|
Args:
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*Copyright 2019 DScribe developers
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#ifndef CELLLIST_H
|
|
17
|
+
#define CELLLIST_H
|
|
18
|
+
|
|
19
|
+
#include <pybind11/numpy.h>
|
|
20
|
+
#include <vector>
|
|
21
|
+
|
|
22
|
+
namespace py = pybind11;
|
|
23
|
+
using namespace std;
|
|
24
|
+
|
|
25
|
+
struct CellListResult {
|
|
26
|
+
vector<int> indices;
|
|
27
|
+
vector<double> distances;
|
|
28
|
+
vector<double> distances_squared;
|
|
29
|
+
vector<vector<double>> displacements;
|
|
30
|
+
vector<int> indices_original;
|
|
31
|
+
vector<vector<double>> factors;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* For calculating pairwise distances using a cell list.
|
|
36
|
+
*/
|
|
37
|
+
class CellList {
|
|
38
|
+
public:
|
|
39
|
+
/**
|
|
40
|
+
* Constructor
|
|
41
|
+
*
|
|
42
|
+
* @param positions Atomic positions in cartesian coordinates.
|
|
43
|
+
* @param atomicNumbers Atomic numbers.
|
|
44
|
+
*/
|
|
45
|
+
CellList(py::array_t<double> positions, py::array_t<int> indices, py::array_t<double> factors, double cutoff);
|
|
46
|
+
/**
|
|
47
|
+
* Get the indices of atoms within the radial cutoff distance from the
|
|
48
|
+
* given position.
|
|
49
|
+
*
|
|
50
|
+
* @param x Cartesian x-coordinate.
|
|
51
|
+
* @param y Cartesian y-coordinate.
|
|
52
|
+
* @param z Cartesian z-coordinate.
|
|
53
|
+
*/
|
|
54
|
+
CellListResult get_neighbours_for_position(const double x, const double y, const double z);
|
|
55
|
+
/**
|
|
56
|
+
* Get the indices of atoms within the radial cutoff distance from the
|
|
57
|
+
* given atomic index. The given index is not included in the returned
|
|
58
|
+
* values.
|
|
59
|
+
*
|
|
60
|
+
* @param i Index of the atom for which neighbours are queried for.
|
|
61
|
+
*/
|
|
62
|
+
CellListResult get_neighbours_for_index(const int i);
|
|
63
|
+
/**
|
|
64
|
+
* Used to calculate the full displacement tensor in an efficient
|
|
65
|
+
* manner.
|
|
66
|
+
*/
|
|
67
|
+
void get_displacement_tensor(
|
|
68
|
+
py::array_t<double> displacements,
|
|
69
|
+
py::array_t<double> distances,
|
|
70
|
+
py::array_t<double> factors,
|
|
71
|
+
py::array_t<int> original_indices,
|
|
72
|
+
int n_atoms
|
|
73
|
+
);
|
|
74
|
+
py::array_t<int> indices_py;
|
|
75
|
+
|
|
76
|
+
private:
|
|
77
|
+
/**
|
|
78
|
+
* Used to initialize the cell list. Querying for distances is only
|
|
79
|
+
* possible after this initialization.
|
|
80
|
+
*/
|
|
81
|
+
void init();
|
|
82
|
+
|
|
83
|
+
// const py::detail::unchecked_reference<double, 2> positions;
|
|
84
|
+
// const py::detail::unchecked_reference<int, 1> indices;
|
|
85
|
+
// const py::detail::unchecked_reference<double, 2> factors;
|
|
86
|
+
vector<vector<double>> positions;
|
|
87
|
+
vector<int> indices;
|
|
88
|
+
vector<vector<double>> factors;
|
|
89
|
+
const double cutoff;
|
|
90
|
+
const double cutoffSquared;
|
|
91
|
+
double xmin;
|
|
92
|
+
double xmax;
|
|
93
|
+
double ymin;
|
|
94
|
+
double ymax;
|
|
95
|
+
double zmin;
|
|
96
|
+
double zmax;
|
|
97
|
+
double dx;
|
|
98
|
+
double dy;
|
|
99
|
+
double dz;
|
|
100
|
+
int nx;
|
|
101
|
+
int ny;
|
|
102
|
+
int nz;
|
|
103
|
+
vector<vector<vector<vector<int>>>> bins;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
#endif
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*Copyright 2019 DScribe developers
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#ifndef GEOMETRY_H
|
|
17
|
+
#define GEOMETRY_H
|
|
18
|
+
|
|
19
|
+
#include <vector>
|
|
20
|
+
#include <stdexcept>
|
|
21
|
+
#include <pybind11/numpy.h>
|
|
22
|
+
#include "celllist.h"
|
|
23
|
+
|
|
24
|
+
namespace py = pybind11;
|
|
25
|
+
using namespace std;
|
|
26
|
+
|
|
27
|
+
struct ExtendedSystem {
|
|
28
|
+
py::array_t<double> positions;
|
|
29
|
+
py::array_t<int> atomic_numbers;
|
|
30
|
+
py::array_t<int> indices;
|
|
31
|
+
py::array_t<double> factors;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
inline vector<double> cross(const vector<double>& a, const vector<double>& b);
|
|
35
|
+
inline double dot(const vector<double>& a, const vector<double>& b);
|
|
36
|
+
inline double norm(const vector<double>& a);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Used to periodically extend an atomic system in order to take into account
|
|
40
|
+
* periodic copies beyond the given unit cell.
|
|
41
|
+
*
|
|
42
|
+
* @param positions Cartesian positions of the original system.
|
|
43
|
+
* @param atomic_numbers Atomic numbers of the original system.
|
|
44
|
+
* @param cell Unit cell of the original system.
|
|
45
|
+
* @param pbc Periodic boundary conditions (array of three booleans) of the original system.
|
|
46
|
+
* @param cutoff Radial cutoff value for determining extension size.
|
|
47
|
+
*
|
|
48
|
+
* @return Instance of ExtendedSystem.
|
|
49
|
+
*/
|
|
50
|
+
ExtendedSystem extend_system(
|
|
51
|
+
py::array_t<double> positions,
|
|
52
|
+
py::array_t<int> atomic_numbers,
|
|
53
|
+
py::array_t<double> cell,
|
|
54
|
+
py::array_t<bool> pbc,
|
|
55
|
+
double cutoff
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns a CellList instance for the given atomic system.
|
|
60
|
+
*
|
|
61
|
+
* Note that you should control how large extension should be performed to take
|
|
62
|
+
* into account the periodic boundary conditions, as the CellList internally
|
|
63
|
+
* works with plain cartesian coordinates.
|
|
64
|
+
*/
|
|
65
|
+
CellList get_cell_list(
|
|
66
|
+
py::array_t<double> positions,
|
|
67
|
+
py::array_t<double> cell,
|
|
68
|
+
py::array_t<bool> pbc,
|
|
69
|
+
double extension,
|
|
70
|
+
double cutoff
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Calculates a pairwise displacement tensor (distance vectors) with a given
|
|
75
|
+
* cutoff.
|
|
76
|
+
*/
|
|
77
|
+
void get_displacement_tensor(
|
|
78
|
+
py::array_t<double> displacements,
|
|
79
|
+
py::array_t<double> distances,
|
|
80
|
+
py::array_t<double> factors,
|
|
81
|
+
py::array_t<double> positions,
|
|
82
|
+
py::array_t<double> cell,
|
|
83
|
+
py::array_t<bool> pbc,
|
|
84
|
+
double cutoff,
|
|
85
|
+
bool return_factors,
|
|
86
|
+
bool return_distances
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
#endif
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""This module defines functions for deriving geometry related quantities from
|
|
2
2
|
a atomic system.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import math
|
|
5
6
|
import itertools
|
|
6
7
|
from collections import defaultdict
|
|
@@ -291,9 +292,9 @@ def get_moments_of_inertia(system, weight=True):
|
|
|
291
292
|
I13 = np.sum(-weights * x * z)
|
|
292
293
|
I23 = np.sum(-weights * y * z)
|
|
293
294
|
|
|
294
|
-
|
|
295
|
+
inertia_tensor = np.array([[I11, I12, I13], [I12, I22, I23], [I13, I23, I33]])
|
|
295
296
|
|
|
296
|
-
evals, evecs = np.linalg.eigh(
|
|
297
|
+
evals, evecs = np.linalg.eigh(inertia_tensor)
|
|
297
298
|
|
|
298
299
|
return evals, evecs
|
|
299
300
|
|
|
@@ -58,7 +58,7 @@ class SymmetryAnalyzer(object):
|
|
|
58
58
|
self._analyzed_system = system
|
|
59
59
|
elif n_pbc == 2:
|
|
60
60
|
# Get the index of the non-periodic axis
|
|
61
|
-
i_pbc = np.argwhere(pbc == False)[0]
|
|
61
|
+
i_pbc = np.argwhere(pbc == False)[0] # noqa: E712
|
|
62
62
|
|
|
63
63
|
# Before calculating the conventional system, make sure that there
|
|
64
64
|
# is enough vacuum in the periodic direction to remove any
|
|
@@ -355,7 +355,7 @@ class SymmetryAnalyzer(object):
|
|
|
355
355
|
return ideal_sys
|
|
356
356
|
# 2D materials get a special treatment
|
|
357
357
|
elif n_pbc == 2:
|
|
358
|
-
i_pbc = np.argwhere(pbc == False)[0]
|
|
358
|
+
i_pbc = np.argwhere(pbc == False)[0] # noqa: E712
|
|
359
359
|
|
|
360
360
|
# Get the full 3D conventional system and it's symmetries. It will
|
|
361
361
|
# include some symmetries that have a translational component
|
|
@@ -1357,7 +1357,7 @@ class SymmetryAnalyzer(object):
|
|
|
1357
1357
|
for trans in translations:
|
|
1358
1358
|
test_positions[
|
|
1359
1359
|
i_trans * n_expr : (i_trans + 1) * n_expr, :
|
|
1360
|
-
] =
|
|
1360
|
+
] = first_test_pos + trans
|
|
1361
1361
|
i_trans += 1
|
|
1362
1362
|
|
|
1363
1363
|
# Test if each test positions can be matched to an atom
|
|
@@ -16,6 +16,7 @@ correponding ITA setting in Bilbao to fetch the Wyckoff positions.
|
|
|
16
16
|
The mathematical expression for the Wyckoff positions is stored along with the
|
|
17
17
|
necessary matrices for solving the variables from a particular system.
|
|
18
18
|
"""
|
|
19
|
+
|
|
19
20
|
import re
|
|
20
21
|
import parser
|
|
21
22
|
import numpy as np
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: matid
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: MatID is a Python package for identifying and analyzing atomistic systems based on their structure.
|
|
5
5
|
Author: Lauri Himanen
|
|
6
6
|
License: Apache License
|
|
@@ -214,10 +214,13 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
214
214
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
215
215
|
Classifier: Programming Language :: Python
|
|
216
216
|
Classifier: Programming Language :: Python :: 3
|
|
217
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
218
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
219
217
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
220
|
-
|
|
218
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
219
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
220
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
221
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
222
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
223
|
+
Requires-Python: >=3.8
|
|
221
224
|
Description-Content-Type: text/markdown
|
|
222
225
|
License-File: LICENSE
|
|
223
226
|
Requires-Dist: numpy
|
|
@@ -229,14 +232,15 @@ Requires-Dist: networkx>=2.4
|
|
|
229
232
|
Provides-Extra: dev
|
|
230
233
|
Requires-Dist: coverage; extra == "dev"
|
|
231
234
|
Requires-Dist: pytest; extra == "dev"
|
|
232
|
-
Requires-Dist:
|
|
235
|
+
Requires-Dist: ruff; extra == "dev"
|
|
233
236
|
Requires-Dist: pydoc-markdown; extra == "dev"
|
|
237
|
+
Requires-Dist: genbadge[coverage]; extra == "dev"
|
|
234
238
|
|
|
235
239
|
<img src="https://raw.githubusercontent.com/nomad-coe/matid/main/docs/static/img/logo.png" width="300">
|
|
236
240
|
|
|
237
241
|

|
|
238
|
-
|
|
239
|
-
[
|
|
243
|
+
[](https://github.com/astral-sh/ruff)
|
|
240
244
|
|
|
241
245
|
MatID is a Python package for identifying and analyzing atomistic systems based
|
|
242
246
|
on their structure.
|
|
@@ -28,8 +28,10 @@ matid/data/constants.py
|
|
|
28
28
|
matid/data/element_data.py
|
|
29
29
|
matid/data/symmetry_data.py
|
|
30
30
|
matid/ext/celllist.cpp
|
|
31
|
+
matid/ext/celllist.h
|
|
31
32
|
matid/ext/ext.cpp
|
|
32
33
|
matid/ext/geometry.cpp
|
|
34
|
+
matid/ext/geometry.h
|
|
33
35
|
matid/geometry/__init__.py
|
|
34
36
|
matid/geometry/geometry.py
|
|
35
37
|
matid/symmetry/__init__.py
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel", "pybind11~=2.11.1"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = 'matid'
|
|
7
|
+
version = '2.0.1'
|
|
8
|
+
description = 'MatID is a Python package for identifying and analyzing atomistic systems based on their structure.'
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [{ name = "Lauri Himanen" }]
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
requires-python = ">=3.8"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"numpy",
|
|
15
|
+
"ase",
|
|
16
|
+
"scipy",
|
|
17
|
+
"spglib>=1.15.0",
|
|
18
|
+
"scikit-learn",
|
|
19
|
+
"networkx>=2.4",
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 5 - Production/Stable",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
25
|
+
"License :: OSI Approved :: Apache Software License",
|
|
26
|
+
"Programming Language :: Python",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
29
|
+
"Programming Language :: Python :: 3.8",
|
|
30
|
+
"Programming Language :: Python :: 3.9",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
]
|
|
35
|
+
keywords = ['atoms', 'structure', 'materials', 'science', 'crystal', 'symmetry']
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Documentation = 'https://nomad-coe.github.io/matid/'
|
|
39
|
+
Source = "https://github.com/nomad-coe/matid"
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
dev = [
|
|
43
|
+
"coverage",
|
|
44
|
+
"pytest",
|
|
45
|
+
"ruff",
|
|
46
|
+
"pydoc-markdown",
|
|
47
|
+
"genbadge[coverage]",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.packages.find]
|
|
51
|
+
include = ["matid*"]
|
|
52
|
+
exclude = ["tests*"]
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
include = ["matid/*.py", "tests/*.py"]
|
|
56
|
+
|
|
57
|
+
# Same as Black.
|
|
58
|
+
line-length = 88
|
|
59
|
+
indent-width = 4
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint]
|
|
62
|
+
select = [
|
|
63
|
+
"E", # pycodestyle
|
|
64
|
+
"W", # pycodestyle
|
|
65
|
+
"PL", # pylint
|
|
66
|
+
]
|
|
67
|
+
ignore = [
|
|
68
|
+
"E501", # Line too long ({width} > {limit} characters)
|
|
69
|
+
"E701", # Multiple statements on one line (colon)
|
|
70
|
+
"E731", # Do not assign a lambda expression, use a def
|
|
71
|
+
"E402", # Module level import not at top of file
|
|
72
|
+
"W605", # Invalid escape sequence
|
|
73
|
+
"PLR0911", # Too many return statements
|
|
74
|
+
"PLR0912", # Too many branches
|
|
75
|
+
"PLR0913", # Too many arguments in function definition
|
|
76
|
+
"PLR0915", # Too many statements
|
|
77
|
+
"PLR2004", # Magic value used instead of constant
|
|
78
|
+
"PLW0603", # Using the global statement
|
|
79
|
+
"PLW2901", # redefined-loop-name
|
|
80
|
+
"PLR1714", # consider-using-in
|
|
81
|
+
"PLR5501", # else-if-used
|
|
82
|
+
]
|
|
83
|
+
fixable = ["ALL"]
|
|
84
|
+
|
|
85
|
+
[tool.ruff.format]
|
|
86
|
+
# indent with spaces, rather than tabs.
|
|
87
|
+
indent-style = "space"
|
|
88
|
+
|
|
89
|
+
# Like Black, respect magic trailing commas.
|
|
90
|
+
skip-magic-trailing-comma = false
|
|
91
|
+
|
|
92
|
+
# Like Black, automatically detect the appropriate line ending.
|
|
93
|
+
line-ending = "auto"
|
matid-2.0.0.dev1/pyproject.toml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools", "wheel", "pybind11~=2.11.1"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = 'matid'
|
|
7
|
-
version = '2.0.0.dev1'
|
|
8
|
-
description = 'MatID is a Python package for identifying and analyzing atomistic systems based on their structure.'
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
authors = [{ name = "Lauri Himanen" }]
|
|
11
|
-
license = { file = "LICENSE" }
|
|
12
|
-
requires-python = ">=3.7"
|
|
13
|
-
dependencies = [
|
|
14
|
-
"numpy",
|
|
15
|
-
"ase",
|
|
16
|
-
"scipy",
|
|
17
|
-
"spglib>=1.15.0",
|
|
18
|
-
"scikit-learn",
|
|
19
|
-
"networkx>=2.4",
|
|
20
|
-
]
|
|
21
|
-
classifiers = [
|
|
22
|
-
"Development Status :: 5 - Production/Stable",
|
|
23
|
-
"Intended Audience :: Developers",
|
|
24
|
-
"Topic :: Scientific/Engineering :: Physics",
|
|
25
|
-
"License :: OSI Approved :: Apache Software License",
|
|
26
|
-
"Programming Language :: Python",
|
|
27
|
-
"Programming Language :: Python :: 3",
|
|
28
|
-
"Programming Language :: Python :: 3.7",
|
|
29
|
-
"Programming Language :: Python :: 3.8",
|
|
30
|
-
"Programming Language :: Python :: 3 :: Only",
|
|
31
|
-
]
|
|
32
|
-
keywords = ['atoms', 'structure', 'materials', 'science', 'crystal', 'symmetry']
|
|
33
|
-
|
|
34
|
-
[project.urls]
|
|
35
|
-
Documentation = 'https://nomad-coe.github.io/matid/'
|
|
36
|
-
Source = "https://github.com/nomad-coe/matid"
|
|
37
|
-
|
|
38
|
-
[project.optional-dependencies]
|
|
39
|
-
dev = [
|
|
40
|
-
"coverage",
|
|
41
|
-
"pytest",
|
|
42
|
-
"black",
|
|
43
|
-
"pydoc-markdown"
|
|
44
|
-
]
|
|
45
|
-
|
|
46
|
-
[tool.setuptools.packages.find]
|
|
47
|
-
include = ["matid*"]
|
|
48
|
-
exclude = ["tests*"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|