structuretoolkit 0.0.35__tar.gz → 0.0.37__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.35 → structuretoolkit-0.0.37}/PKG-INFO +11 -14
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/README.md +0 -1
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/pyproject.toml +10 -11
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/_version.py +2 -2
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/distance.py +2 -4
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/dscribe.py +7 -9
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/neighbors.py +31 -32
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/pyscal.py +11 -8
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/snap.py +4 -5
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/spatial.py +7 -7
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/strain.py +4 -6
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/symmetry.py +3 -4
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/build/__init__.py +0 -2
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/build/aimsgb.py +1 -2
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/build/compound.py +5 -7
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/build/sqs.py +17 -18
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/build/surface.py +8 -10
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/common/helper.py +2 -4
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/common/phonopy.py +3 -3
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/visualize.py +30 -30
- structuretoolkit-0.0.35/structuretoolkit/build/random.py +0 -107
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/.gitignore +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/LICENSE +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/__init__.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/__init__.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/analyse/phonopy.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/build/mesh.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/common/__init__.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/common/error.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/common/pymatgen.py +0 -0
- {structuretoolkit-0.0.35 → structuretoolkit-0.0.37}/structuretoolkit/common/pyscal.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structuretoolkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.37
|
|
4
4
|
Summary: build, analyse and visualise atomistic structures for materials science
|
|
5
5
|
Project-URL: Homepage, https://github.com/pyiron/structuretoolkit
|
|
6
6
|
Project-URL: Documentation, https://github.com/pyiron/structuretoolkit
|
|
@@ -41,37 +41,35 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
41
41
|
Classifier: Intended Audience :: Science/Research
|
|
42
42
|
Classifier: License :: OSI Approved :: BSD License
|
|
43
43
|
Classifier: Operating System :: OS Independent
|
|
44
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
45
44
|
Classifier: Programming Language :: Python :: 3.10
|
|
46
45
|
Classifier: Programming Language :: Python :: 3.11
|
|
47
46
|
Classifier: Programming Language :: Python :: 3.12
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
48
48
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
49
|
-
Requires-Python: <3.
|
|
49
|
+
Requires-Python: <3.14,>=3.10
|
|
50
50
|
Requires-Dist: ase<=3.26.0,>=3.20.1
|
|
51
|
-
Requires-Dist: numpy<=2.3.
|
|
52
|
-
Requires-Dist: scipy<=1.16.
|
|
51
|
+
Requires-Dist: numpy<=2.3.4,>=1.23.5
|
|
52
|
+
Requires-Dist: scipy<=1.16.3,>=1.15.0
|
|
53
53
|
Provides-Extra: clusters
|
|
54
|
-
Requires-Dist: scikit-learn==1.
|
|
54
|
+
Requires-Dist: scikit-learn==1.7.2; extra == 'clusters'
|
|
55
55
|
Provides-Extra: dscribe
|
|
56
56
|
Requires-Dist: dscribe==2.1.2; extra == 'dscribe'
|
|
57
57
|
Provides-Extra: grainboundary
|
|
58
58
|
Requires-Dist: aimsgb<=1.1.1,>=1.0.2; extra == 'grainboundary'
|
|
59
|
-
Requires-Dist: pymatgen<=2025.
|
|
59
|
+
Requires-Dist: pymatgen<=2025.6.14,>=2022.2.1; extra == 'grainboundary'
|
|
60
60
|
Provides-Extra: matplotlib
|
|
61
|
-
Requires-Dist: matplotlib==3.10.
|
|
61
|
+
Requires-Dist: matplotlib==3.10.7; extra == 'matplotlib'
|
|
62
62
|
Provides-Extra: nglview
|
|
63
63
|
Requires-Dist: nglview<=3.1.4,>=2.7.7; extra == 'nglview'
|
|
64
64
|
Provides-Extra: phonopy
|
|
65
|
-
Requires-Dist: phonopy<=2.43.
|
|
65
|
+
Requires-Dist: phonopy<=2.43.6,>=2.16.2; extra == 'phonopy'
|
|
66
66
|
Requires-Dist: spglib<=2.6.0,>=1.16.5; extra == 'phonopy'
|
|
67
67
|
Provides-Extra: plotly
|
|
68
|
-
Requires-Dist: plotly<=6.3.
|
|
68
|
+
Requires-Dist: plotly<=6.3.1,>=4.14.3; extra == 'plotly'
|
|
69
69
|
Provides-Extra: pyscal
|
|
70
70
|
Requires-Dist: pyscal3<=3.3.0,>=3.2.5; extra == 'pyscal'
|
|
71
|
-
Provides-Extra: pyxtal
|
|
72
|
-
Requires-Dist: pyxtal<=1.1.1,>=0.5.5; extra == 'pyxtal'
|
|
73
71
|
Provides-Extra: surface
|
|
74
|
-
Requires-Dist: pymatgen<=2025.
|
|
72
|
+
Requires-Dist: pymatgen<=2025.6.14,>=2022.2.1; extra == 'surface'
|
|
75
73
|
Requires-Dist: spglib<=2.6.0,>=1.16.5; extra == 'surface'
|
|
76
74
|
Provides-Extra: symmetry
|
|
77
75
|
Requires-Dist: spglib<=2.6.0,>=1.16.5; extra == 'symmetry'
|
|
@@ -127,7 +125,6 @@ stk.plot3d(structure)
|
|
|
127
125
|
* `stk.build.high_index_surface()`
|
|
128
126
|
* `stk.build.get_high_index_surface_info()`
|
|
129
127
|
* `stk.build.sqs_structures()`
|
|
130
|
-
* `stk.build.pyxtal()`
|
|
131
128
|
* `stk.build.B2()`
|
|
132
129
|
* `stk.build.C14()`
|
|
133
130
|
* `stk.build.C15()`
|
|
@@ -11,22 +11,22 @@ authors = [
|
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
license = { file = "LICENSE" }
|
|
13
13
|
keywords = ["pyiron"]
|
|
14
|
-
requires-python = ">=3.
|
|
14
|
+
requires-python = ">=3.10, <3.14"
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Development Status :: 5 - Production/Stable",
|
|
17
17
|
"Topic :: Scientific/Engineering :: Physics",
|
|
18
18
|
"License :: OSI Approved :: BSD License",
|
|
19
19
|
"Intended Audience :: Science/Research",
|
|
20
20
|
"Operating System :: OS Independent",
|
|
21
|
-
"Programming Language :: Python :: 3.9",
|
|
22
21
|
"Programming Language :: Python :: 3.10",
|
|
23
22
|
"Programming Language :: Python :: 3.11",
|
|
24
23
|
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
25
|
]
|
|
26
26
|
dependencies = [
|
|
27
27
|
"ase>=3.20.1,<=3.26.0",
|
|
28
|
-
"numpy>=1.23.5,<=2.3.
|
|
29
|
-
"scipy>=1.
|
|
28
|
+
"numpy>=1.23.5,<=2.3.4",
|
|
29
|
+
"scipy>=1.15.0,<=1.16.3",
|
|
30
30
|
]
|
|
31
31
|
dynamic = ["version"]
|
|
32
32
|
|
|
@@ -39,23 +39,22 @@ Repository = "https://github.com/pyiron/structuretoolkit"
|
|
|
39
39
|
dscribe = ["dscribe==2.1.2"]
|
|
40
40
|
grainboundary = [
|
|
41
41
|
"aimsgb>=1.0.2,<=1.1.1",
|
|
42
|
-
"pymatgen>=2022.2.1,<=2025.
|
|
42
|
+
"pymatgen>=2022.2.1,<=2025.6.14",
|
|
43
43
|
]
|
|
44
44
|
pyscal = ["pyscal3>=3.2.5,<=3.3.0"]
|
|
45
45
|
nglview = ["nglview>=2.7.7,<=3.1.4"]
|
|
46
|
-
matplotlib = ["matplotlib==3.10.
|
|
47
|
-
plotly = ["plotly>=4.14.3,<=6.3.
|
|
48
|
-
clusters = ["scikit-learn==1.
|
|
46
|
+
matplotlib = ["matplotlib==3.10.7"]
|
|
47
|
+
plotly = ["plotly>=4.14.3,<=6.3.1"]
|
|
48
|
+
clusters = ["scikit-learn==1.7.2"]
|
|
49
49
|
symmetry = ["spglib>=1.16.5,<=2.6.0"]
|
|
50
50
|
surface = [
|
|
51
51
|
"spglib>=1.16.5,<=2.6.0",
|
|
52
|
-
"pymatgen>=2022.2.1,<=2025.
|
|
52
|
+
"pymatgen>=2022.2.1,<=2025.6.14",
|
|
53
53
|
]
|
|
54
54
|
phonopy = [
|
|
55
|
-
"phonopy>=2.16.2,<=2.43.
|
|
55
|
+
"phonopy>=2.16.2,<=2.43.6",
|
|
56
56
|
"spglib>=1.16.5,<=2.6.0",
|
|
57
57
|
]
|
|
58
|
-
pyxtal = ["pyxtal>=0.5.5,<=1.1.1"]
|
|
59
58
|
|
|
60
59
|
[tool.ruff]
|
|
61
60
|
exclude = [".ci_support", "tests", "setup.py", "_version.py"]
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0,
|
|
31
|
+
__version__ = version = '0.0.37'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 37)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
from ase.atoms import Atoms
|
|
5
3
|
|
|
6
4
|
|
|
7
5
|
def get_distances_array(
|
|
8
6
|
structure: Atoms,
|
|
9
|
-
p1:
|
|
10
|
-
p2:
|
|
7
|
+
p1: np.ndarray | None = None,
|
|
8
|
+
p2: np.ndarray | None = None,
|
|
11
9
|
mic: bool = True,
|
|
12
10
|
vectors: bool = False,
|
|
13
11
|
) -> np.ndarray:
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
from ase.atoms import Atoms
|
|
5
3
|
|
|
6
4
|
|
|
7
5
|
def soap_descriptor_per_atom(
|
|
8
6
|
structure: Atoms,
|
|
9
|
-
r_cut:
|
|
10
|
-
n_max:
|
|
11
|
-
l_max:
|
|
12
|
-
sigma:
|
|
7
|
+
r_cut: float | None = None,
|
|
8
|
+
n_max: int | None = None,
|
|
9
|
+
l_max: int | None = None,
|
|
10
|
+
sigma: float | None = 1.0,
|
|
13
11
|
rbf: str = "gto",
|
|
14
|
-
weighting:
|
|
12
|
+
weighting: np.ndarray | None = None,
|
|
15
13
|
average: str = "off",
|
|
16
14
|
compression: dict = None,
|
|
17
|
-
species:
|
|
15
|
+
species: list | None = None,
|
|
18
16
|
periodic: bool = True,
|
|
19
17
|
sparse: bool = False,
|
|
20
18
|
dtype: str = "float64",
|
|
21
|
-
centers:
|
|
19
|
+
centers: np.ndarray | None = None,
|
|
22
20
|
n_jobs: int = 1,
|
|
23
21
|
only_physical_cores: bool = False,
|
|
24
22
|
verbose: bool = False,
|
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
import itertools
|
|
5
5
|
import warnings
|
|
6
|
-
from typing import Optional, Union
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
from ase.atoms import Atoms
|
|
10
9
|
from scipy.sparse import coo_matrix
|
|
11
10
|
from scipy.spatial import cKDTree
|
|
12
11
|
from scipy.spatial.transform import Rotation
|
|
13
|
-
from scipy.special import gamma,
|
|
12
|
+
from scipy.special import gamma, sph_harm_y
|
|
14
13
|
|
|
15
14
|
from structuretoolkit.common.helper import (
|
|
16
15
|
get_average_of_unique_labels,
|
|
@@ -149,8 +148,8 @@ class Tree:
|
|
|
149
148
|
def _reshape(
|
|
150
149
|
self,
|
|
151
150
|
value: np.ndarray,
|
|
152
|
-
key:
|
|
153
|
-
ref_vector:
|
|
151
|
+
key: str | None = None,
|
|
152
|
+
ref_vector: np.ndarray | None = None,
|
|
154
153
|
) -> np.ndarray:
|
|
155
154
|
"""
|
|
156
155
|
Reshape the given value based on the specified key and reference vector.
|
|
@@ -258,7 +257,7 @@ class Tree:
|
|
|
258
257
|
+ " with the correct norm_order value"
|
|
259
258
|
)
|
|
260
259
|
|
|
261
|
-
def _get_max_length(self, ref_vector:
|
|
260
|
+
def _get_max_length(self, ref_vector: np.ndarray | None = None) -> int:
|
|
262
261
|
"""
|
|
263
262
|
Get the maximum length of the reference vector.
|
|
264
263
|
|
|
@@ -279,7 +278,7 @@ class Tree:
|
|
|
279
278
|
return max(len(dd[dd < np.inf]) for dd in ref_vector)
|
|
280
279
|
|
|
281
280
|
def _contract(
|
|
282
|
-
self, value: np.ndarray, ref_vector:
|
|
281
|
+
self, value: np.ndarray, ref_vector: np.ndarray | None = None
|
|
283
282
|
) -> np.ndarray:
|
|
284
283
|
"""
|
|
285
284
|
Contract the given value based on the specified reference vector.
|
|
@@ -295,7 +294,7 @@ class Tree:
|
|
|
295
294
|
return value
|
|
296
295
|
return [
|
|
297
296
|
vv[: np.sum(dist < np.inf)]
|
|
298
|
-
for vv, dist in zip(value, self.filled.distances)
|
|
297
|
+
for vv, dist in zip(value, self.filled.distances, strict=True)
|
|
299
298
|
]
|
|
300
299
|
|
|
301
300
|
def _allow_ragged_to_mode(self, new_bool: bool) -> str:
|
|
@@ -362,7 +361,7 @@ class Tree:
|
|
|
362
361
|
def _get_distances_and_indices(
|
|
363
362
|
self,
|
|
364
363
|
positions: np.ndarray,
|
|
365
|
-
num_neighbors:
|
|
364
|
+
num_neighbors: int | None = None,
|
|
366
365
|
cutoff_radius: float = np.inf,
|
|
367
366
|
width_buffer: float = 1.2,
|
|
368
367
|
) -> tuple[np.ndarray, np.ndarray]:
|
|
@@ -431,10 +430,10 @@ class Tree:
|
|
|
431
430
|
def _get_vectors(
|
|
432
431
|
self,
|
|
433
432
|
positions: np.ndarray,
|
|
434
|
-
num_neighbors:
|
|
433
|
+
num_neighbors: int | None = None,
|
|
435
434
|
cutoff_radius: float = np.inf,
|
|
436
|
-
distances:
|
|
437
|
-
indices:
|
|
435
|
+
distances: np.ndarray | None = None,
|
|
436
|
+
indices: np.ndarray | None = None,
|
|
438
437
|
width_buffer: float = 1.2,
|
|
439
438
|
) -> np.ndarray:
|
|
440
439
|
"""
|
|
@@ -470,7 +469,7 @@ class Tree:
|
|
|
470
469
|
|
|
471
470
|
def _estimate_num_neighbors(
|
|
472
471
|
self,
|
|
473
|
-
num_neighbors:
|
|
472
|
+
num_neighbors: int | None = None,
|
|
474
473
|
cutoff_radius: float = np.inf,
|
|
475
474
|
width_buffer: float = 1.2,
|
|
476
475
|
) -> int:
|
|
@@ -515,7 +514,7 @@ class Tree:
|
|
|
515
514
|
|
|
516
515
|
def _estimate_width(
|
|
517
516
|
self,
|
|
518
|
-
num_neighbors:
|
|
517
|
+
num_neighbors: int | None = None,
|
|
519
518
|
cutoff_radius: float = np.inf,
|
|
520
519
|
width_buffer: float = 1.2,
|
|
521
520
|
) -> float:
|
|
@@ -551,7 +550,7 @@ class Tree:
|
|
|
551
550
|
def get_neighborhood(
|
|
552
551
|
self,
|
|
553
552
|
positions: np.ndarray,
|
|
554
|
-
num_neighbors:
|
|
553
|
+
num_neighbors: int | None = None,
|
|
555
554
|
cutoff_radius: float = np.inf,
|
|
556
555
|
width_buffer: float = 1.2,
|
|
557
556
|
) -> "Tree":
|
|
@@ -647,7 +646,7 @@ class Tree:
|
|
|
647
646
|
l: np.ndarray,
|
|
648
647
|
m: np.ndarray,
|
|
649
648
|
cutoff_radius: float = np.inf,
|
|
650
|
-
rotation:
|
|
649
|
+
rotation: np.ndarray | None = None,
|
|
651
650
|
) -> np.ndarray:
|
|
652
651
|
"""
|
|
653
652
|
Args:
|
|
@@ -668,7 +667,7 @@ class Tree:
|
|
|
668
667
|
The angles are calculated based on `self.vecs`, where the azimuthal angle is defined on the
|
|
669
668
|
xy-plane and the polar angle is along the z-axis.
|
|
670
669
|
|
|
671
|
-
See more on: scipy.special.
|
|
670
|
+
See more on: scipy.special.sph_harm_y
|
|
672
671
|
|
|
673
672
|
"""
|
|
674
673
|
vecs = self.filled.vecs
|
|
@@ -685,7 +684,7 @@ class Tree:
|
|
|
685
684
|
phi[within_cutoff] = np.arctan2(
|
|
686
685
|
np.linalg.norm(vecs[within_cutoff, :2], axis=-1), vecs[within_cutoff, 2]
|
|
687
686
|
)
|
|
688
|
-
return np.sum(
|
|
687
|
+
return np.sum(sph_harm_y(l, m, phi, theta) * within_cutoff, axis=-1) / np.sum(
|
|
689
688
|
within_cutoff, axis=-1
|
|
690
689
|
)
|
|
691
690
|
|
|
@@ -868,8 +867,8 @@ class Neighbors(Tree):
|
|
|
868
867
|
|
|
869
868
|
def get_local_shells(
|
|
870
869
|
self,
|
|
871
|
-
mode:
|
|
872
|
-
tolerance:
|
|
870
|
+
mode: str | None = None,
|
|
871
|
+
tolerance: int | None = None,
|
|
873
872
|
cluster_by_distances: bool = False,
|
|
874
873
|
cluster_by_vecs: bool = False,
|
|
875
874
|
) -> np.ndarray:
|
|
@@ -947,8 +946,8 @@ class Neighbors(Tree):
|
|
|
947
946
|
|
|
948
947
|
def get_global_shells(
|
|
949
948
|
self,
|
|
950
|
-
mode:
|
|
951
|
-
tolerance:
|
|
949
|
+
mode: str | None = None,
|
|
950
|
+
tolerance: int | None = None,
|
|
952
951
|
cluster_by_distances: bool = False,
|
|
953
952
|
cluster_by_vecs: bool = False,
|
|
954
953
|
) -> np.ndarray:
|
|
@@ -1008,7 +1007,7 @@ class Neighbors(Tree):
|
|
|
1008
1007
|
|
|
1009
1008
|
def get_shell_matrix(
|
|
1010
1009
|
self,
|
|
1011
|
-
chemical_pair:
|
|
1010
|
+
chemical_pair: list[str] | None = None,
|
|
1012
1011
|
cluster_by_distances: bool = False,
|
|
1013
1012
|
cluster_by_vecs: bool = False,
|
|
1014
1013
|
):
|
|
@@ -1107,8 +1106,8 @@ class Neighbors(Tree):
|
|
|
1107
1106
|
|
|
1108
1107
|
def cluster_by_vecs(
|
|
1109
1108
|
self,
|
|
1110
|
-
distance_threshold:
|
|
1111
|
-
n_clusters:
|
|
1109
|
+
distance_threshold: float | None = None,
|
|
1110
|
+
n_clusters: int | None = None,
|
|
1112
1111
|
linkage: str = "complete",
|
|
1113
1112
|
metric: str = "euclidean",
|
|
1114
1113
|
):
|
|
@@ -1152,8 +1151,8 @@ class Neighbors(Tree):
|
|
|
1152
1151
|
|
|
1153
1152
|
def cluster_by_distances(
|
|
1154
1153
|
self,
|
|
1155
|
-
distance_threshold:
|
|
1156
|
-
n_clusters:
|
|
1154
|
+
distance_threshold: float | None = None,
|
|
1155
|
+
n_clusters: int | None = None,
|
|
1157
1156
|
linkage: str = "complete",
|
|
1158
1157
|
metric: str = "euclidean",
|
|
1159
1158
|
use_vecs: bool = False,
|
|
@@ -1225,7 +1224,7 @@ class Neighbors(Tree):
|
|
|
1225
1224
|
|
|
1226
1225
|
def cluster_analysis(
|
|
1227
1226
|
self, id_list: list, return_cluster_sizes: bool = False
|
|
1228
|
-
) ->
|
|
1227
|
+
) -> dict[int, list[int]] | tuple[dict[int, list[int]], list[int]]:
|
|
1229
1228
|
"""
|
|
1230
1229
|
Perform cluster analysis on a list of atom IDs.
|
|
1231
1230
|
|
|
@@ -1283,7 +1282,7 @@ class Neighbors(Tree):
|
|
|
1283
1282
|
def get_bonds(
|
|
1284
1283
|
self,
|
|
1285
1284
|
radius: float = np.inf,
|
|
1286
|
-
max_shells:
|
|
1285
|
+
max_shells: int | None = None,
|
|
1287
1286
|
prec: float = 0.1,
|
|
1288
1287
|
) -> list[dict[str, list[list[int]]]]:
|
|
1289
1288
|
"""
|
|
@@ -1322,7 +1321,7 @@ class Neighbors(Tree):
|
|
|
1322
1321
|
el_list = self._ref_structure.get_chemical_symbols()
|
|
1323
1322
|
|
|
1324
1323
|
ind_shell = []
|
|
1325
|
-
for d, i in zip(dist, ind):
|
|
1324
|
+
for d, i in zip(dist, ind, strict=True):
|
|
1326
1325
|
id_list = get_cluster(d[d < radius], i[d < radius])
|
|
1327
1326
|
ia_shells_dict = {}
|
|
1328
1327
|
for i_shell_list in id_list:
|
|
@@ -1361,7 +1360,7 @@ def get_neighbors(
|
|
|
1361
1360
|
structure: Atoms,
|
|
1362
1361
|
num_neighbors: int = 12,
|
|
1363
1362
|
tolerance: int = 2,
|
|
1364
|
-
id_list:
|
|
1363
|
+
id_list: list | None = None,
|
|
1365
1364
|
cutoff_radius: float = np.inf,
|
|
1366
1365
|
width_buffer: float = 1.2,
|
|
1367
1366
|
mode: str = "filled",
|
|
@@ -1400,12 +1399,12 @@ def _get_neighbors(
|
|
|
1400
1399
|
structure: Atoms,
|
|
1401
1400
|
num_neighbors: int = 12,
|
|
1402
1401
|
tolerance: int = 2,
|
|
1403
|
-
id_list:
|
|
1402
|
+
id_list: list | None = None,
|
|
1404
1403
|
cutoff_radius: float = np.inf,
|
|
1405
1404
|
width_buffer: float = 1.2,
|
|
1406
1405
|
get_tree: bool = False,
|
|
1407
1406
|
norm_order: int = 2,
|
|
1408
|
-
) ->
|
|
1407
|
+
) -> Neighbors | Tree:
|
|
1409
1408
|
"""
|
|
1410
1409
|
Get the neighbors of atoms in a structure.
|
|
1411
1410
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
|
|
2
2
|
# Distributed under the terms of "New BSD License", see the LICENSE file.
|
|
3
3
|
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from ase.atoms import Atoms
|
|
@@ -24,10 +24,10 @@ def get_steinhardt_parameters(
|
|
|
24
24
|
structure: Atoms,
|
|
25
25
|
neighbor_method: str = "cutoff",
|
|
26
26
|
cutoff: float = 0.0,
|
|
27
|
-
n_clusters:
|
|
28
|
-
q:
|
|
27
|
+
n_clusters: int | None = 2,
|
|
28
|
+
q: tuple | None = None,
|
|
29
29
|
averaged: bool = False,
|
|
30
|
-
) ->
|
|
30
|
+
) -> tuple[np.ndarray] | tuple[np.ndarray, np.ndarray]:
|
|
31
31
|
"""
|
|
32
32
|
Calculate Steinhardts parameters
|
|
33
33
|
|
|
@@ -55,7 +55,7 @@ def get_steinhardt_parameters(
|
|
|
55
55
|
|
|
56
56
|
cl = cluster.KMeans(n_clusters=n_clusters)
|
|
57
57
|
|
|
58
|
-
ind = cl.fit(list(zip(*sysq))).labels_
|
|
58
|
+
ind = cl.fit(list(zip(*sysq, strict=True))).labels_
|
|
59
59
|
return sysq, ind
|
|
60
60
|
else:
|
|
61
61
|
return sysq
|
|
@@ -80,7 +80,7 @@ def get_centro_symmetry_descriptors(
|
|
|
80
80
|
|
|
81
81
|
def get_diamond_structure_descriptors(
|
|
82
82
|
structure: Atoms, mode: str = "total", ovito_compatibility: bool = False
|
|
83
|
-
) ->
|
|
83
|
+
) -> dict[str, int] | np.ndarray:
|
|
84
84
|
"""
|
|
85
85
|
Analyse diamond structure
|
|
86
86
|
|
|
@@ -197,7 +197,10 @@ def get_adaptive_cna_descriptors(
|
|
|
197
197
|
if not ovito_compatibility:
|
|
198
198
|
return cna
|
|
199
199
|
else:
|
|
200
|
-
return {
|
|
200
|
+
return {
|
|
201
|
+
o: cna[p]
|
|
202
|
+
for o, p in zip(ovito_parameter, pyscal_parameter, strict=True)
|
|
203
|
+
}
|
|
201
204
|
else:
|
|
202
205
|
cnalist = np.array(sys.atoms.structure)
|
|
203
206
|
if mode == "numeric":
|
|
@@ -241,7 +244,7 @@ def find_solids(
|
|
|
241
244
|
q: int = 6,
|
|
242
245
|
right: bool = True,
|
|
243
246
|
return_sys: bool = False,
|
|
244
|
-
) ->
|
|
247
|
+
) -> int | Any:
|
|
245
248
|
"""
|
|
246
249
|
Get the number of solids or the corresponding pyscal system.
|
|
247
250
|
Calls necessary pyscal methods as described in https://pyscal.org/en/latest/methods/03_solidliquid.html.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from ctypes import POINTER, c_double, c_int, cast
|
|
2
|
-
from typing import Optional, Union
|
|
3
2
|
|
|
4
3
|
import numpy as np
|
|
5
4
|
from ase.atoms import Atoms
|
|
@@ -70,7 +69,7 @@ def get_snap_descriptors_per_atom(
|
|
|
70
69
|
rmin0: float = 0.0,
|
|
71
70
|
bzeroflag: bool = False,
|
|
72
71
|
quadraticflag: bool = False,
|
|
73
|
-
weights:
|
|
72
|
+
weights: list | np.ndarray | None = None,
|
|
74
73
|
cutoff: float = 10.0,
|
|
75
74
|
) -> np.ndarray:
|
|
76
75
|
"""
|
|
@@ -121,7 +120,7 @@ def get_snap_descriptor_derivatives(
|
|
|
121
120
|
rmin0: float = 0.0,
|
|
122
121
|
bzeroflag: bool = False,
|
|
123
122
|
quadraticflag: bool = False,
|
|
124
|
-
weights:
|
|
123
|
+
weights: list | np.ndarray | None = None,
|
|
125
124
|
cutoff: float = 10.0,
|
|
126
125
|
):
|
|
127
126
|
"""
|
|
@@ -525,7 +524,7 @@ def _set_computes_snap(lmp, bispec_options: dict):
|
|
|
525
524
|
kw_substrings = [f"{k} {v}" for k, v in kw_options.items()]
|
|
526
525
|
kwargs = " ".join(kw_substrings)
|
|
527
526
|
|
|
528
|
-
for _op, base in zip(("b", "db", "vb"), (base_b, base_db, base_vb)):
|
|
527
|
+
for _op, base in zip(("b", "db", "vb"), (base_b, base_db, base_vb), strict=True):
|
|
529
528
|
command = f"{base} {radelem} {wj} {kwargs}"
|
|
530
529
|
lmp.command(command)
|
|
531
530
|
|
|
@@ -659,7 +658,7 @@ def _get_default_parameters(
|
|
|
659
658
|
rmin0: float = 0.0,
|
|
660
659
|
bzeroflag: bool = False,
|
|
661
660
|
quadraticflag: bool = False,
|
|
662
|
-
weights:
|
|
661
|
+
weights: list | np.ndarray | None = None,
|
|
663
662
|
cutoff: float = 10.0,
|
|
664
663
|
):
|
|
665
664
|
"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
|
|
2
2
|
# Distributed under the terms of "New BSD License", see the LICENSE file.
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from collections.abc import Callable
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from ase.atoms import Atoms
|
|
@@ -225,7 +225,7 @@ class Interstitials:
|
|
|
225
225
|
l_values: np.ndarray = np.arange(2, 13),
|
|
226
226
|
q_eps: float = 0.3,
|
|
227
227
|
var_ratio: float = 5.0,
|
|
228
|
-
min_samples:
|
|
228
|
+
min_samples: int | None = None,
|
|
229
229
|
neigh_args: dict = None,
|
|
230
230
|
**kwargs,
|
|
231
231
|
):
|
|
@@ -294,7 +294,7 @@ class Interstitials:
|
|
|
294
294
|
self.structure = structure
|
|
295
295
|
|
|
296
296
|
def run_workflow(
|
|
297
|
-
self, positions:
|
|
297
|
+
self, positions: np.ndarray | None = None, steps: int = -1
|
|
298
298
|
) -> np.ndarray:
|
|
299
299
|
"""
|
|
300
300
|
Run the workflow to obtain the interstitial positions.
|
|
@@ -407,7 +407,7 @@ def get_interstitials(
|
|
|
407
407
|
l_values: np.ndarray = np.arange(2, 13),
|
|
408
408
|
q_eps: float = 0.3,
|
|
409
409
|
var_ratio: float = 5.0,
|
|
410
|
-
min_samples:
|
|
410
|
+
min_samples: int | None = None,
|
|
411
411
|
neigh_args: dict = None,
|
|
412
412
|
**kwargs,
|
|
413
413
|
) -> Interstitials:
|
|
@@ -457,7 +457,7 @@ get_interstitials.__doc__ = (
|
|
|
457
457
|
def get_layers(
|
|
458
458
|
structure: Atoms,
|
|
459
459
|
distance_threshold: float = 0.01,
|
|
460
|
-
id_list:
|
|
460
|
+
id_list: list[int] | None = None,
|
|
461
461
|
wrap_atoms: bool = True,
|
|
462
462
|
planes: np.ndarray = None,
|
|
463
463
|
cluster_method: str = None,
|
|
@@ -690,9 +690,9 @@ def get_delaunay_neighbors(structure: Atoms, width_buffer: float = 10.0) -> np.n
|
|
|
690
690
|
|
|
691
691
|
def get_cluster_positions(
|
|
692
692
|
structure: Atoms,
|
|
693
|
-
positions:
|
|
693
|
+
positions: np.ndarray | None = None,
|
|
694
694
|
eps: float = 1.0,
|
|
695
|
-
buffer_width:
|
|
695
|
+
buffer_width: float | None = None,
|
|
696
696
|
return_labels: bool = False,
|
|
697
697
|
) -> np.ndarray:
|
|
698
698
|
"""
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
from ase.atoms import Atoms
|
|
5
3
|
from scipy.spatial.transform import Rotation
|
|
@@ -30,7 +28,7 @@ class Strain:
|
|
|
30
28
|
self,
|
|
31
29
|
structure: Atoms,
|
|
32
30
|
ref_structure: Atoms,
|
|
33
|
-
num_neighbors:
|
|
31
|
+
num_neighbors: int | None = None,
|
|
34
32
|
only_bulk_type: bool = False,
|
|
35
33
|
):
|
|
36
34
|
"""
|
|
@@ -85,7 +83,7 @@ class Strain:
|
|
|
85
83
|
)
|
|
86
84
|
|
|
87
85
|
def _get_perpendicular_unit_vectors(
|
|
88
|
-
self, vec: np.ndarray, vec_axis:
|
|
86
|
+
self, vec: np.ndarray, vec_axis: np.ndarray | None = None
|
|
89
87
|
) -> np.ndarray:
|
|
90
88
|
"""
|
|
91
89
|
Get the perpendicular unit vectors of the given vectors.
|
|
@@ -146,7 +144,7 @@ class Strain:
|
|
|
146
144
|
self,
|
|
147
145
|
vec_before: np.ndarray,
|
|
148
146
|
vec_after: np.ndarray,
|
|
149
|
-
vec_axis:
|
|
147
|
+
vec_axis: np.ndarray | None = None,
|
|
150
148
|
) -> np.ndarray:
|
|
151
149
|
"""
|
|
152
150
|
Calculate the rotation matrix that transforms the `vec_before` vectors to the `vec_after` vectors.
|
|
@@ -319,7 +317,7 @@ class Strain:
|
|
|
319
317
|
def get_strain(
|
|
320
318
|
structure: Atoms,
|
|
321
319
|
ref_structure: Atoms,
|
|
322
|
-
num_neighbors:
|
|
320
|
+
num_neighbors: int | None = None,
|
|
323
321
|
only_bulk_type: bool = False,
|
|
324
322
|
return_object: bool = False,
|
|
325
323
|
):
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import ast
|
|
5
5
|
import dataclasses
|
|
6
6
|
import string
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
import numpy as np
|
|
10
9
|
import spglib
|
|
@@ -263,7 +262,7 @@ class Symmetry(dict):
|
|
|
263
262
|
) / len(self.rotations)
|
|
264
263
|
|
|
265
264
|
def _get_spglib_cell(
|
|
266
|
-
self, use_elements:
|
|
265
|
+
self, use_elements: bool | None = None, use_magmoms: bool | None = None
|
|
267
266
|
) -> tuple:
|
|
268
267
|
"""
|
|
269
268
|
Get the cell information in the format required by spglib.
|
|
@@ -380,8 +379,8 @@ class Symmetry(dict):
|
|
|
380
379
|
def get_primitive_cell(
|
|
381
380
|
self,
|
|
382
381
|
standardize: bool = False,
|
|
383
|
-
use_elements:
|
|
384
|
-
use_magmoms:
|
|
382
|
+
use_elements: bool | None = None,
|
|
383
|
+
use_magmoms: bool | None = None,
|
|
385
384
|
) -> Atoms:
|
|
386
385
|
"""
|
|
387
386
|
Get primitive cell of a given structure.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from structuretoolkit.build.aimsgb import get_grainboundary_info, grainboundary
|
|
2
2
|
from structuretoolkit.build.compound import B2, C14, C15, C36, D03
|
|
3
3
|
from structuretoolkit.build.mesh import create_mesh
|
|
4
|
-
from structuretoolkit.build.random import pyxtal
|
|
5
4
|
from structuretoolkit.build.sqs import sqs_structures
|
|
6
5
|
from structuretoolkit.build.surface import (
|
|
7
6
|
get_high_index_surface_info,
|
|
@@ -17,7 +16,6 @@ __all__ = [
|
|
|
17
16
|
"C36",
|
|
18
17
|
"D03",
|
|
19
18
|
"create_mesh",
|
|
20
|
-
"pyxtal",
|
|
21
19
|
"sqs_structures",
|
|
22
20
|
"get_high_index_surface_info",
|
|
23
21
|
"high_index_surface",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
|
|
2
2
|
# Distributed under the terms of "New BSD License", see the LICENSE file.
|
|
3
3
|
|
|
4
|
-
from typing import Optional
|
|
5
4
|
from warnings import warn
|
|
6
5
|
|
|
7
6
|
import numpy as np
|
|
@@ -59,7 +58,7 @@ def grainboundary(
|
|
|
59
58
|
delete_layer: str = "0b0t0b0t",
|
|
60
59
|
tol: float = 0.25,
|
|
61
60
|
to_primitive: bool = False,
|
|
62
|
-
add_if_dist:
|
|
61
|
+
add_if_dist: float | None = None,
|
|
63
62
|
):
|
|
64
63
|
"""
|
|
65
64
|
Generate a grain boundary structure based on aimsgb.
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
from ase.atoms import Atoms
|
|
5
3
|
from ase.build import bulk
|
|
@@ -8,7 +6,7 @@ from ase.spacegroup import crystal
|
|
|
8
6
|
from structuretoolkit.analyse.neighbors import get_neighbors
|
|
9
7
|
|
|
10
8
|
|
|
11
|
-
def B2(element_a: str, element_b: str, a:
|
|
9
|
+
def B2(element_a: str, element_b: str, a: float | None = None):
|
|
12
10
|
"""
|
|
13
11
|
Builds a cubic $AB$ B2 structure of interpenetrating simple cubic lattices.
|
|
14
12
|
|
|
@@ -33,7 +31,7 @@ def B2(element_a: str, element_b: str, a: Optional[float] = None):
|
|
|
33
31
|
def C14(
|
|
34
32
|
element_a: str,
|
|
35
33
|
element_b: str,
|
|
36
|
-
a:
|
|
34
|
+
a: float | None = None,
|
|
37
35
|
c_over_a: float = 1.626,
|
|
38
36
|
x1: float = 0.1697,
|
|
39
37
|
z1: float = 0.5629,
|
|
@@ -83,7 +81,7 @@ def C14(
|
|
|
83
81
|
return s
|
|
84
82
|
|
|
85
83
|
|
|
86
|
-
def C15(element_a: str, element_b: str, a:
|
|
84
|
+
def C15(element_a: str, element_b: str, a: float | None = None) -> Atoms:
|
|
87
85
|
"""
|
|
88
86
|
Builds a cubic $A B_2$ C15 Laves phase cell.
|
|
89
87
|
|
|
@@ -125,7 +123,7 @@ def C15(element_a: str, element_b: str, a: Optional[float] = None) -> Atoms:
|
|
|
125
123
|
def C36(
|
|
126
124
|
element_a: str,
|
|
127
125
|
element_b: str,
|
|
128
|
-
a:
|
|
126
|
+
a: float | None = None,
|
|
129
127
|
c_over_a: float = 3.252,
|
|
130
128
|
x1: float = 0.16429,
|
|
131
129
|
z1: float = 0.09400,
|
|
@@ -186,7 +184,7 @@ def C36(
|
|
|
186
184
|
return s
|
|
187
185
|
|
|
188
186
|
|
|
189
|
-
def D03(element_a: str, element_b: str, a:
|
|
187
|
+
def D03(element_a: str, element_b: str, a: float | None = None) -> Atoms:
|
|
190
188
|
"""
|
|
191
189
|
Builds a cubic $A B_3$ D03 cubic cell.
|
|
192
190
|
|
|
@@ -3,7 +3,6 @@ import random
|
|
|
3
3
|
import warnings
|
|
4
4
|
from collections.abc import Iterable
|
|
5
5
|
from multiprocessing import cpu_count
|
|
6
|
-
from typing import Optional, Union
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
from ase.atoms import Atoms
|
|
@@ -127,7 +126,7 @@ def remap_sro(species: Iterable[str], array: np.ndarray) -> dict[str, list]:
|
|
|
127
126
|
|
|
128
127
|
|
|
129
128
|
def remap_sqs_results(
|
|
130
|
-
result: dict[str,
|
|
129
|
+
result: dict[str, Atoms | np.ndarray],
|
|
131
130
|
) -> tuple[Atoms, dict[str, list]]:
|
|
132
131
|
"""
|
|
133
132
|
Remap the results of SQS optimization.
|
|
@@ -155,28 +154,28 @@ def transpose(it: Iterable[Iterable]) -> Iterable[tuple]:
|
|
|
155
154
|
Iterable[tuple]: The transposed iterable.
|
|
156
155
|
|
|
157
156
|
"""
|
|
158
|
-
return zip(*it)
|
|
157
|
+
return zip(*it, strict=True)
|
|
159
158
|
|
|
160
159
|
|
|
161
160
|
def sqs_structures(
|
|
162
161
|
structure: Atoms,
|
|
163
|
-
mole_fractions: dict[str,
|
|
164
|
-
weights:
|
|
165
|
-
objective:
|
|
166
|
-
iterations:
|
|
162
|
+
mole_fractions: dict[str, float | int],
|
|
163
|
+
weights: dict[int, float] | None = None,
|
|
164
|
+
objective: float | np.ndarray = 0.0,
|
|
165
|
+
iterations: float | int = 1e6,
|
|
167
166
|
output_structures: int = 10,
|
|
168
167
|
mode: str = "random",
|
|
169
|
-
num_threads:
|
|
170
|
-
prefactors:
|
|
171
|
-
pair_weights:
|
|
172
|
-
rtol:
|
|
173
|
-
atol:
|
|
174
|
-
which:
|
|
175
|
-
shell_distances:
|
|
176
|
-
minimal:
|
|
177
|
-
similar:
|
|
178
|
-
return_statistics:
|
|
179
|
-
) ->
|
|
168
|
+
num_threads: int | None = None,
|
|
169
|
+
prefactors: float | np.ndarray | None = None,
|
|
170
|
+
pair_weights: np.ndarray | None = None,
|
|
171
|
+
rtol: float | None = None,
|
|
172
|
+
atol: float | None = None,
|
|
173
|
+
which: Iterable[int] | None = None,
|
|
174
|
+
shell_distances: Iterable[int] | None = None,
|
|
175
|
+
minimal: bool | None = True,
|
|
176
|
+
similar: bool | None = True,
|
|
177
|
+
return_statistics: bool | None = False,
|
|
178
|
+
) -> Atoms | tuple[Atoms, dict[str, list], int, float]:
|
|
180
179
|
"""
|
|
181
180
|
Generate SQS structures.
|
|
182
181
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
from ase.atoms import Atoms
|
|
5
3
|
from ase.build import bulk, surface
|
|
@@ -12,10 +10,10 @@ def get_high_index_surface_info(
|
|
|
12
10
|
element: str,
|
|
13
11
|
crystal_structure: str,
|
|
14
12
|
lattice_constant: float,
|
|
15
|
-
terrace_orientation:
|
|
16
|
-
step_orientation:
|
|
17
|
-
kink_orientation:
|
|
18
|
-
step_down_vector:
|
|
13
|
+
terrace_orientation: list | None = None,
|
|
14
|
+
step_orientation: list | None = None,
|
|
15
|
+
kink_orientation: list | None = None,
|
|
16
|
+
step_down_vector: list | None = None,
|
|
19
17
|
length_step: int = 3,
|
|
20
18
|
length_terrace: int = 3,
|
|
21
19
|
length_kink: int = 1,
|
|
@@ -99,10 +97,10 @@ def high_index_surface(
|
|
|
99
97
|
element: str,
|
|
100
98
|
crystal_structure: str,
|
|
101
99
|
lattice_constant: float,
|
|
102
|
-
terrace_orientation:
|
|
103
|
-
step_orientation:
|
|
104
|
-
kink_orientation:
|
|
105
|
-
step_down_vector:
|
|
100
|
+
terrace_orientation: list | None = None,
|
|
101
|
+
step_orientation: list | None = None,
|
|
102
|
+
kink_orientation: list | None = None,
|
|
103
|
+
step_down_vector: list | None = None,
|
|
106
104
|
length_step: int = 3,
|
|
107
105
|
length_terrace: int = 3,
|
|
108
106
|
length_kink: int = 1,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional, Union
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
from ase.atoms import Atoms
|
|
5
3
|
from scipy.sparse import coo_matrix
|
|
@@ -24,7 +22,7 @@ def get_extended_positions(
|
|
|
24
22
|
width: float,
|
|
25
23
|
return_indices: bool = False,
|
|
26
24
|
norm_order: int = 2,
|
|
27
|
-
positions:
|
|
25
|
+
positions: np.ndarray | None = None,
|
|
28
26
|
):
|
|
29
27
|
"""
|
|
30
28
|
Get all atoms in the boundary around the supercell which have a distance
|
|
@@ -276,7 +274,7 @@ def apply_strain(
|
|
|
276
274
|
return structure_copy
|
|
277
275
|
|
|
278
276
|
|
|
279
|
-
def get_cell(cell:
|
|
277
|
+
def get_cell(cell: Atoms | list | tuple | np.ndarray | float):
|
|
280
278
|
"""
|
|
281
279
|
Get cell of an ase structure, or convert a float or a (3,)-array into a
|
|
282
280
|
orthogonal cell.
|
|
@@ -11,9 +11,9 @@ def phonopy_to_atoms(ph_atoms) -> Atoms:
|
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
13
|
return Atoms(
|
|
14
|
-
symbols=list(ph_atoms.
|
|
15
|
-
positions=list(ph_atoms.
|
|
16
|
-
cell=list(ph_atoms.
|
|
14
|
+
symbols=list(ph_atoms.symbols),
|
|
15
|
+
positions=list(ph_atoms.positions),
|
|
16
|
+
cell=list(ph_atoms.cell),
|
|
17
17
|
pbc=True,
|
|
18
18
|
)
|
|
19
19
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Distributed under the terms of "New BSD License", see the LICENSE file.
|
|
3
3
|
|
|
4
4
|
import warnings
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
from ase.atoms import Atoms
|
|
@@ -30,21 +30,21 @@ def plot3d(
|
|
|
30
30
|
camera: str = "orthographic",
|
|
31
31
|
spacefill: bool = True,
|
|
32
32
|
particle_size: float = 1.0,
|
|
33
|
-
select_atoms:
|
|
33
|
+
select_atoms: np.ndarray | None = None,
|
|
34
34
|
background: str = "white",
|
|
35
|
-
color_scheme:
|
|
36
|
-
colors:
|
|
37
|
-
scalar_field:
|
|
38
|
-
scalar_start:
|
|
39
|
-
scalar_end:
|
|
40
|
-
scalar_cmap:
|
|
41
|
-
vector_field:
|
|
42
|
-
vector_color:
|
|
35
|
+
color_scheme: str | None = None,
|
|
36
|
+
colors: np.ndarray | None = None,
|
|
37
|
+
scalar_field: np.ndarray | None = None,
|
|
38
|
+
scalar_start: float | None = None,
|
|
39
|
+
scalar_end: float | None = None,
|
|
40
|
+
scalar_cmap: Any | None = None,
|
|
41
|
+
vector_field: np.ndarray | None = None,
|
|
42
|
+
vector_color: np.ndarray | None = None,
|
|
43
43
|
magnetic_moments: bool = False,
|
|
44
44
|
view_plane: np.ndarray = np.array([0, 0, 1]),
|
|
45
45
|
distance_from_camera: float = 1.0,
|
|
46
46
|
opacity: float = 1.0,
|
|
47
|
-
height:
|
|
47
|
+
height: float | None = None,
|
|
48
48
|
):
|
|
49
49
|
"""
|
|
50
50
|
Plot3d relies on NGLView or plotly to visualize atomic structures. Here, we construct a string in the "protein database"
|
|
@@ -195,7 +195,7 @@ def _draw_box_plotly(fig: Any, structure: Atoms, px: Any, go: Any) -> Any:
|
|
|
195
195
|
cell = get_cell(structure)
|
|
196
196
|
data = fig.data
|
|
197
197
|
for lines in _get_box_skeleton(cell):
|
|
198
|
-
fig = px.line_3d(**dict(zip(["x", "y", "z"], lines.T)))
|
|
198
|
+
fig = px.line_3d(**dict(zip(["x", "y", "z"], lines.T, strict=True)))
|
|
199
199
|
fig.update_traces(line_color="#000000")
|
|
200
200
|
data = fig.data + data
|
|
201
201
|
return go.Figure(data=data)
|
|
@@ -204,14 +204,14 @@ def _draw_box_plotly(fig: Any, structure: Atoms, px: Any, go: Any) -> Any:
|
|
|
204
204
|
def _plot3d_plotly(
|
|
205
205
|
structure: Atoms,
|
|
206
206
|
show_cell: bool = True,
|
|
207
|
-
scalar_field:
|
|
208
|
-
select_atoms:
|
|
207
|
+
scalar_field: np.ndarray | None = None,
|
|
208
|
+
select_atoms: np.ndarray | None = None,
|
|
209
209
|
particle_size: float = 1.0,
|
|
210
210
|
camera: str = "orthographic",
|
|
211
211
|
view_plane: np.ndarray = np.array([1, 1, 1]),
|
|
212
212
|
distance_from_camera: float = 1.0,
|
|
213
213
|
opacity: float = 1.0,
|
|
214
|
-
height:
|
|
214
|
+
height: float | None = None,
|
|
215
215
|
):
|
|
216
216
|
"""
|
|
217
217
|
Make a 3D plot of the atomic structure.
|
|
@@ -284,16 +284,16 @@ def _plot3d(
|
|
|
284
284
|
camera: str = "orthographic",
|
|
285
285
|
spacefill: bool = True,
|
|
286
286
|
particle_size: float = 1.0,
|
|
287
|
-
select_atoms:
|
|
287
|
+
select_atoms: np.ndarray | None = None,
|
|
288
288
|
background: str = "white",
|
|
289
|
-
color_scheme:
|
|
290
|
-
colors:
|
|
291
|
-
scalar_field:
|
|
292
|
-
scalar_start:
|
|
293
|
-
scalar_end:
|
|
294
|
-
scalar_cmap:
|
|
295
|
-
vector_field:
|
|
296
|
-
vector_color:
|
|
289
|
+
color_scheme: str | None = None,
|
|
290
|
+
colors: np.ndarray | None = None,
|
|
291
|
+
scalar_field: np.ndarray | None = None,
|
|
292
|
+
scalar_start: float | None = None,
|
|
293
|
+
scalar_end: float | None = None,
|
|
294
|
+
scalar_cmap: Any | None = None,
|
|
295
|
+
vector_field: np.ndarray | None = None,
|
|
296
|
+
vector_color: np.ndarray | None = None,
|
|
297
297
|
magnetic_moments: bool = False,
|
|
298
298
|
view_plane: np.ndarray = np.array([0, 0, 1]),
|
|
299
299
|
distance_from_camera: float = 1.0,
|
|
@@ -462,7 +462,7 @@ def _plot3d(
|
|
|
462
462
|
vector_color = np.ones((len(structure), 3)) * vector_color
|
|
463
463
|
|
|
464
464
|
if vector_field is not None:
|
|
465
|
-
for arr, pos, col in zip(vector_field, positions, vector_color):
|
|
465
|
+
for arr, pos, col in zip(vector_field, positions, vector_color, strict=True):
|
|
466
466
|
view.shape.add_arrow(list(pos), list(pos + arr), list(col), 0.2)
|
|
467
467
|
|
|
468
468
|
if show_axes: # Add axes
|
|
@@ -576,8 +576,8 @@ def _ngl_write_atom(
|
|
|
576
576
|
x: float,
|
|
577
577
|
y: float,
|
|
578
578
|
z: float,
|
|
579
|
-
group:
|
|
580
|
-
num2:
|
|
579
|
+
group: str | None = None,
|
|
580
|
+
num2: int | None = None,
|
|
581
581
|
occupancy: float = 1.0,
|
|
582
582
|
temperature_factor: float = 0.0,
|
|
583
583
|
) -> str:
|
|
@@ -689,7 +689,7 @@ def _add_colorscheme_spacefill(
|
|
|
689
689
|
Returns:
|
|
690
690
|
(nglview.NGLWidget): The modified widget.
|
|
691
691
|
"""
|
|
692
|
-
for elem, num in set(zip(elements, atomic_numbers)):
|
|
692
|
+
for elem, num in set(zip(elements, atomic_numbers, strict=True)):
|
|
693
693
|
view.add_spacefill(
|
|
694
694
|
selection="#" + elem,
|
|
695
695
|
radius_type="vdw",
|
|
@@ -726,8 +726,8 @@ def _add_custom_color_spacefill(
|
|
|
726
726
|
|
|
727
727
|
def _scalars_to_hex_colors(
|
|
728
728
|
scalar_field: np.ndarray,
|
|
729
|
-
start:
|
|
730
|
-
end:
|
|
729
|
+
start: float | None = None,
|
|
730
|
+
end: float | None = None,
|
|
731
731
|
cmap=None,
|
|
732
732
|
):
|
|
733
733
|
"""
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
|
|
2
|
-
# Distributed under the terms of "New BSD License", see the LICENSE file.
|
|
3
|
-
|
|
4
|
-
import warnings
|
|
5
|
-
from typing import Union
|
|
6
|
-
|
|
7
|
-
try:
|
|
8
|
-
from tqdm.auto import tqdm
|
|
9
|
-
except ImportError:
|
|
10
|
-
|
|
11
|
-
def tqdm(x):
|
|
12
|
-
return x
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
from ase import Atoms
|
|
16
|
-
|
|
17
|
-
from structuretoolkit.common.helper import center_coordinates_in_unit_cell
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def pyxtal(
|
|
21
|
-
group: Union[int, list[int]],
|
|
22
|
-
species: tuple[str],
|
|
23
|
-
num_ions: tuple[int],
|
|
24
|
-
dim=3,
|
|
25
|
-
repeat=1,
|
|
26
|
-
allow_exceptions=True,
|
|
27
|
-
**kwargs,
|
|
28
|
-
) -> Union[Atoms, list[dict]]:
|
|
29
|
-
"""
|
|
30
|
-
Generate random crystal structures with PyXtal.
|
|
31
|
-
|
|
32
|
-
`group` must be between 1 and the largest possible value for the given dimensionality:
|
|
33
|
-
dim=3 => 1 - 230 (space groups)
|
|
34
|
-
dim=2 => 1 - 80 (layer groups)
|
|
35
|
-
dim=1 => 1 - 75 (rod groups)
|
|
36
|
-
dim=0 => 1 - 58 (point groups)
|
|
37
|
-
|
|
38
|
-
When `group` is passed as a list of integers or `repeat>1`, generate multiple structures and return them in a list
|
|
39
|
-
of dicts containing the keys `atoms`, `symmetry` and `repeat` for the ASE structure, the symmetry group
|
|
40
|
-
number and which iteration it is, respectively.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
group (list of int, or int): the symmetry group to generate or a list of them
|
|
44
|
-
species (tuple of str): which species to include, defines the stoichiometry together with `num_ions`
|
|
45
|
-
num_ions (tuple of int): how many of each species to include, defines the stoichiometry together with `species`
|
|
46
|
-
dim (int): dimensionality of the symmetry group, 0 is point groups, 1 is rod groups, 2 is layer groups and 3 is space groups
|
|
47
|
-
repeat (int): how many random structures to generate
|
|
48
|
-
allow_exceptions (bool): when generating multiple structures, silence errors when the requested stoichiometry and symmetry group are incompatible
|
|
49
|
-
**kwargs: passed to `pyxtal.pyxtal` function verbatim
|
|
50
|
-
|
|
51
|
-
Returns:
|
|
52
|
-
:class:`~.Atoms`: the generated structure, if repeat==1 and only one symmetry group is requested
|
|
53
|
-
list of dict of all generated structures, if repeat>1 or multiple symmetry groups are requested
|
|
54
|
-
|
|
55
|
-
Raises:
|
|
56
|
-
ValueError: if `species` and `num_ions` are not of the same length
|
|
57
|
-
ValueError: if stoichiometry and symmetry group are incompatible and allow_exceptions==False or only one structure is requested
|
|
58
|
-
"""
|
|
59
|
-
from pyxtal import pyxtal as _pyxtal
|
|
60
|
-
from pyxtal.msg import Comp_CompatibilityError
|
|
61
|
-
|
|
62
|
-
if len(species) != len(num_ions):
|
|
63
|
-
raise ValueError(
|
|
64
|
-
"species and num_ions must be of same length, "
|
|
65
|
-
f"not {species} and {num_ions}!"
|
|
66
|
-
)
|
|
67
|
-
stoich = "".join(f"{s}{n}" for s, n in zip(species, num_ions))
|
|
68
|
-
|
|
69
|
-
def generate(group):
|
|
70
|
-
s = _pyxtal()
|
|
71
|
-
try:
|
|
72
|
-
s.from_random(
|
|
73
|
-
dim=dim, group=group, species=species, numIons=num_ions, **kwargs
|
|
74
|
-
)
|
|
75
|
-
except Comp_CompatibilityError:
|
|
76
|
-
if not allow_exceptions:
|
|
77
|
-
raise ValueError(
|
|
78
|
-
f"Symmetry group {group} incompatible with stoichiometry {stoich}!"
|
|
79
|
-
) from None
|
|
80
|
-
else:
|
|
81
|
-
return None
|
|
82
|
-
s = s.to_ase()
|
|
83
|
-
s = center_coordinates_in_unit_cell(structure=s)
|
|
84
|
-
return s
|
|
85
|
-
|
|
86
|
-
# return a single structure
|
|
87
|
-
if repeat == 1 and isinstance(group, int):
|
|
88
|
-
allow_exceptions = False
|
|
89
|
-
return generate(group)
|
|
90
|
-
else:
|
|
91
|
-
structures = []
|
|
92
|
-
if isinstance(group, int):
|
|
93
|
-
group = [group]
|
|
94
|
-
failed_groups = []
|
|
95
|
-
for g in tqdm(group, desc="Spacegroups"):
|
|
96
|
-
for i in range(repeat):
|
|
97
|
-
s = generate(g)
|
|
98
|
-
if s is None:
|
|
99
|
-
failed_groups.append(g)
|
|
100
|
-
continue
|
|
101
|
-
structures.append({"atoms": s, "symmetry": g, "repeat": i})
|
|
102
|
-
if len(failed_groups) > 0:
|
|
103
|
-
warnings.warn(
|
|
104
|
-
f"Groups [{', '.join(map(str, failed_groups))}] could not be generated with stoichiometry {stoich}!",
|
|
105
|
-
stacklevel=2,
|
|
106
|
-
)
|
|
107
|
-
return structures
|
|
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
|