@mat3ra/made 2026.7.18-0 → 2026.7.29-0
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.
- package/data/reciprocal_paths.json +38 -38
- package/dist/js/data/reciprocal_paths.json +38 -38
- package/dist/js/lattice/reciprocal/symmetry_points.js +1 -1
- package/package.json +1 -1
- package/src/js/lattice/reciprocal/symmetry_points.ts +1 -1
- package/src/py/mat3ra/made/reciprocal/symmetry_points.py +1 -1
- package/src/py/mat3ra/made/tools/build/defective_structures/three_dimensional/solid_solution/builder.py +1 -1
- package/src/py/mat3ra/made/tools/calculate/__init__.py +29 -9
- package/src/py/mat3ra/made/tools/operations/core/unary.py +6 -3
- package/tests/js/lattice/lattice_reciprocal.ts +2 -2
- package/tests/py/unit/fixtures/bulk.py +1 -1
- package/tests/py/unit/test_reciprocal_lattice.py +4 -4
- package/tests/py/unit/test_reciprocal_paths.py +3 -3
- package/tests/py/unit/test_symmetry_points.py +7 -7
- package/tests/py/unit/test_tools_build_supercell.py +19 -1
- package/tests/py/unit/test_tools_calculate.py +7 -15
|
@@ -1,111 +1,111 @@
|
|
|
1
1
|
{
|
|
2
2
|
"CUB": [
|
|
3
|
-
["
|
|
3
|
+
["Γ", "X", "M", "Γ", "R", "X"],
|
|
4
4
|
["M", "R"]
|
|
5
5
|
],
|
|
6
6
|
"BCC": [
|
|
7
|
-
["
|
|
7
|
+
["Γ", "H", "N", "Γ", "P", "H"],
|
|
8
8
|
["P", "N"]
|
|
9
9
|
],
|
|
10
10
|
"FCC": [
|
|
11
|
-
["
|
|
11
|
+
["Γ", "X", "W", "K", "Γ", "L", "U", "W", "L"],
|
|
12
12
|
["U", "X"]
|
|
13
13
|
],
|
|
14
14
|
"TET": [
|
|
15
|
-
["
|
|
15
|
+
["Γ", "X", "M", "Γ", "Z", "R", "A", "Z"],
|
|
16
16
|
["X", "R"],
|
|
17
17
|
["M", "A"]
|
|
18
18
|
],
|
|
19
19
|
"BCT-1": [
|
|
20
|
-
["
|
|
20
|
+
["Γ", "X", "M", "Γ", "Z", "P", "N", "Z1", "M"],
|
|
21
21
|
["X", "P"]
|
|
22
22
|
],
|
|
23
23
|
"BCT-2": [
|
|
24
|
-
["
|
|
24
|
+
["Γ", "X", "Y", "∑", "Γ", "Z", "∑1", "N", "P", "Y1", "Z"],
|
|
25
25
|
["X", "P"]
|
|
26
26
|
],
|
|
27
27
|
"ORC": [
|
|
28
|
-
["
|
|
28
|
+
["Γ", "X", "S", "Y", "Γ", "Z", "U", "R", "T", "Z"],
|
|
29
29
|
["Y", "T"],
|
|
30
30
|
["U", "X"],
|
|
31
31
|
["S", "R"]
|
|
32
32
|
],
|
|
33
33
|
"ORCF-1": [
|
|
34
|
-
["
|
|
34
|
+
["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
|
|
35
35
|
["T", "X1"],
|
|
36
36
|
["X", "A", "Z"],
|
|
37
|
-
["L", "
|
|
37
|
+
["L", "Γ"]
|
|
38
38
|
],
|
|
39
39
|
"ORCF-2": [
|
|
40
|
-
["
|
|
40
|
+
["Γ", "Y", "C", "D", "X", "Γ", "Z", "D1", "H", "C"],
|
|
41
41
|
["C1", "Z"],
|
|
42
42
|
["X", "H1"],
|
|
43
43
|
["H", "Y"],
|
|
44
|
-
["L", "
|
|
44
|
+
["L", "Γ"]
|
|
45
45
|
],
|
|
46
46
|
"ORCF-3": [
|
|
47
|
-
["
|
|
47
|
+
["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
|
|
48
48
|
["X", "A", "Z"],
|
|
49
|
-
["L", "
|
|
49
|
+
["L", "Γ"]
|
|
50
50
|
],
|
|
51
51
|
"ORCI": [
|
|
52
|
-
["
|
|
52
|
+
["Γ", "X", "L", "T", "W", "R", "X1", "Z", "Γ", "Y", "S", "W"],
|
|
53
53
|
["L1", "Y"],
|
|
54
54
|
["Y1", "Z"]
|
|
55
55
|
],
|
|
56
56
|
"ORCC": [
|
|
57
|
-
["
|
|
57
|
+
["Γ", "X", "S", "R", "A", "Z", "Γ", "Y", "X1", "A1", "T", "Y"],
|
|
58
58
|
["Z", "T"]
|
|
59
59
|
],
|
|
60
60
|
"HEX": [
|
|
61
|
-
["
|
|
61
|
+
["Γ", "M", "K", "Γ", "A", "L", "H", "A"],
|
|
62
62
|
["L", "M"],
|
|
63
63
|
["K", "H"]
|
|
64
64
|
],
|
|
65
65
|
"RHL-1": [
|
|
66
|
-
["
|
|
67
|
-
["B", "Z", "
|
|
66
|
+
["Γ", "L", "B1"],
|
|
67
|
+
["B", "Z", "Γ", "X"],
|
|
68
68
|
["Q", "F", "P1", "Z"],
|
|
69
69
|
["L", "P"]
|
|
70
70
|
],
|
|
71
|
-
"RHL-2": [["
|
|
71
|
+
"RHL-2": [["Γ", "P", "Z", "Q", "Γ", "F", "P1", "Q1", "L", "Z"]],
|
|
72
72
|
"MCL": [
|
|
73
|
-
["
|
|
73
|
+
["Γ", "Y", "H", "C", "E", "M1", "A", "X", "H1"],
|
|
74
74
|
["M", "D", "Z"],
|
|
75
75
|
["Y", "D"]
|
|
76
76
|
],
|
|
77
77
|
"MCLC-1": [
|
|
78
|
-
["
|
|
78
|
+
["Γ", "Y", "Γ", "L", "I"],
|
|
79
79
|
["I1", "Z", "F1"],
|
|
80
80
|
["Y", "X1"],
|
|
81
|
-
["X", "
|
|
82
|
-
["M", "
|
|
81
|
+
["X", "Γ", "N"],
|
|
82
|
+
["M", "Γ"]
|
|
83
83
|
],
|
|
84
84
|
"MCLC-2": [
|
|
85
|
-
["
|
|
85
|
+
["Γ", "Y", "F", "L", "I"],
|
|
86
86
|
["I1", "Z", "F1"],
|
|
87
|
-
["N", "
|
|
87
|
+
["N", "Γ", "M"]
|
|
88
88
|
],
|
|
89
89
|
"MCLC-3": [
|
|
90
|
-
["
|
|
91
|
-
["H1", "Y1", "X", "
|
|
92
|
-
["M", "
|
|
90
|
+
["Γ", "Y", "F", "H", "Z", "I", "F1"],
|
|
91
|
+
["H1", "Y1", "X", "Γ", "N"],
|
|
92
|
+
["M", "Γ"]
|
|
93
93
|
],
|
|
94
94
|
"MCLC-4": [
|
|
95
|
-
["
|
|
96
|
-
["H1", "Y1", "X", "
|
|
97
|
-
["M", "
|
|
95
|
+
["Γ", "Y", "F", "H", "Z", "I"],
|
|
96
|
+
["H1", "Y1", "X", "Γ", "N"],
|
|
97
|
+
["M", "Γ"]
|
|
98
98
|
],
|
|
99
99
|
"MCLC-5": [
|
|
100
|
-
["
|
|
100
|
+
["Γ", "Y", "F", "L", "I"],
|
|
101
101
|
["I1", "Z", "H", "F1"],
|
|
102
|
-
["H1", "Y1", "X", "
|
|
103
|
-
["M", "
|
|
102
|
+
["H1", "Y1", "X", "Γ", "N"],
|
|
103
|
+
["M", "Γ"]
|
|
104
104
|
],
|
|
105
105
|
"TRI": [
|
|
106
|
-
["X", "
|
|
107
|
-
["L", "
|
|
108
|
-
["N", "
|
|
109
|
-
["R", "
|
|
106
|
+
["X", "Γ", "Y"],
|
|
107
|
+
["L", "Γ", "Z"],
|
|
108
|
+
["N", "Γ", "M"],
|
|
109
|
+
["R", "Γ"]
|
|
110
110
|
]
|
|
111
111
|
}
|
|
@@ -1,111 +1,111 @@
|
|
|
1
1
|
{
|
|
2
2
|
"CUB": [
|
|
3
|
-
["
|
|
3
|
+
["Γ", "X", "M", "Γ", "R", "X"],
|
|
4
4
|
["M", "R"]
|
|
5
5
|
],
|
|
6
6
|
"BCC": [
|
|
7
|
-
["
|
|
7
|
+
["Γ", "H", "N", "Γ", "P", "H"],
|
|
8
8
|
["P", "N"]
|
|
9
9
|
],
|
|
10
10
|
"FCC": [
|
|
11
|
-
["
|
|
11
|
+
["Γ", "X", "W", "K", "Γ", "L", "U", "W", "L"],
|
|
12
12
|
["U", "X"]
|
|
13
13
|
],
|
|
14
14
|
"TET": [
|
|
15
|
-
["
|
|
15
|
+
["Γ", "X", "M", "Γ", "Z", "R", "A", "Z"],
|
|
16
16
|
["X", "R"],
|
|
17
17
|
["M", "A"]
|
|
18
18
|
],
|
|
19
19
|
"BCT-1": [
|
|
20
|
-
["
|
|
20
|
+
["Γ", "X", "M", "Γ", "Z", "P", "N", "Z1", "M"],
|
|
21
21
|
["X", "P"]
|
|
22
22
|
],
|
|
23
23
|
"BCT-2": [
|
|
24
|
-
["
|
|
24
|
+
["Γ", "X", "Y", "∑", "Γ", "Z", "∑1", "N", "P", "Y1", "Z"],
|
|
25
25
|
["X", "P"]
|
|
26
26
|
],
|
|
27
27
|
"ORC": [
|
|
28
|
-
["
|
|
28
|
+
["Γ", "X", "S", "Y", "Γ", "Z", "U", "R", "T", "Z"],
|
|
29
29
|
["Y", "T"],
|
|
30
30
|
["U", "X"],
|
|
31
31
|
["S", "R"]
|
|
32
32
|
],
|
|
33
33
|
"ORCF-1": [
|
|
34
|
-
["
|
|
34
|
+
["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
|
|
35
35
|
["T", "X1"],
|
|
36
36
|
["X", "A", "Z"],
|
|
37
|
-
["L", "
|
|
37
|
+
["L", "Γ"]
|
|
38
38
|
],
|
|
39
39
|
"ORCF-2": [
|
|
40
|
-
["
|
|
40
|
+
["Γ", "Y", "C", "D", "X", "Γ", "Z", "D1", "H", "C"],
|
|
41
41
|
["C1", "Z"],
|
|
42
42
|
["X", "H1"],
|
|
43
43
|
["H", "Y"],
|
|
44
|
-
["L", "
|
|
44
|
+
["L", "Γ"]
|
|
45
45
|
],
|
|
46
46
|
"ORCF-3": [
|
|
47
|
-
["
|
|
47
|
+
["Γ", "Y", "T", "Z", "Γ", "X", "A1", "Y"],
|
|
48
48
|
["X", "A", "Z"],
|
|
49
|
-
["L", "
|
|
49
|
+
["L", "Γ"]
|
|
50
50
|
],
|
|
51
51
|
"ORCI": [
|
|
52
|
-
["
|
|
52
|
+
["Γ", "X", "L", "T", "W", "R", "X1", "Z", "Γ", "Y", "S", "W"],
|
|
53
53
|
["L1", "Y"],
|
|
54
54
|
["Y1", "Z"]
|
|
55
55
|
],
|
|
56
56
|
"ORCC": [
|
|
57
|
-
["
|
|
57
|
+
["Γ", "X", "S", "R", "A", "Z", "Γ", "Y", "X1", "A1", "T", "Y"],
|
|
58
58
|
["Z", "T"]
|
|
59
59
|
],
|
|
60
60
|
"HEX": [
|
|
61
|
-
["
|
|
61
|
+
["Γ", "M", "K", "Γ", "A", "L", "H", "A"],
|
|
62
62
|
["L", "M"],
|
|
63
63
|
["K", "H"]
|
|
64
64
|
],
|
|
65
65
|
"RHL-1": [
|
|
66
|
-
["
|
|
67
|
-
["B", "Z", "
|
|
66
|
+
["Γ", "L", "B1"],
|
|
67
|
+
["B", "Z", "Γ", "X"],
|
|
68
68
|
["Q", "F", "P1", "Z"],
|
|
69
69
|
["L", "P"]
|
|
70
70
|
],
|
|
71
|
-
"RHL-2": [["
|
|
71
|
+
"RHL-2": [["Γ", "P", "Z", "Q", "Γ", "F", "P1", "Q1", "L", "Z"]],
|
|
72
72
|
"MCL": [
|
|
73
|
-
["
|
|
73
|
+
["Γ", "Y", "H", "C", "E", "M1", "A", "X", "H1"],
|
|
74
74
|
["M", "D", "Z"],
|
|
75
75
|
["Y", "D"]
|
|
76
76
|
],
|
|
77
77
|
"MCLC-1": [
|
|
78
|
-
["
|
|
78
|
+
["Γ", "Y", "Γ", "L", "I"],
|
|
79
79
|
["I1", "Z", "F1"],
|
|
80
80
|
["Y", "X1"],
|
|
81
|
-
["X", "
|
|
82
|
-
["M", "
|
|
81
|
+
["X", "Γ", "N"],
|
|
82
|
+
["M", "Γ"]
|
|
83
83
|
],
|
|
84
84
|
"MCLC-2": [
|
|
85
|
-
["
|
|
85
|
+
["Γ", "Y", "F", "L", "I"],
|
|
86
86
|
["I1", "Z", "F1"],
|
|
87
|
-
["N", "
|
|
87
|
+
["N", "Γ", "M"]
|
|
88
88
|
],
|
|
89
89
|
"MCLC-3": [
|
|
90
|
-
["
|
|
91
|
-
["H1", "Y1", "X", "
|
|
92
|
-
["M", "
|
|
90
|
+
["Γ", "Y", "F", "H", "Z", "I", "F1"],
|
|
91
|
+
["H1", "Y1", "X", "Γ", "N"],
|
|
92
|
+
["M", "Γ"]
|
|
93
93
|
],
|
|
94
94
|
"MCLC-4": [
|
|
95
|
-
["
|
|
96
|
-
["H1", "Y1", "X", "
|
|
97
|
-
["M", "
|
|
95
|
+
["Γ", "Y", "F", "H", "Z", "I"],
|
|
96
|
+
["H1", "Y1", "X", "Γ", "N"],
|
|
97
|
+
["M", "Γ"]
|
|
98
98
|
],
|
|
99
99
|
"MCLC-5": [
|
|
100
|
-
["
|
|
100
|
+
["Γ", "Y", "F", "L", "I"],
|
|
101
101
|
["I1", "Z", "H", "F1"],
|
|
102
|
-
["H1", "Y1", "X", "
|
|
103
|
-
["M", "
|
|
102
|
+
["H1", "Y1", "X", "Γ", "N"],
|
|
103
|
+
["M", "Γ"]
|
|
104
104
|
],
|
|
105
105
|
"TRI": [
|
|
106
|
-
["X", "
|
|
107
|
-
["L", "
|
|
108
|
-
["N", "
|
|
109
|
-
["R", "
|
|
106
|
+
["X", "Γ", "Y"],
|
|
107
|
+
["L", "Γ", "Z"],
|
|
108
|
+
["N", "Γ", "M"],
|
|
109
|
+
["R", "Γ"]
|
|
110
110
|
]
|
|
111
111
|
}
|
package/package.json
CHANGED
|
@@ -367,7 +367,7 @@ def get_symmetry_points(lattice: Any) -> List[dict]:
|
|
|
367
367
|
"""
|
|
368
368
|
lattice_type = lattice.type.value if hasattr(lattice.type, "value") else str(lattice.type)
|
|
369
369
|
|
|
370
|
-
gamma_point = [{"point": "
|
|
370
|
+
gamma_point = [{"point": "Γ", "coordinates": [0.0, 0.0, 0.0]}]
|
|
371
371
|
|
|
372
372
|
points_fn = POINTS.get(lattice_type)
|
|
373
373
|
if points_fn is None:
|
|
@@ -31,7 +31,7 @@ class SolidSolutionBuilder(MergeBuilder):
|
|
|
31
31
|
source_element = configuration.source_element
|
|
32
32
|
target_element = configuration.target_element
|
|
33
33
|
material.name = (
|
|
34
|
-
f"{formula} - Solid Solution ({source_element}
|
|
34
|
+
f"{formula} - Solid Solution ({source_element}->{target_element} "
|
|
35
35
|
f"{concentration_percentage:.4g}%)"
|
|
36
36
|
)
|
|
37
37
|
return material
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Optional, Tuple
|
|
2
2
|
|
|
3
3
|
from ...material import Material
|
|
4
4
|
from ..analyze.other import get_surface_area
|
|
@@ -88,6 +88,31 @@ def calculate_adhesion_energy(
|
|
|
88
88
|
return (energy_substrate_slab + energy_film_slab - energy_interface) / area
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
def _get_interface_with_build_metadata(interface: Material) -> MaterialWithBuildMetadata:
|
|
92
|
+
if isinstance(interface, MaterialWithBuildMetadata):
|
|
93
|
+
return interface
|
|
94
|
+
return MaterialWithBuildMetadata.create(interface.to_dict())
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _resolve_interface_bulk_materials(
|
|
98
|
+
interface: Material,
|
|
99
|
+
substrate_bulk: Optional[Material],
|
|
100
|
+
film_bulk: Optional[Material],
|
|
101
|
+
) -> Tuple[Optional[Material], Optional[Material]]:
|
|
102
|
+
"""Resolve missing bulks from interface build metadata (handles BoundaryConditions metadata)."""
|
|
103
|
+
try:
|
|
104
|
+
interface_with_metadata = _get_interface_with_build_metadata(interface)
|
|
105
|
+
if substrate_bulk is None:
|
|
106
|
+
substrate_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="substrate"))
|
|
107
|
+
if film_bulk is None:
|
|
108
|
+
film_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="film"))
|
|
109
|
+
except (ValueError, TypeError) as exc:
|
|
110
|
+
raise ValueError(
|
|
111
|
+
"The substrate and film bulk materials must be provided or defined in the interface metadata."
|
|
112
|
+
) from exc
|
|
113
|
+
return substrate_bulk, film_bulk
|
|
114
|
+
|
|
115
|
+
|
|
91
116
|
def calculate_interfacial_energy(
|
|
92
117
|
interface: Material,
|
|
93
118
|
substrate_slab: Optional[Material] = None,
|
|
@@ -115,14 +140,9 @@ def calculate_interfacial_energy(
|
|
|
115
140
|
substrate_slab = get_slab(interface, part="substrate") if substrate_slab is None else substrate_slab
|
|
116
141
|
film_slab = get_slab(interface, part="film") if film_slab is None else film_slab
|
|
117
142
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
film_bulk = Material.create(get_interface_bulk_crystal(interface_with_metadata, part="film"))
|
|
122
|
-
except ValueError as exc:
|
|
123
|
-
raise ValueError(
|
|
124
|
-
"The substrate and film bulk materials must be provided or defined in the interface metadata."
|
|
125
|
-
) from exc
|
|
143
|
+
if substrate_bulk is None or film_bulk is None:
|
|
144
|
+
substrate_bulk, film_bulk = _resolve_interface_bulk_materials(interface, substrate_bulk, film_bulk)
|
|
145
|
+
|
|
126
146
|
surface_energy_substrate = calculate_surface_energy(substrate_slab, substrate_bulk, calculator)
|
|
127
147
|
surface_energy_film = calculate_surface_energy(film_slab, film_bulk, calculator)
|
|
128
148
|
adhesion_energy = calculate_adhesion_energy(interface, substrate_slab, film_slab, calculator)
|
|
@@ -22,9 +22,12 @@ def supercell(material: MaterialWithBuildMetadata, supercell_matrix) -> Material
|
|
|
22
22
|
atoms = to_ase(material)
|
|
23
23
|
|
|
24
24
|
supercell_atoms = ase_make_supercell(atoms, supercell_matrix)
|
|
25
|
-
|
|
26
|
-
#
|
|
27
|
-
|
|
25
|
+
material_config = from_ase(supercell_atoms)
|
|
26
|
+
# ASE make_supercell drops atoms.info; merge prior build/boundaryConditions when present.
|
|
27
|
+
source_metadata = material.to_dict().get("metadata") or {}
|
|
28
|
+
if source_metadata:
|
|
29
|
+
material_config["metadata"] = {**material_config.get("metadata", {}), **source_metadata}
|
|
30
|
+
new_material = MaterialWithBuildMetadata.create(material_config)
|
|
28
31
|
new_material.name = material.name
|
|
29
32
|
return new_material
|
|
30
33
|
|
|
@@ -14,7 +14,7 @@ describe("Lattice Reciprocal", () => {
|
|
|
14
14
|
const lattice = new ReciprocalLattice(Na4Cl4.lattice as LatticeSchema);
|
|
15
15
|
const expectedPath = [
|
|
16
16
|
{
|
|
17
|
-
point: "
|
|
17
|
+
point: "Γ",
|
|
18
18
|
steps: 0,
|
|
19
19
|
coordinates: [0, 0, 0],
|
|
20
20
|
},
|
|
@@ -54,7 +54,7 @@ describe("Lattice Reciprocal", () => {
|
|
|
54
54
|
const actualPoints = lattice.symmetryPoints;
|
|
55
55
|
const expectedPoints = [
|
|
56
56
|
{
|
|
57
|
-
point: "
|
|
57
|
+
point: "Γ",
|
|
58
58
|
coordinates: [0, 0, 0],
|
|
59
59
|
},
|
|
60
60
|
{
|
|
@@ -5,7 +5,7 @@ from mat3ra.standata.materials import Materials
|
|
|
5
5
|
BULK_SrTiO3 = Materials.get_by_name_first_match("SrTiO3")
|
|
6
6
|
BULK_GRAPHITE = Materials.get_by_name_first_match("Graphite")
|
|
7
7
|
BULK_SiO2 = Materials.get_by_name_first_match("SiO2")
|
|
8
|
-
BULK_Hf2O_MCL = Materials.get_by_name_first_match("Hafnium
|
|
8
|
+
BULK_Hf2O_MCL = Materials.get_by_name_first_match("Hafnium IV Oxide, MCL")
|
|
9
9
|
BULK_TiN = Materials.get_by_name_first_match("TiN")
|
|
10
10
|
BULK_Ni_PRIMITIVE = Materials.get_by_name_first_match("Nickel")
|
|
11
11
|
BULK_GRAPHENE = Materials.get_by_name_first_match("Graphene")
|
|
@@ -5,18 +5,18 @@ from mat3ra.utils import assertion as assertion_utils
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def test_reciprocal_lattice_symmetry_points_cub():
|
|
8
|
-
"""CUB lattice should have
|
|
8
|
+
"""CUB lattice should have Γ, R, X, M symmetry points."""
|
|
9
9
|
lattice = ReciprocalLattice(a=5.64, b=5.64, c=5.64, type="CUB")
|
|
10
10
|
points = lattice.symmetry_points
|
|
11
11
|
labels = [p["point"] for p in points]
|
|
12
|
-
assert labels == ["
|
|
12
|
+
assert labels == ["Γ", "R", "X", "M"]
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def test_reciprocal_lattice_default_kpoint_path_cub():
|
|
16
16
|
lattice = ReciprocalLattice(a=5.64, b=5.64, c=5.64, type="CUB")
|
|
17
17
|
path = lattice.default_kpoint_path
|
|
18
18
|
labels = [p["point"] for p in path]
|
|
19
|
-
assert labels == ["
|
|
19
|
+
assert labels == ["Γ", "X", "M", "Γ", "R", "X", "M", "R"]
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def test_reciprocal_lattice_default_kpoint_path_bct():
|
|
@@ -32,7 +32,7 @@ def test_reciprocal_lattice_extract_kpoint_path():
|
|
|
32
32
|
data_points = [[0, 0, 0], [0.5, 0.5, 0.5]]
|
|
33
33
|
result = lattice.extract_kpoint_path(data_points)
|
|
34
34
|
assert len(result) == 2
|
|
35
|
-
assert result[0]["point"] == "
|
|
35
|
+
assert result[0]["point"] == "Γ"
|
|
36
36
|
assert result[0]["steps"] == 0
|
|
37
37
|
assert result[1]["point"] == "R"
|
|
38
38
|
assert result[1]["steps"] == 1
|
|
@@ -49,16 +49,16 @@ def test_reciprocal_paths_entry_structure():
|
|
|
49
49
|
def test_reciprocal_paths_cub():
|
|
50
50
|
path = RECIPROCAL_PATHS["CUB"]
|
|
51
51
|
labels = [p["point"] for p in path]
|
|
52
|
-
assert labels == ["
|
|
52
|
+
assert labels == ["Γ", "X", "M", "Γ", "R", "X", "M", "R"]
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def test_reciprocal_paths_fcc():
|
|
56
56
|
path = RECIPROCAL_PATHS["FCC"]
|
|
57
57
|
labels = [p["point"] for p in path]
|
|
58
|
-
assert labels == ["
|
|
58
|
+
assert labels == ["Γ", "X", "W", "K", "Γ", "L", "U", "W", "L", "U", "X"]
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
def test_reciprocal_paths_hex():
|
|
62
62
|
path = RECIPROCAL_PATHS["HEX"]
|
|
63
63
|
labels = [p["point"] for p in path]
|
|
64
|
-
assert labels == ["
|
|
64
|
+
assert labels == ["Γ", "M", "K", "Γ", "A", "L", "H", "A", "L", "M", "K", "H"]
|
|
@@ -10,7 +10,7 @@ def test_symmetry_points_gamma_always_first():
|
|
|
10
10
|
"""Gamma point should always be the first symmetry point."""
|
|
11
11
|
lattice = Lattice(a=1.0, b=1.0, c=1.0, type="CUB")
|
|
12
12
|
points = get_symmetry_points(lattice)
|
|
13
|
-
assert points[0]["point"] == "
|
|
13
|
+
assert points[0]["point"] == "Γ"
|
|
14
14
|
assert points[0]["coordinates"] == [0.0, 0.0, 0.0]
|
|
15
15
|
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ def test_symmetry_points_cub():
|
|
|
18
18
|
lattice = Lattice(a=5.64, b=5.64, c=5.64, type="CUB")
|
|
19
19
|
points = get_symmetry_points(lattice)
|
|
20
20
|
labels = [p["point"] for p in points]
|
|
21
|
-
assert labels == ["
|
|
21
|
+
assert labels == ["Γ", "R", "X", "M"]
|
|
22
22
|
# Verify specific coordinates
|
|
23
23
|
r_point = next(p for p in points if p["point"] == "R")
|
|
24
24
|
assertion_utils.assert_deep_almost_equal(r_point["coordinates"], [0.5, 0.5, 0.5])
|
|
@@ -45,7 +45,7 @@ def test_symmetry_points_bcc():
|
|
|
45
45
|
lattice = Lattice(a=3.0, b=3.0, c=3.0, type="BCC")
|
|
46
46
|
points = get_symmetry_points(lattice)
|
|
47
47
|
labels = [p["point"] for p in points]
|
|
48
|
-
assert labels == ["
|
|
48
|
+
assert labels == ["Γ", "H", "P", "N"]
|
|
49
49
|
h_point = next(p for p in points if p["point"] == "H")
|
|
50
50
|
assertion_utils.assert_deep_almost_equal(h_point["coordinates"], [0.5, -0.5, 0.5])
|
|
51
51
|
|
|
@@ -54,7 +54,7 @@ def test_symmetry_points_hex():
|
|
|
54
54
|
lattice = Lattice(a=2.46, b=2.46, c=6.71, type="HEX")
|
|
55
55
|
points = get_symmetry_points(lattice)
|
|
56
56
|
labels = [p["point"] for p in points]
|
|
57
|
-
assert set(labels) == {"
|
|
57
|
+
assert set(labels) == {"Γ", "A", "H", "K", "L", "M"}
|
|
58
58
|
k_point = next(p for p in points if p["point"] == "K")
|
|
59
59
|
assertion_utils.assert_deep_almost_equal(k_point["coordinates"], [1 / 3, 1 / 3, 0.0])
|
|
60
60
|
|
|
@@ -86,14 +86,14 @@ def test_symmetry_points_tet():
|
|
|
86
86
|
lattice = Lattice(a=3.0, b=3.0, c=5.0, type="TET")
|
|
87
87
|
points = get_symmetry_points(lattice)
|
|
88
88
|
labels = [p["point"] for p in points]
|
|
89
|
-
assert set(labels) == {"
|
|
89
|
+
assert set(labels) == {"Γ", "A", "M", "R", "X", "Z"}
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
def test_symmetry_points_orc():
|
|
93
93
|
lattice = Lattice(a=2.0, b=3.0, c=4.0, type="ORC")
|
|
94
94
|
points = get_symmetry_points(lattice)
|
|
95
95
|
labels = [p["point"] for p in points]
|
|
96
|
-
assert set(labels) == {"
|
|
96
|
+
assert set(labels) == {"Γ", "R", "S", "T", "U", "X", "Y", "Z"}
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def test_symmetry_points_rhl1():
|
|
@@ -144,7 +144,7 @@ def test_symmetry_points_all_lattice_types(lattice_type):
|
|
|
144
144
|
lattice = Lattice(a=3.0, b=4.0, c=5.0, alpha=80.0, beta=85.0, gamma=75.0, type=lattice_type)
|
|
145
145
|
points = get_symmetry_points(lattice)
|
|
146
146
|
assert len(points) >= 1
|
|
147
|
-
assert points[0]["point"] == "
|
|
147
|
+
assert points[0]["point"] == "Γ"
|
|
148
148
|
# All coordinates should be lists of 3 floats
|
|
149
149
|
for p in points:
|
|
150
150
|
assert len(p["coordinates"]) == 3
|
|
@@ -2,18 +2,22 @@ import numpy as np
|
|
|
2
2
|
import pytest
|
|
3
3
|
from mat3ra.made.material import Material
|
|
4
4
|
from mat3ra.made.tools.build_components.entities.reusable.three_dimensional.supercell.helpers import create_supercell
|
|
5
|
+
from mat3ra.made.tools.build_components.metadata import MaterialWithBuildMetadata
|
|
6
|
+
from unit.fixtures.interface.zsl import GRAPHENE_NICKEL_INTERFACE
|
|
5
7
|
from unit.fixtures.supercell import SI_SUPERCELL_2X2X1
|
|
6
8
|
|
|
7
9
|
from .fixtures.bulk import BULK_Si_PRIMITIVE
|
|
8
10
|
from .utils import assert_two_entities_deep_almost_equal
|
|
9
11
|
|
|
12
|
+
SUPERCELL_MATRIX_2X2X1 = [[2, 0, 0], [0, 2, 0], [0, 0, 1]]
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
@pytest.mark.parametrize(
|
|
12
16
|
"material_config, supercell_matrix, expected_material_config",
|
|
13
17
|
[
|
|
14
18
|
(
|
|
15
19
|
BULK_Si_PRIMITIVE,
|
|
16
|
-
|
|
20
|
+
SUPERCELL_MATRIX_2X2X1,
|
|
17
21
|
SI_SUPERCELL_2X2X1,
|
|
18
22
|
),
|
|
19
23
|
],
|
|
@@ -27,3 +31,17 @@ def test_create_supercell(material_config, supercell_matrix, expected_material_c
|
|
|
27
31
|
expected_vectors = np.array(supercell_matrix) @ np.array(material.lattice.vector_arrays)
|
|
28
32
|
actual_vectors = np.array(supercell_material.lattice.vector_arrays)
|
|
29
33
|
assert np.allclose(actual_vectors, expected_vectors, atol=1e-6), "Supercell vectors do not match expected values."
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_create_supercell_preserves_prior_build_metadata():
|
|
37
|
+
material = MaterialWithBuildMetadata.create(GRAPHENE_NICKEL_INTERFACE)
|
|
38
|
+
prior_build_types = [step.configuration.get("type") for step in material.metadata.build]
|
|
39
|
+
|
|
40
|
+
supercell_material = create_supercell(material, SUPERCELL_MATRIX_2X2X1)
|
|
41
|
+
|
|
42
|
+
result_build_types = [step.configuration.get("type") for step in supercell_material.metadata.build]
|
|
43
|
+
assert result_build_types[:-1] == prior_build_types
|
|
44
|
+
assert result_build_types[-1] == "SupercellConfiguration"
|
|
45
|
+
assert supercell_material.metadata.to_dict().get("boundaryConditions") == material.metadata.to_dict().get(
|
|
46
|
+
"boundaryConditions"
|
|
47
|
+
)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
import pytest
|
|
3
2
|
from ase.build import add_adsorbate, bulk, fcc111, graphene, surface
|
|
4
3
|
from ase.calculators import emt
|
|
5
4
|
from mat3ra.made.material import Material
|
|
@@ -20,16 +19,15 @@ graphene_layer.cell = nickel_slab.cell
|
|
|
20
19
|
interface = nickel_slab.copy()
|
|
21
20
|
add_adsorbate(interface, graphene_layer, height=2, position="ontop")
|
|
22
21
|
|
|
23
|
-
# Material
|
|
22
|
+
# Material.create yields MaterialMetadataBoundaryConditions; bulks are resolved from nested build.
|
|
24
23
|
interface_material = Material.create(GRAPHENE_NICKEL_INTERFACE)
|
|
25
24
|
nickel_slab_material = Material.create(from_ase(nickel_slab))
|
|
26
|
-
nickel_bulk_material = Material.create(from_ase(bulk("Ni", "fcc", a=3.52)))
|
|
27
|
-
graphene_layer_material = Material.create(from_ase(graphene_layer))
|
|
28
|
-
graphene_bulk_material = graphene_layer
|
|
29
25
|
|
|
30
26
|
# Calculator setup
|
|
31
27
|
calculator = emt.EMT()
|
|
32
28
|
|
|
29
|
+
EXPECTED_INTERFACIAL_ENERGY = -0.78488
|
|
30
|
+
|
|
33
31
|
|
|
34
32
|
def test_calculate_total_energy():
|
|
35
33
|
atoms = bulk("C", cubic=True)
|
|
@@ -59,17 +57,11 @@ def test_calculate_adhesion_energy():
|
|
|
59
57
|
assert np.isclose(adhesion_energy, 0.07345)
|
|
60
58
|
|
|
61
59
|
|
|
62
|
-
@pytest.mark.skip(reason="This test is not working as expected")
|
|
63
60
|
def test_calculate_interfacial_energy():
|
|
64
61
|
interfacial_energy = calculate_interfacial_energy(
|
|
65
62
|
interface_material,
|
|
66
|
-
nickel_slab_material,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
graphene_bulk_material,
|
|
70
|
-
calculator,
|
|
71
|
-
)
|
|
72
|
-
assert np.isclose(
|
|
73
|
-
interfacial_energy,
|
|
74
|
-
-0.78488,
|
|
63
|
+
substrate_slab=nickel_slab_material,
|
|
64
|
+
film_slab=graphene_layer,
|
|
65
|
+
calculator=calculator,
|
|
75
66
|
)
|
|
67
|
+
assert np.isclose(interfacial_energy, EXPECTED_INTERFACIAL_ENERGY)
|