structuretoolkit 0.0.26__tar.gz → 0.0.27__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.
- {structuretoolkit-0.0.26/structuretoolkit.egg-info → structuretoolkit-0.0.27}/PKG-INFO +4 -4
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/pyproject.toml +3 -3
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/_version.py +3 -3
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/pyscal.py +20 -48
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/symmetry.py +99 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/common/pyscal.py +2 -6
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27/structuretoolkit.egg-info}/PKG-INFO +4 -4
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit.egg-info/requires.txt +3 -3
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_pyscal.py +5 -8
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_symmetry.py +62 -8
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/LICENSE +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/MANIFEST.in +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/README.md +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/setup.cfg +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/setup.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/__init__.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/__init__.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/distance.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/dscribe.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/neighbors.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/phonopy.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/snap.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/spatial.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/analyse/strain.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/__init__.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/aimsgb.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/compound.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/mesh.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/random.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/sqs.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/build/surface.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/common/__init__.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/common/error.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/common/helper.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/common/phonopy.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/common/pymatgen.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit/visualize.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit.egg-info/SOURCES.txt +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit.egg-info/dependency_links.txt +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit.egg-info/top_level.txt +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_aimsgb.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_analyse.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_compound.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_dscribe.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_helpers.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_high_index_surface.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_mesh.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_neighbors.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_pymatgen.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_pyxtal.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_snap.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_strain.py +0 -0
- {structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/tests/test_visualize.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: structuretoolkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.27
|
|
4
4
|
Summary: build, analyse and visualise atomistic structures for materials science
|
|
5
5
|
Author-email: Jan Janssen <janssen@mpie.de>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -58,7 +58,7 @@ Provides-Extra: grainboundary
|
|
|
58
58
|
Requires-Dist: aimsgb<=1.1.1,>=1.0.2; extra == "grainboundary"
|
|
59
59
|
Requires-Dist: pymatgen<=2024.6.10,>=2022.2.1; extra == "grainboundary"
|
|
60
60
|
Provides-Extra: pyscal
|
|
61
|
-
Requires-Dist:
|
|
61
|
+
Requires-Dist: pyscal3==3.2.5; extra == "pyscal"
|
|
62
62
|
Provides-Extra: nglview
|
|
63
63
|
Requires-Dist: nglview<=3.1.2,>=2.7.7; extra == "nglview"
|
|
64
64
|
Provides-Extra: matplotlib
|
|
@@ -66,14 +66,14 @@ Requires-Dist: matplotlib==3.8.4; extra == "matplotlib"
|
|
|
66
66
|
Provides-Extra: plotly
|
|
67
67
|
Requires-Dist: plotly<=5.22.0,>=4.14.3; extra == "plotly"
|
|
68
68
|
Provides-Extra: clusters
|
|
69
|
-
Requires-Dist: scikit-learn==1.5.
|
|
69
|
+
Requires-Dist: scikit-learn==1.5.1; extra == "clusters"
|
|
70
70
|
Provides-Extra: symmetry
|
|
71
71
|
Requires-Dist: spglib<=2.4.0,>=1.16.5; extra == "symmetry"
|
|
72
72
|
Provides-Extra: surface
|
|
73
73
|
Requires-Dist: spglib<=2.4.0,>=1.16.5; extra == "surface"
|
|
74
74
|
Requires-Dist: pymatgen<=2024.6.10,>=2022.2.1; extra == "surface"
|
|
75
75
|
Provides-Extra: phonopy
|
|
76
|
-
Requires-Dist: phonopy<=2.
|
|
76
|
+
Requires-Dist: phonopy<=2.26.3,>=2.16.2; extra == "phonopy"
|
|
77
77
|
Requires-Dist: spglib<=2.4.0,>=1.16.5; extra == "phonopy"
|
|
78
78
|
Provides-Extra: pyxtal
|
|
79
79
|
Requires-Dist: pyxtal<=0.6.7,>=0.5.5; extra == "pyxtal"
|
|
@@ -41,18 +41,18 @@ grainboundary = [
|
|
|
41
41
|
"aimsgb>=1.0.2,<=1.1.1",
|
|
42
42
|
"pymatgen>=2022.2.1,<=2024.6.10",
|
|
43
43
|
]
|
|
44
|
-
pyscal = ["
|
|
44
|
+
pyscal = ["pyscal3==3.2.5"]
|
|
45
45
|
nglview = ["nglview>=2.7.7,<=3.1.2"]
|
|
46
46
|
matplotlib = ["matplotlib==3.8.4"]
|
|
47
47
|
plotly = ["plotly>=4.14.3,<=5.22.0"]
|
|
48
|
-
clusters = ["scikit-learn==1.5.
|
|
48
|
+
clusters = ["scikit-learn==1.5.1"]
|
|
49
49
|
symmetry = ["spglib>=1.16.5,<=2.4.0"]
|
|
50
50
|
surface = [
|
|
51
51
|
"spglib>=1.16.5,<=2.4.0",
|
|
52
52
|
"pymatgen>=2022.2.1,<=2024.6.10",
|
|
53
53
|
]
|
|
54
54
|
phonopy = [
|
|
55
|
-
"phonopy>=2.16.2,<=2.
|
|
55
|
+
"phonopy>=2.16.2,<=2.26.3",
|
|
56
56
|
"spglib>=1.16.5,<=2.4.0",
|
|
57
57
|
]
|
|
58
58
|
pyxtal = ["pyxtal>=0.5.5,<=0.6.7"]
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-
|
|
11
|
+
"date": "2024-07-10T10:21:34+0200",
|
|
12
12
|
"dirty": true,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.0.
|
|
14
|
+
"full-revisionid": "bf6acd3da4ce39b1035efcb21b1f1027cca9d388",
|
|
15
|
+
"version": "0.0.27"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -47,11 +47,8 @@ def get_steinhardt_parameters(
|
|
|
47
47
|
sys = ase_to_pyscal(structure)
|
|
48
48
|
q = (4, 6) if q is None else q
|
|
49
49
|
|
|
50
|
-
sys.
|
|
51
|
-
|
|
52
|
-
sys.calculate_q(q, averaged=averaged)
|
|
53
|
-
|
|
54
|
-
sysq = np.array(sys.get_qvals(q, averaged=averaged))
|
|
50
|
+
sys.find.neighbors(method=neighbor_method, cutoff=cutoff)
|
|
51
|
+
sysq = np.array(sys.calculate.steinhardt_parameter(q, averaged=averaged))
|
|
55
52
|
|
|
56
53
|
if n_clusters is not None:
|
|
57
54
|
from sklearn import cluster
|
|
@@ -78,7 +75,7 @@ def get_centro_symmetry_descriptors(
|
|
|
78
75
|
csm (list) : list of centrosymmetry parameter
|
|
79
76
|
"""
|
|
80
77
|
sys = ase_to_pyscal(structure)
|
|
81
|
-
return np.array(sys.
|
|
78
|
+
return np.array(sys.calculate.centrosymmetry(nmax=num_neighbors))
|
|
82
79
|
|
|
83
80
|
|
|
84
81
|
def get_diamond_structure_descriptors(
|
|
@@ -101,23 +98,19 @@ def get_diamond_structure_descriptors(
|
|
|
101
98
|
(depends on `mode`)
|
|
102
99
|
"""
|
|
103
100
|
sys = ase_to_pyscal(structure)
|
|
104
|
-
diamond_dict = sys.
|
|
101
|
+
diamond_dict = sys.analyze.diamond_structure()
|
|
105
102
|
|
|
106
103
|
ovito_identifiers = [
|
|
104
|
+
"Other",
|
|
107
105
|
"Cubic diamond",
|
|
108
106
|
"Cubic diamond (1st neighbor)",
|
|
109
107
|
"Cubic diamond (2nd neighbor)",
|
|
110
108
|
"Hexagonal diamond",
|
|
111
109
|
"Hexagonal diamond (1st neighbor)",
|
|
112
110
|
"Hexagonal diamond (2nd neighbor)",
|
|
113
|
-
"Other",
|
|
114
111
|
]
|
|
115
112
|
pyscal_identifiers = [
|
|
116
113
|
"others",
|
|
117
|
-
"fcc",
|
|
118
|
-
"hcp",
|
|
119
|
-
"bcc",
|
|
120
|
-
"ico",
|
|
121
114
|
"cubic diamond",
|
|
122
115
|
"cubic diamond 1NN",
|
|
123
116
|
"cubic diamond 2NN",
|
|
@@ -125,19 +118,6 @@ def get_diamond_structure_descriptors(
|
|
|
125
118
|
"hex diamond 1NN",
|
|
126
119
|
"hex diamond 2NN",
|
|
127
120
|
]
|
|
128
|
-
convert_to_ovito = {
|
|
129
|
-
0: 6,
|
|
130
|
-
1: 6,
|
|
131
|
-
2: 6,
|
|
132
|
-
3: 6,
|
|
133
|
-
4: 6,
|
|
134
|
-
5: 0,
|
|
135
|
-
6: 1,
|
|
136
|
-
7: 2,
|
|
137
|
-
8: 3,
|
|
138
|
-
9: 4,
|
|
139
|
-
10: 5,
|
|
140
|
-
}
|
|
141
121
|
|
|
142
122
|
if mode == "total":
|
|
143
123
|
if not ovito_compatibility:
|
|
@@ -158,26 +138,22 @@ def get_diamond_structure_descriptors(
|
|
|
158
138
|
"IdentifyDiamond.counts.HEX_DIAMOND_SECOND_NEIGHBOR": diamond_dict[
|
|
159
139
|
"hex diamond 2NN"
|
|
160
140
|
],
|
|
161
|
-
"IdentifyDiamond.counts.OTHER": diamond_dict["others"]
|
|
162
|
-
+ diamond_dict["fcc"]
|
|
163
|
-
+ diamond_dict["hcp"]
|
|
164
|
-
+ diamond_dict["bcc"]
|
|
165
|
-
+ diamond_dict["ico"],
|
|
141
|
+
"IdentifyDiamond.counts.OTHER": diamond_dict["others"],
|
|
166
142
|
}
|
|
167
143
|
elif mode == "numeric":
|
|
168
144
|
if not ovito_compatibility:
|
|
169
|
-
return np.array(
|
|
145
|
+
return np.array(sys.atoms.structure)
|
|
170
146
|
else:
|
|
171
|
-
return np.array([
|
|
147
|
+
return np.array([6 if x == 0 else x - 1 for x in sys.atoms.structure])
|
|
148
|
+
|
|
172
149
|
elif mode == "str":
|
|
173
150
|
if not ovito_compatibility:
|
|
174
|
-
return np.array(
|
|
151
|
+
return np.array(
|
|
152
|
+
[pyscal_identifiers[structure] for structure in sys.atoms.structure]
|
|
153
|
+
)
|
|
175
154
|
else:
|
|
176
155
|
return np.array(
|
|
177
|
-
[
|
|
178
|
-
ovito_identifiers[convert_to_ovito[atom.structure]]
|
|
179
|
-
for atom in sys.atoms
|
|
180
|
-
]
|
|
156
|
+
[ovito_identifiers[structure] for structure in sys.atoms.structure]
|
|
181
157
|
)
|
|
182
158
|
else:
|
|
183
159
|
raise ValueError(
|
|
@@ -217,7 +193,7 @@ def get_adaptive_cna_descriptors(
|
|
|
217
193
|
"CommonNeighborAnalysis.counts.ICO",
|
|
218
194
|
]
|
|
219
195
|
|
|
220
|
-
cna = sys.
|
|
196
|
+
cna = sys.analyze.common_neighbor_analysis()
|
|
221
197
|
|
|
222
198
|
if mode == "total":
|
|
223
199
|
if not ovito_compatibility:
|
|
@@ -225,8 +201,7 @@ def get_adaptive_cna_descriptors(
|
|
|
225
201
|
else:
|
|
226
202
|
return {o: cna[p] for o, p in zip(ovito_parameter, pyscal_parameter)}
|
|
227
203
|
else:
|
|
228
|
-
|
|
229
|
-
cnalist = np.array([atom.structure for atom in structure])
|
|
204
|
+
cnalist = np.array(sys.atoms.structure)
|
|
230
205
|
if mode == "numeric":
|
|
231
206
|
return cnalist
|
|
232
207
|
elif mode == "str":
|
|
@@ -250,9 +225,8 @@ def get_voronoi_volumes(structure: Atoms) -> np.ndarray:
|
|
|
250
225
|
structure : (ase.atoms.Atoms): The structure to analyze.
|
|
251
226
|
"""
|
|
252
227
|
sys = ase_to_pyscal(structure)
|
|
253
|
-
sys.
|
|
254
|
-
|
|
255
|
-
return np.array([atom.volume for atom in structure])
|
|
228
|
+
sys.find.neighbors(method="voronoi")
|
|
229
|
+
return np.array(sys.atoms.voronoi.volume)
|
|
256
230
|
|
|
257
231
|
|
|
258
232
|
def find_solids(
|
|
@@ -287,8 +261,8 @@ def find_solids(
|
|
|
287
261
|
pyscal system: pyscal system when return_sys=True
|
|
288
262
|
"""
|
|
289
263
|
sys = ase_to_pyscal(structure)
|
|
290
|
-
sys.
|
|
291
|
-
sys.
|
|
264
|
+
sys.find.neighbors(method=neighbor_method, cutoff=cutoff)
|
|
265
|
+
sys.find.solids(
|
|
292
266
|
bonds=bonds,
|
|
293
267
|
threshold=threshold,
|
|
294
268
|
avgthreshold=avgthreshold,
|
|
@@ -299,6 +273,4 @@ def find_solids(
|
|
|
299
273
|
)
|
|
300
274
|
if return_sys:
|
|
301
275
|
return sys
|
|
302
|
-
|
|
303
|
-
solids = [atom for atom in structure if atom.solid]
|
|
304
|
-
return len(solids)
|
|
276
|
+
return np.sum(sys.atoms.solid)
|
|
@@ -9,6 +9,8 @@ import numpy as np
|
|
|
9
9
|
import spglib
|
|
10
10
|
from scipy.spatial import cKDTree
|
|
11
11
|
from typing import Optional
|
|
12
|
+
import string
|
|
13
|
+
from functools import cached_property
|
|
12
14
|
|
|
13
15
|
import structuretoolkit.common.helper
|
|
14
16
|
from structuretoolkit.common.error import SymmetryError
|
|
@@ -230,6 +232,33 @@ class Symmetry(dict):
|
|
|
230
232
|
np.einsum("ijk->jki", v_reshaped)[self.permutations],
|
|
231
233
|
).reshape(np.shape(vectors)) / len(self["rotations"])
|
|
232
234
|
|
|
235
|
+
def symmetrize_tensor(self, tensor: np.ndarray) -> np.ndarray:
|
|
236
|
+
"""
|
|
237
|
+
Symmetrization of any tensor. The tensor is defined by a matrix with a
|
|
238
|
+
shape of `n * (n_atoms, 3)`. For example, if the structure has 100
|
|
239
|
+
atoms, the vector can have a shape of (100, 3), (100, 3, 100, 3),
|
|
240
|
+
(100, 3, 100, 3, 100, 3) etc. Additionally, you can also have an array
|
|
241
|
+
of tensors, i.e. in this example you can have a shape like (4, 100, 3)
|
|
242
|
+
or (2, 100, 3, 100, 3). When the shape is (n, n_atoms, 3), the function
|
|
243
|
+
works in the same way as `symmetrize_vectors`, which might be somewhat
|
|
244
|
+
faster.
|
|
245
|
+
|
|
246
|
+
This function can be useful for the symmetrization of Hessian tensors,
|
|
247
|
+
or any other tensors which should be symmetric.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
tensors (ndarray): n * (n_atoms, 3) tensor to symmetrize
|
|
251
|
+
|
|
252
|
+
Returns
|
|
253
|
+
(np.ndarray) symmetrized tensor of the same shape
|
|
254
|
+
"""
|
|
255
|
+
return _SymmetrizeTensor(
|
|
256
|
+
tensor=tensor,
|
|
257
|
+
structure=self._structure,
|
|
258
|
+
rotations=self.rotations,
|
|
259
|
+
permutations=self.permutations,
|
|
260
|
+
).result
|
|
261
|
+
|
|
233
262
|
def _get_spglib_cell(
|
|
234
263
|
self, use_elements: Optional[bool] = None, use_magmoms: Optional[bool] = None
|
|
235
264
|
) -> tuple:
|
|
@@ -389,3 +418,73 @@ class Symmetry(dict):
|
|
|
389
418
|
if mesh is None:
|
|
390
419
|
raise SymmetryError(spglib.spglib.spglib_error.message)
|
|
391
420
|
return mesh
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class _SymmetrizeTensor:
|
|
424
|
+
def __init__(self, tensor, structure, rotations, permutations):
|
|
425
|
+
self._tensor = np.array(tensor)
|
|
426
|
+
self._structure = structure
|
|
427
|
+
self._rotations = rotations
|
|
428
|
+
self._permutations = permutations
|
|
429
|
+
|
|
430
|
+
@cached_property
|
|
431
|
+
def order(self):
|
|
432
|
+
order = len(self._tensor.shape) // 2
|
|
433
|
+
if self._tensor.shape[-2 * order :] != order * self._structure.positions.shape:
|
|
434
|
+
raise ValueError(
|
|
435
|
+
"Tensor must have a shape of a multiple of (n_atoms, 3). See"
|
|
436
|
+
" docstring for more info"
|
|
437
|
+
)
|
|
438
|
+
return order
|
|
439
|
+
|
|
440
|
+
@cached_property
|
|
441
|
+
def ij(self):
|
|
442
|
+
return string.ascii_lowercase[: 2 * self.order]
|
|
443
|
+
|
|
444
|
+
@property
|
|
445
|
+
def IJ(self):
|
|
446
|
+
return self.ij.upper()
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def ij_reorder(self):
|
|
450
|
+
return "".join(
|
|
451
|
+
[self.ij[ii] for ii in np.arange(2 * self.order).reshape(-1, 2).T.flatten()]
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
@property
|
|
455
|
+
def IJ_reorder(self):
|
|
456
|
+
return "".join(
|
|
457
|
+
[self.IJ[ii] for ii in np.arange(2 * self.order).reshape(2, -1).T.flatten()]
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
@cached_property
|
|
461
|
+
def t_t(self):
|
|
462
|
+
return np.einsum("...{}->{}...".format(self.ij, self.ij_reorder), self._tensor)
|
|
463
|
+
|
|
464
|
+
@cached_property
|
|
465
|
+
def str_einsum(self):
|
|
466
|
+
return (
|
|
467
|
+
",".join(
|
|
468
|
+
[I + i for i, I in zip(self.ij[-self.order :], self.IJ[-self.order :])]
|
|
469
|
+
)
|
|
470
|
+
+ ","
|
|
471
|
+
+ self.IJ[: self.order]
|
|
472
|
+
+ self.ij[self.order :]
|
|
473
|
+
+ "...->..."
|
|
474
|
+
+ self.IJ_reorder
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
@property
|
|
478
|
+
def result(self):
|
|
479
|
+
return np.mean(
|
|
480
|
+
[
|
|
481
|
+
np.einsum(
|
|
482
|
+
self.str_einsum,
|
|
483
|
+
*self.order * (rot,),
|
|
484
|
+
self.t_t[tuple(np.meshgrid(*self.order * (perm,), indexing="ij"))],
|
|
485
|
+
optimize=True,
|
|
486
|
+
)
|
|
487
|
+
for rot, perm in zip(self._rotations, self._permutations)
|
|
488
|
+
],
|
|
489
|
+
axis=0,
|
|
490
|
+
)
|
|
@@ -12,11 +12,7 @@ def ase_to_pyscal(structure: Atoms):
|
|
|
12
12
|
Returns:
|
|
13
13
|
Pyscal system: See the pyscal documentation.
|
|
14
14
|
"""
|
|
15
|
-
import
|
|
15
|
+
import pyscal3 as pc
|
|
16
16
|
|
|
17
|
-
sys = pc.System()
|
|
18
|
-
sys.read_inputfile(
|
|
19
|
-
filename=structure,
|
|
20
|
-
format="ase",
|
|
21
|
-
)
|
|
17
|
+
sys = pc.System(structure, format="ase")
|
|
22
18
|
return sys
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: structuretoolkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.27
|
|
4
4
|
Summary: build, analyse and visualise atomistic structures for materials science
|
|
5
5
|
Author-email: Jan Janssen <janssen@mpie.de>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -58,7 +58,7 @@ Provides-Extra: grainboundary
|
|
|
58
58
|
Requires-Dist: aimsgb<=1.1.1,>=1.0.2; extra == "grainboundary"
|
|
59
59
|
Requires-Dist: pymatgen<=2024.6.10,>=2022.2.1; extra == "grainboundary"
|
|
60
60
|
Provides-Extra: pyscal
|
|
61
|
-
Requires-Dist:
|
|
61
|
+
Requires-Dist: pyscal3==3.2.5; extra == "pyscal"
|
|
62
62
|
Provides-Extra: nglview
|
|
63
63
|
Requires-Dist: nglview<=3.1.2,>=2.7.7; extra == "nglview"
|
|
64
64
|
Provides-Extra: matplotlib
|
|
@@ -66,14 +66,14 @@ Requires-Dist: matplotlib==3.8.4; extra == "matplotlib"
|
|
|
66
66
|
Provides-Extra: plotly
|
|
67
67
|
Requires-Dist: plotly<=5.22.0,>=4.14.3; extra == "plotly"
|
|
68
68
|
Provides-Extra: clusters
|
|
69
|
-
Requires-Dist: scikit-learn==1.5.
|
|
69
|
+
Requires-Dist: scikit-learn==1.5.1; extra == "clusters"
|
|
70
70
|
Provides-Extra: symmetry
|
|
71
71
|
Requires-Dist: spglib<=2.4.0,>=1.16.5; extra == "symmetry"
|
|
72
72
|
Provides-Extra: surface
|
|
73
73
|
Requires-Dist: spglib<=2.4.0,>=1.16.5; extra == "surface"
|
|
74
74
|
Requires-Dist: pymatgen<=2024.6.10,>=2022.2.1; extra == "surface"
|
|
75
75
|
Provides-Extra: phonopy
|
|
76
|
-
Requires-Dist: phonopy<=2.
|
|
76
|
+
Requires-Dist: phonopy<=2.26.3,>=2.16.2; extra == "phonopy"
|
|
77
77
|
Requires-Dist: spglib<=2.4.0,>=1.16.5; extra == "phonopy"
|
|
78
78
|
Provides-Extra: pyxtal
|
|
79
79
|
Requires-Dist: pyxtal<=0.6.7,>=0.5.5; extra == "pyxtal"
|
|
@@ -3,7 +3,7 @@ numpy<=1.26.4,>=1.23.5
|
|
|
3
3
|
scipy<=1.14.0,>=1.9.3
|
|
4
4
|
|
|
5
5
|
[clusters]
|
|
6
|
-
scikit-learn==1.5.
|
|
6
|
+
scikit-learn==1.5.1
|
|
7
7
|
|
|
8
8
|
[dscribe]
|
|
9
9
|
dscribe==2.1.1
|
|
@@ -19,14 +19,14 @@ matplotlib==3.8.4
|
|
|
19
19
|
nglview<=3.1.2,>=2.7.7
|
|
20
20
|
|
|
21
21
|
[phonopy]
|
|
22
|
-
phonopy<=2.
|
|
22
|
+
phonopy<=2.26.3,>=2.16.2
|
|
23
23
|
spglib<=2.4.0,>=1.16.5
|
|
24
24
|
|
|
25
25
|
[plotly]
|
|
26
26
|
plotly<=5.22.0,>=4.14.3
|
|
27
27
|
|
|
28
28
|
[pyscal]
|
|
29
|
-
|
|
29
|
+
pyscal3==3.2.5
|
|
30
30
|
|
|
31
31
|
[pyxtal]
|
|
32
32
|
pyxtal<=0.6.7,>=0.5.5
|
|
@@ -9,7 +9,7 @@ from ase.atoms import Atoms
|
|
|
9
9
|
import structuretoolkit as stk
|
|
10
10
|
|
|
11
11
|
try:
|
|
12
|
-
import pyscal
|
|
12
|
+
import pyscal3 as pyscal
|
|
13
13
|
|
|
14
14
|
skip_pyscal_test = False
|
|
15
15
|
except ImportError:
|
|
@@ -17,7 +17,7 @@ except ImportError:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@unittest.skipIf(
|
|
20
|
-
skip_pyscal_test, "
|
|
20
|
+
skip_pyscal_test, "pyscal3 is not installed, so the pyscal3 tests are skipped."
|
|
21
21
|
)
|
|
22
22
|
class Testpyscal(unittest.TestCase):
|
|
23
23
|
@classmethod
|
|
@@ -394,10 +394,6 @@ class Testpyscalatoms(unittest.TestCase):
|
|
|
394
394
|
def test_analyse_pyscal_diamond_structure(self):
|
|
395
395
|
pyscal_keys = [
|
|
396
396
|
"others",
|
|
397
|
-
"fcc",
|
|
398
|
-
"hcp",
|
|
399
|
-
"bcc",
|
|
400
|
-
"ico",
|
|
401
397
|
"cubic diamond",
|
|
402
398
|
"cubic diamond 1NN",
|
|
403
399
|
"cubic diamond 2NN",
|
|
@@ -438,10 +434,11 @@ class Testpyscalatoms(unittest.TestCase):
|
|
|
438
434
|
res_dict_total = stk.analyse.get_diamond_structure_descriptors(
|
|
439
435
|
structure=self.si_dia, mode="total", ovito_compatibility=False
|
|
440
436
|
)
|
|
437
|
+
|
|
441
438
|
self.assertEqual(
|
|
442
439
|
sum([k in res_dict_total.keys() for k in pyscal_keys]), len(pyscal_keys)
|
|
443
440
|
)
|
|
444
|
-
self.assertEqual(res_dict_total[pyscal_keys[
|
|
441
|
+
self.assertEqual(res_dict_total[pyscal_keys[1]], len(self.si_dia))
|
|
445
442
|
|
|
446
443
|
res_numeric = stk.analyse.get_diamond_structure_descriptors(
|
|
447
444
|
structure=self.al_fcc, mode="numeric", ovito_compatibility=False
|
|
@@ -462,7 +459,7 @@ class Testpyscalatoms(unittest.TestCase):
|
|
|
462
459
|
structure=self.si_dia, mode="numeric", ovito_compatibility=False
|
|
463
460
|
)
|
|
464
461
|
self.assertEqual(len(res_numeric), len(self.si_dia))
|
|
465
|
-
self.assertTrue(all([v ==
|
|
462
|
+
self.assertTrue(all([v == 1 for v in res_numeric]))
|
|
466
463
|
|
|
467
464
|
res_str = stk.analyse.get_diamond_structure_descriptors(
|
|
468
465
|
structure=self.al_fcc, mode="str", ovito_compatibility=False
|
|
@@ -18,6 +18,7 @@ except ImportError:
|
|
|
18
18
|
|
|
19
19
|
try:
|
|
20
20
|
import spglib
|
|
21
|
+
from structuretoolkit.analyse.symmetry import _SymmetrizeTensor
|
|
21
22
|
|
|
22
23
|
skip_spglib_test = False
|
|
23
24
|
except ImportError:
|
|
@@ -108,20 +109,22 @@ class TestAtoms(unittest.TestCase):
|
|
|
108
109
|
"AlAl", scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)], cell=cell, pbc=True
|
|
109
110
|
)
|
|
110
111
|
v = np.random.rand(6).reshape(-1, 3)
|
|
112
|
+
sym = stk.analyse.get_symmetry(structure=Al)
|
|
111
113
|
self.assertAlmostEqual(
|
|
112
|
-
np.linalg.norm(
|
|
113
|
-
stk.analyse.get_symmetry(structure=Al).symmetrize_vectors(v)
|
|
114
|
-
),
|
|
114
|
+
np.linalg.norm(sym.symmetrize_vectors(v)),
|
|
115
115
|
0,
|
|
116
116
|
)
|
|
117
117
|
vv = np.random.rand(12).reshape(2, 2, 3)
|
|
118
|
-
for vvv in
|
|
118
|
+
for vvv in sym.symmetrize_vectors(vv):
|
|
119
119
|
self.assertAlmostEqual(np.linalg.norm(vvv), 0)
|
|
120
120
|
Al.positions[0, 0] += 0.01
|
|
121
|
-
w =
|
|
121
|
+
w = sym.symmetrize_vectors(v)
|
|
122
122
|
self.assertAlmostEqual(
|
|
123
123
|
np.absolute(w[:, 0]).sum(), np.linalg.norm(w, axis=-1).sum()
|
|
124
124
|
)
|
|
125
|
+
self.assertAlmostEqual(
|
|
126
|
+
np.linalg.norm(sym.symmetrize_vectors(v) - sym.symmetrize_tensor(v)), 0
|
|
127
|
+
)
|
|
125
128
|
|
|
126
129
|
def test_get_symmetry_dataset(self):
|
|
127
130
|
cell = 2.2 * np.identity(3)
|
|
@@ -155,7 +158,7 @@ class TestAtoms(unittest.TestCase):
|
|
|
155
158
|
)
|
|
156
159
|
|
|
157
160
|
def test_get_primitive_cell_hex(self):
|
|
158
|
-
elements = [
|
|
161
|
+
elements = ["Fe", "Fe", "Fe", "Fe", "O", "O", "O", "O", "O", "O"]
|
|
159
162
|
positions = [
|
|
160
163
|
[0.0, 0.0, 4.89],
|
|
161
164
|
[0.0, 0.0, 11.78],
|
|
@@ -174,8 +177,7 @@ class TestAtoms(unittest.TestCase):
|
|
|
174
177
|
sym = stk.analyse.get_symmetry(structure=structure_repeat)
|
|
175
178
|
structure_prim_base = sym.get_primitive_cell()
|
|
176
179
|
self.assertEqual(
|
|
177
|
-
structure_prim_base.get_chemical_symbols(),
|
|
178
|
-
structure.get_chemical_symbols()
|
|
180
|
+
structure_prim_base.get_chemical_symbols(), structure.get_chemical_symbols()
|
|
179
181
|
)
|
|
180
182
|
|
|
181
183
|
def test_get_equivalent_points(self):
|
|
@@ -284,5 +286,57 @@ class TestAtoms(unittest.TestCase):
|
|
|
284
286
|
stk.analyse.get_symmetry(structure=structure)
|
|
285
287
|
|
|
286
288
|
|
|
289
|
+
@unittest.skipIf(
|
|
290
|
+
skip_spglib_test, "spglib is not installed, so the spglib tests are skipped."
|
|
291
|
+
)
|
|
292
|
+
class TestSymmetrizeTensors(unittest.TestCase):
|
|
293
|
+
@classmethod
|
|
294
|
+
def setUpClass(cls):
|
|
295
|
+
cls.structure = bulk("Al", cubic=True, a=4.0).repeat(2)
|
|
296
|
+
cls.dataset = {
|
|
297
|
+
"structure": cls.structure,
|
|
298
|
+
"rotations": np.eye(3),
|
|
299
|
+
"permutations": np.arange(len(cls.structure)),
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
def test_order(self):
|
|
303
|
+
with self.assertRaises(ValueError):
|
|
304
|
+
_SymmetrizeTensor(
|
|
305
|
+
tensor=np.array([1]), **self.dataset
|
|
306
|
+
).order
|
|
307
|
+
self.assertEqual(
|
|
308
|
+
_SymmetrizeTensor(
|
|
309
|
+
tensor=np.random.randn(*self.structure.positions.shape), **self.dataset
|
|
310
|
+
).order,
|
|
311
|
+
1,
|
|
312
|
+
)
|
|
313
|
+
self.assertEqual(
|
|
314
|
+
_SymmetrizeTensor(
|
|
315
|
+
tensor=np.random.randn(*2 * self.structure.positions.shape),
|
|
316
|
+
**self.dataset,
|
|
317
|
+
).order,
|
|
318
|
+
2,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def test_indexing(self):
|
|
322
|
+
st = _SymmetrizeTensor(
|
|
323
|
+
tensor=np.random.randn(*2 * self.structure.positions.shape), **self.dataset
|
|
324
|
+
)
|
|
325
|
+
self.assertEqual(st.ij, "abcd")
|
|
326
|
+
self.assertEqual(st.ij_reorder, "acbd")
|
|
327
|
+
self.assertEqual(st.IJ, "ABCD")
|
|
328
|
+
self.assertEqual(st.IJ_reorder, "ACBD")
|
|
329
|
+
|
|
330
|
+
def test_str_einsum(self):
|
|
331
|
+
st = _SymmetrizeTensor(
|
|
332
|
+
tensor=np.random.randn(*2 * self.structure.positions.shape), **self.dataset
|
|
333
|
+
)
|
|
334
|
+
self.assertEqual(st.str_einsum, "Cc,Dd,ABcd...->...ACBD")
|
|
335
|
+
st = _SymmetrizeTensor(
|
|
336
|
+
tensor=np.random.randn(*self.structure.positions.shape), **self.dataset
|
|
337
|
+
)
|
|
338
|
+
self.assertEqual(st.str_einsum, "Bb,Ab...->...AB")
|
|
339
|
+
|
|
340
|
+
|
|
287
341
|
if __name__ == "__main__":
|
|
288
342
|
unittest.main()
|
|
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
|
{structuretoolkit-0.0.26 → structuretoolkit-0.0.27}/structuretoolkit.egg-info/dependency_links.txt
RENAMED
|
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
|