@mat3ra/made 2025.8.7-1 → 2025.8.8-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/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/py/mat3ra/made/tools/build/compound_pristine_structures/two_dimensional/interface/base/helpers.py +2 -2
- package/src/py/mat3ra/made/tools/build/compound_pristine_structures/two_dimensional/interface/zsl/helpers.py +2 -2
- package/src/py/mat3ra/made/tools/build/pristine_structures/two_dimensional/slab/configuration.py +13 -4
- package/src/py/mat3ra/made/tools/build/pristine_structures/two_dimensional/slab/helpers.py +10 -5
- package/src/py/mat3ra/made/tools/build_components/entities/reusable/two_dimensional/atomic_layers_unique_repeated/builder.py +28 -9
- package/src/py/mat3ra/made/tools/build_components/entities/reusable/two_dimensional/atomic_layers_unique_repeated/configuration.py +2 -1
- package/src/py/mat3ra/made/tools/build_components/entities/reusable/two_dimensional/slab_stack/helpers.py +4 -1
- package/tests/py/unit/fixtures/slab.py +44 -0
- package/tests/py/unit/test_tools_analyze_interface.py +18 -3
- package/tests/py/unit/test_tools_analyze_interface_zsl.py +12 -2
- package/tests/py/unit/test_tools_build_defect/test_adatom.py +2 -0
- package/tests/py/unit/test_tools_build_defect/test_island.py +2 -0
- package/tests/py/unit/test_tools_build_defect/test_terrace.py +2 -0
- package/tests/py/unit/test_tools_build_interface.py +8 -4
- package/tests/py/unit/test_tools_build_interface_zsl.py +2 -2
- package/tests/py/unit/test_tools_build_slab.py +45 -14
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -19,7 +19,7 @@ dependencies = [
|
|
|
19
19
|
# new verison of numpy==2.0.0 is not handled by pymatgen yet
|
|
20
20
|
"numpy<=1.26.4",
|
|
21
21
|
"mat3ra-utils",
|
|
22
|
-
"mat3ra-esse
|
|
22
|
+
"mat3ra-esse",
|
|
23
23
|
"mat3ra-code"
|
|
24
24
|
|
|
25
25
|
]
|
|
@@ -110,7 +110,7 @@ def create_interface_simple(
|
|
|
110
110
|
miller_indices=substrate_miller_indices,
|
|
111
111
|
number_of_layers=substrate_number_of_layers,
|
|
112
112
|
vacuum=0,
|
|
113
|
-
|
|
113
|
+
termination_top_formula=substrate_termination_formula,
|
|
114
114
|
xy_supercell_matrix=substrate_xy_supercell_matrix,
|
|
115
115
|
use_conventional_cell=use_conventional_cell,
|
|
116
116
|
)
|
|
@@ -119,7 +119,7 @@ def create_interface_simple(
|
|
|
119
119
|
miller_indices=film_miller_indices,
|
|
120
120
|
number_of_layers=film_number_of_layers,
|
|
121
121
|
vacuum=0,
|
|
122
|
-
|
|
122
|
+
termination_top_formula=film_termination_formula,
|
|
123
123
|
xy_supercell_matrix=film_xy_supercell_matrix,
|
|
124
124
|
use_conventional_cell=use_conventional_cell,
|
|
125
125
|
)
|
|
@@ -46,7 +46,7 @@ def create_interface_zsl(
|
|
|
46
46
|
miller_indices=substrate_miller_indices,
|
|
47
47
|
number_of_layers=substrate_number_of_layers,
|
|
48
48
|
vacuum=0,
|
|
49
|
-
|
|
49
|
+
termination_bottom_formula=substrate_termination_formula,
|
|
50
50
|
use_conventional_cell=use_conventional_cell,
|
|
51
51
|
)
|
|
52
52
|
film_slab = create_slab(
|
|
@@ -54,7 +54,7 @@ def create_interface_zsl(
|
|
|
54
54
|
miller_indices=film_miller_indices,
|
|
55
55
|
number_of_layers=film_number_of_layers,
|
|
56
56
|
vacuum=0,
|
|
57
|
-
|
|
57
|
+
termination_top_formula=film_termination_formula,
|
|
58
58
|
use_conventional_cell=use_conventional_cell,
|
|
59
59
|
)
|
|
60
60
|
|
package/src/py/mat3ra/made/tools/build/pristine_structures/two_dimensional/slab/configuration.py
CHANGED
|
@@ -12,6 +12,7 @@ from .....build_components.metadata import MaterialWithBuildMetadata
|
|
|
12
12
|
from .....build_components import select_slab_termination
|
|
13
13
|
from .....build_components.operations.core.combinations.stack.configuration import StackConfiguration
|
|
14
14
|
from .....build_components.entities.core.two_dimensional.vacuum.configuration import VacuumConfiguration
|
|
15
|
+
from .....build_components.entities.auxiliary.two_dimensional.termination import Termination
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class SlabConfiguration(StackConfiguration, SlabConfigurationSchema):
|
|
@@ -19,6 +20,9 @@ class SlabConfiguration(StackConfiguration, SlabConfigurationSchema):
|
|
|
19
20
|
stack_components: List[Union[AtomicLayersUniqueRepeatedConfiguration, VacuumConfiguration]] # No Materials!
|
|
20
21
|
direction: AxisEnum = AxisEnum.z
|
|
21
22
|
|
|
23
|
+
termination_top: Optional[Termination] = None
|
|
24
|
+
termination_bottom: Optional[Termination] = None
|
|
25
|
+
|
|
22
26
|
@property
|
|
23
27
|
def number_of_layers(self):
|
|
24
28
|
return self.atomic_layers.number_of_repetitions
|
|
@@ -46,7 +50,8 @@ class SlabConfiguration(StackConfiguration, SlabConfigurationSchema):
|
|
|
46
50
|
material_or_dict: Union[Material, dict],
|
|
47
51
|
miller_indices: Tuple[int, int, int],
|
|
48
52
|
number_of_layers: int,
|
|
49
|
-
|
|
53
|
+
termination_top_formula: Optional[str] = None,
|
|
54
|
+
termination_bottom_formula: Optional[str] = None,
|
|
50
55
|
vacuum: float = 10.0,
|
|
51
56
|
use_conventional_cell: bool = True,
|
|
52
57
|
) -> "SlabConfiguration":
|
|
@@ -56,7 +61,9 @@ class SlabConfiguration(StackConfiguration, SlabConfigurationSchema):
|
|
|
56
61
|
material_or_dict (Union[Material, dict]): Material or dictionary representation of the material.
|
|
57
62
|
miller_indices (Tuple[int, int, int]): Miller indices for the slab surface.
|
|
58
63
|
number_of_layers (int): Number of atomic layers in the slab, in the number of unit cells.
|
|
59
|
-
|
|
64
|
+
termination_top_formula (Optional[str]): Formula of the top termination to use for the slab (i.e. "SrTiO").
|
|
65
|
+
termination_bottom_formula (Optional[str]): Formula of the bottom termination to use for the slab.
|
|
66
|
+
|
|
60
67
|
vacuum (float): Size of the vacuum layer in Angstroms.
|
|
61
68
|
|
|
62
69
|
Returns:
|
|
@@ -71,14 +78,16 @@ class SlabConfiguration(StackConfiguration, SlabConfigurationSchema):
|
|
|
71
78
|
material=material, miller_indices=miller_indices
|
|
72
79
|
)
|
|
73
80
|
terminations = crystal_lattice_planes_analyzer.terminations
|
|
74
|
-
|
|
81
|
+
termination_top = select_slab_termination(terminations, termination_top_formula)
|
|
82
|
+
termination_bottom = select_slab_termination(terminations, termination_bottom_formula)
|
|
75
83
|
|
|
76
84
|
if use_conventional_cell:
|
|
77
85
|
material = crystal_lattice_planes_analyzer.material_with_conventional_lattice
|
|
78
86
|
atomic_layers_repeated_configuration = AtomicLayersUniqueRepeatedConfiguration(
|
|
79
87
|
crystal=material,
|
|
80
88
|
miller_indices=miller_indices,
|
|
81
|
-
termination_top=
|
|
89
|
+
termination_top=termination_top,
|
|
90
|
+
termination_bottom=termination_bottom,
|
|
82
91
|
number_of_repetitions=number_of_layers,
|
|
83
92
|
)
|
|
84
93
|
|
|
@@ -15,8 +15,10 @@ def create_slab(
|
|
|
15
15
|
miller_indices: Tuple[int, int, int] = (0, 0, 1),
|
|
16
16
|
use_conventional_cell=True,
|
|
17
17
|
use_orthogonal_c: bool = True,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
termination_top: Optional[Termination] = None,
|
|
19
|
+
termination_bottom: Optional[Termination] = None,
|
|
20
|
+
termination_top_formula: Optional[str] = None,
|
|
21
|
+
termination_bottom_formula: Optional[str] = None,
|
|
20
22
|
number_of_layers=1,
|
|
21
23
|
vacuum=10.0,
|
|
22
24
|
xy_supercell_matrix=DEFAULT_XY_SUPERCELL_MATRIX,
|
|
@@ -46,8 +48,10 @@ def create_slab(
|
|
|
46
48
|
)
|
|
47
49
|
material_to_use = crystal_lattice_planes_analyzer.material_with_conventional_lattice
|
|
48
50
|
|
|
49
|
-
if
|
|
50
|
-
|
|
51
|
+
if termination_top is not None:
|
|
52
|
+
termination_top_formula = termination_top.formula
|
|
53
|
+
if termination_bottom is not None:
|
|
54
|
+
termination_bottom_formula = termination_bottom.formula
|
|
51
55
|
|
|
52
56
|
slab_builder_parameters = SlabBuilderParameters(
|
|
53
57
|
xy_supercell_matrix=xy_supercell_matrix,
|
|
@@ -57,7 +61,8 @@ def create_slab(
|
|
|
57
61
|
material_or_dict=material_to_use,
|
|
58
62
|
miller_indices=miller_indices,
|
|
59
63
|
number_of_layers=number_of_layers,
|
|
60
|
-
|
|
64
|
+
termination_top_formula=termination_top_formula,
|
|
65
|
+
termination_bottom_formula=termination_bottom_formula,
|
|
61
66
|
vacuum=vacuum,
|
|
62
67
|
use_conventional_cell=use_conventional_cell,
|
|
63
68
|
)
|
|
@@ -2,7 +2,7 @@ from typing import Type
|
|
|
2
2
|
|
|
3
3
|
from ......analyze import BaseMaterialAnalyzer
|
|
4
4
|
from ......modify import wrap_to_unit_cell
|
|
5
|
-
from ......operations.core.unary import supercell, translate
|
|
5
|
+
from ......operations.core.unary import rotate, supercell, translate
|
|
6
6
|
from ..... import MaterialWithBuildMetadata
|
|
7
7
|
from ....auxiliary.two_dimensional.miller_indices import MillerIndices
|
|
8
8
|
from ..crystal_lattice_planes.builder import CrystalLatticePlanesBuilder
|
|
@@ -16,15 +16,28 @@ class AtomicLayersUniqueRepeatedBuilder(CrystalLatticePlanesBuilder):
|
|
|
16
16
|
crystal_lattice_planes_material = super()._generate(configuration)
|
|
17
17
|
|
|
18
18
|
crystal_lattice_planes_material_analyzer = self.get_analyzer(configuration)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
|
|
20
|
+
if configuration.termination_top is not None:
|
|
21
|
+
termination = configuration.termination_top
|
|
22
|
+
should_rotate = False
|
|
23
|
+
elif configuration.termination_bottom is not None:
|
|
24
|
+
termination = configuration.termination_bottom
|
|
25
|
+
should_rotate = True
|
|
26
|
+
else:
|
|
27
|
+
raise ValueError(
|
|
28
|
+
"Either termination_top or termination_bottom is required for AtomicLayersUniqueRepeatedBuilder"
|
|
24
29
|
)
|
|
30
|
+
|
|
31
|
+
translation_vector = (
|
|
32
|
+
crystal_lattice_planes_material_analyzer.get_translation_vector_for_termination_without_vacuum(termination)
|
|
25
33
|
)
|
|
26
34
|
material_translated = translate(crystal_lattice_planes_material, translation_vector)
|
|
27
35
|
material_translated_wrapped = wrap_to_unit_cell(material_translated)
|
|
36
|
+
|
|
37
|
+
if should_rotate:
|
|
38
|
+
# Rotation of basis around [1,0,0] yielded the same material, probably due to the symmetry of unit cell.
|
|
39
|
+
# rotation around X and Z simultaneously gives the mirroring effect. (x,y,z) ⟶ (z,−y,x)
|
|
40
|
+
material_translated_wrapped = rotate(material_translated_wrapped, angle=180, axis=[1, 0, 1])
|
|
28
41
|
material_translated_wrapped_layered = supercell(
|
|
29
42
|
material_translated_wrapped, [[1, 0, 0], [0, 1, 0], [0, 0, configuration.number_of_repetitions]]
|
|
30
43
|
)
|
|
@@ -35,9 +48,15 @@ class AtomicLayersUniqueRepeatedBuilder(CrystalLatticePlanesBuilder):
|
|
|
35
48
|
) -> MaterialWithBuildMetadata:
|
|
36
49
|
material_analyzer = BaseMaterialAnalyzer(material=material)
|
|
37
50
|
material.formula = material_analyzer.formula
|
|
38
|
-
termination = configuration.termination_top
|
|
39
51
|
miller_indices_str = str(MillerIndices(root=configuration.miller_indices))
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
|
|
53
|
+
if configuration.termination_top is not None:
|
|
54
|
+
termination_str = f"termination {configuration.termination_top}"
|
|
55
|
+
elif configuration.termination_bottom is not None:
|
|
56
|
+
termination_str = f"bottom termination {configuration.termination_bottom}"
|
|
57
|
+
else:
|
|
58
|
+
termination_str = ""
|
|
59
|
+
|
|
60
|
+
new_name = f"{material.formula}{miller_indices_str}, {termination_str}"
|
|
42
61
|
material.name = new_name
|
|
43
62
|
return material
|
|
@@ -9,5 +9,6 @@ from ..crystal_lattice_planes.configuration import CrystalLatticePlanesConfigura
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class AtomicLayersUniqueRepeatedConfiguration(CrystalLatticePlanesConfiguration, AtomicLayersUniqueRepeatedSchema):
|
|
12
|
-
termination_top: Optional[Termination]
|
|
12
|
+
termination_top: Optional[Termination] = None
|
|
13
|
+
termination_bottom: Optional[Termination] = None
|
|
13
14
|
number_of_repetitions: int
|
|
@@ -63,7 +63,10 @@ def recreate_slab_with_fractional_layers(
|
|
|
63
63
|
slab_with_int_layers_without_vacuum = create_slab(
|
|
64
64
|
crystal=slab_without_vacuum.atomic_layers.crystal,
|
|
65
65
|
miller_indices=slab_without_vacuum.atomic_layers.miller_indices,
|
|
66
|
-
|
|
66
|
+
termination_top_formula=slab_without_vacuum.atomic_layers.termination_top.formula
|
|
67
|
+
if slab_without_vacuum.atomic_layers.termination_top
|
|
68
|
+
else None,
|
|
69
|
+
termination_bottom_formula=None,
|
|
67
70
|
number_of_layers=ceiling_number_of_layers,
|
|
68
71
|
vacuum=0,
|
|
69
72
|
xy_supercell_matrix=build_parameters.xy_supercell_matrix,
|
|
@@ -560,3 +560,47 @@ SLAB_SrTiO3_011_TERMINATION_SrTiO = {
|
|
|
560
560
|
"type": "TRI",
|
|
561
561
|
},
|
|
562
562
|
}
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
SLAB_SrTiO3_011_TERMINATION_O2_BOTTOM = {
|
|
566
|
+
"name": "O3SrTi(011), bottom termination O2_Pmmm_2, Slab",
|
|
567
|
+
"basis": {
|
|
568
|
+
"elements": [
|
|
569
|
+
{"id": 0, "value": "Sr"},
|
|
570
|
+
{"id": 1, "value": "Ti"},
|
|
571
|
+
{"id": 2, "value": "O"},
|
|
572
|
+
{"id": 3, "value": "O"},
|
|
573
|
+
{"id": 4, "value": "O"},
|
|
574
|
+
{"id": 5, "value": "Sr"},
|
|
575
|
+
{"id": 6, "value": "Ti"},
|
|
576
|
+
{"id": 7, "value": "O"},
|
|
577
|
+
{"id": 8, "value": "O"},
|
|
578
|
+
{"id": 9, "value": "O"},
|
|
579
|
+
],
|
|
580
|
+
"coordinates": [
|
|
581
|
+
{"id": 0, "value": [0.5, 0.749999, 0.152537778]},
|
|
582
|
+
{"id": 1, "value": [0, 0.249999, 0.152537778]},
|
|
583
|
+
{"id": 2, "value": [0.5, 0.249999, 0.152537778]},
|
|
584
|
+
{"id": 3, "value": [0, 0.999999, 6.1e-7]},
|
|
585
|
+
{"id": 4, "value": [0, 0.499999, 6.1e-7]},
|
|
586
|
+
{"id": 5, "value": [0.5, 0.249999, 0.457612114]},
|
|
587
|
+
{"id": 6, "value": [0, 0.749999, 0.457612114]},
|
|
588
|
+
{"id": 7, "value": [0.5, 0.749999, 0.457612114]},
|
|
589
|
+
{"id": 8, "value": [0, 0.499999, 0.305074946]},
|
|
590
|
+
{"id": 9, "value": [0, 0.999999, 0.305074946]},
|
|
591
|
+
],
|
|
592
|
+
"units": "crystal",
|
|
593
|
+
"labels": [],
|
|
594
|
+
"constraints": [],
|
|
595
|
+
},
|
|
596
|
+
"lattice": {
|
|
597
|
+
"a": 3.912701,
|
|
598
|
+
"b": 5.53339482,
|
|
599
|
+
"c": 9.068928726,
|
|
600
|
+
"alpha": 90,
|
|
601
|
+
"beta": 90,
|
|
602
|
+
"gamma": 90,
|
|
603
|
+
"units": {"length": "angstrom", "angle": "degree"},
|
|
604
|
+
"type": "TRI",
|
|
605
|
+
},
|
|
606
|
+
}
|
|
@@ -38,10 +38,20 @@ TEST_CASES = [(SUBSTRATE_SI_001, FILM_GE_001, EXPECTED_PROPERTIES_SI_GE_001)]
|
|
|
38
38
|
@pytest.mark.parametrize("substrate, film, expected", TEST_CASES)
|
|
39
39
|
def test_interface_analyzer(substrate, film, expected):
|
|
40
40
|
substrate_slab_config = SlabConfiguration.from_parameters(
|
|
41
|
-
substrate.bulk_config,
|
|
41
|
+
substrate.bulk_config,
|
|
42
|
+
substrate.miller_indices,
|
|
43
|
+
substrate.number_of_layers,
|
|
44
|
+
vacuum=substrate.vacuum,
|
|
45
|
+
termination_top_formula=None,
|
|
46
|
+
termination_bottom_formula=None,
|
|
42
47
|
)
|
|
43
48
|
film_slab_config = SlabConfiguration.from_parameters(
|
|
44
|
-
film.bulk_config,
|
|
49
|
+
film.bulk_config,
|
|
50
|
+
film.miller_indices,
|
|
51
|
+
film.number_of_layers,
|
|
52
|
+
vacuum=film.vacuum,
|
|
53
|
+
termination_top_formula=None,
|
|
54
|
+
termination_bottom_formula=None,
|
|
45
55
|
)
|
|
46
56
|
|
|
47
57
|
interface_analyzer = InterfaceAnalyzer(
|
|
@@ -88,7 +98,12 @@ def test_commensurate_analyzer_functionality(
|
|
|
88
98
|
material_config, analyzer_params, expected_matches_len, expected_angle_range
|
|
89
99
|
):
|
|
90
100
|
slab_config = SlabConfiguration.from_parameters(
|
|
91
|
-
material_config,
|
|
101
|
+
material_config,
|
|
102
|
+
miller_indices=(0, 0, 1),
|
|
103
|
+
number_of_layers=1,
|
|
104
|
+
vacuum=0.0,
|
|
105
|
+
termination_top_formula=None,
|
|
106
|
+
termination_bottom_formula=None,
|
|
92
107
|
)
|
|
93
108
|
|
|
94
109
|
analyzer = CommensurateLatticeInterfaceAnalyzer(substrate_slab_configuration=slab_config, **analyzer_params)
|
|
@@ -67,7 +67,12 @@ EXPECTED_PROPERTIES_SI_GE_001: Final = SimpleNamespace(
|
|
|
67
67
|
)
|
|
68
68
|
def test_zsl_interface_analyzer(substrate, film, zsl_params, expected_matches_min):
|
|
69
69
|
substrate_slab_config = SlabConfiguration.from_parameters(
|
|
70
|
-
substrate.bulk_config,
|
|
70
|
+
substrate.bulk_config,
|
|
71
|
+
substrate.miller_indices,
|
|
72
|
+
substrate.number_of_layers,
|
|
73
|
+
vacuum=0.0,
|
|
74
|
+
termination_top_formula=None,
|
|
75
|
+
termination_bottom_formula=None,
|
|
71
76
|
)
|
|
72
77
|
film_slab_config = SlabConfiguration.from_parameters(
|
|
73
78
|
film.bulk_config, film.miller_indices, film.number_of_layers, vacuum=0.0
|
|
@@ -150,7 +155,12 @@ def test_zsl_interface_analyzer_sort_by_strain_then_area(
|
|
|
150
155
|
|
|
151
156
|
analyzer = ZSLInterfaceAnalyzer(
|
|
152
157
|
substrate_slab_configuration=SlabConfiguration.from_parameters(
|
|
153
|
-
substrate.bulk_config,
|
|
158
|
+
substrate.bulk_config,
|
|
159
|
+
substrate.miller_indices,
|
|
160
|
+
substrate.number_of_layers,
|
|
161
|
+
vacuum=0.0,
|
|
162
|
+
termination_top_formula=None,
|
|
163
|
+
termination_bottom_formula=None,
|
|
154
164
|
),
|
|
155
165
|
film_slab_configuration=SlabConfiguration.from_parameters(
|
|
156
166
|
film.bulk_config, film.miller_indices, film.number_of_layers, vacuum=0.0
|
|
@@ -47,6 +47,8 @@ def test_create_adatom(
|
|
|
47
47
|
crystal=Material.create(crystal_config),
|
|
48
48
|
number_of_layers=2,
|
|
49
49
|
xy_supercell_matrix=[[2, 0], [0, 2]],
|
|
50
|
+
termination_top_formula=None,
|
|
51
|
+
termination_bottom_formula=None,
|
|
50
52
|
)
|
|
51
53
|
defect = create_defect_adatom(slab, position_on_surface, distance_z, adatom_placement_method, chemical_element)
|
|
52
54
|
|
|
@@ -25,6 +25,8 @@ def test_create_island_defect(slab_parameters, condition_class, condition_params
|
|
|
25
25
|
Material.create(slab_parameters["crystal"]),
|
|
26
26
|
number_of_layers=slab_parameters["number_of_layers"],
|
|
27
27
|
xy_supercell_matrix=slab_parameters["xy_supercell_matrix"],
|
|
28
|
+
termination_top_formula=None,
|
|
29
|
+
termination_bottom_formula=None,
|
|
28
30
|
)
|
|
29
31
|
condition = condition_class(
|
|
30
32
|
center_position=condition_params["center_position"],
|
|
@@ -30,6 +30,8 @@ def test_create_terrace(
|
|
|
30
30
|
Material.create(slab_parameters["crystal"]),
|
|
31
31
|
number_of_layers=slab_parameters["number_of_layers"],
|
|
32
32
|
xy_supercell_matrix=slab_parameters["xy_supercell_matrix"],
|
|
33
|
+
termination_top_formula=None,
|
|
34
|
+
termination_bottom_formula=None,
|
|
33
35
|
)
|
|
34
36
|
terrace = create_defect_terrace(
|
|
35
37
|
slab=slab,
|
|
@@ -82,10 +82,16 @@ PRECISION = 1e-3
|
|
|
82
82
|
def test_simple_interface_builder(substrate, film, expected_interface):
|
|
83
83
|
builder = InterfaceBuilder(build_parameters=InterfaceBuilderParameters(make_primitive=False))
|
|
84
84
|
substrate_slab_config = SlabConfiguration.from_parameters(
|
|
85
|
-
substrate.bulk_config,
|
|
85
|
+
substrate.bulk_config,
|
|
86
|
+
substrate.miller_indices,
|
|
87
|
+
substrate.number_of_layers,
|
|
88
|
+
vacuum=substrate.vacuum,
|
|
86
89
|
)
|
|
87
90
|
film_slab_config = SlabConfiguration.from_parameters(
|
|
88
|
-
film.bulk_config,
|
|
91
|
+
film.bulk_config,
|
|
92
|
+
film.miller_indices,
|
|
93
|
+
film.number_of_layers,
|
|
94
|
+
vacuum=film.vacuum,
|
|
89
95
|
)
|
|
90
96
|
|
|
91
97
|
analyzer = InterfaceAnalyzer(
|
|
@@ -111,14 +117,12 @@ def test_create_simple_interface_between_slabs(substrate, film, expected_interfa
|
|
|
111
117
|
miller_indices=substrate.miller_indices,
|
|
112
118
|
number_of_layers=substrate.number_of_layers,
|
|
113
119
|
vacuum=0,
|
|
114
|
-
termination_formula=None,
|
|
115
120
|
)
|
|
116
121
|
film_slab_config = SlabConfiguration.from_parameters(
|
|
117
122
|
material_or_dict=film.bulk_config,
|
|
118
123
|
miller_indices=film.miller_indices,
|
|
119
124
|
number_of_layers=film.number_of_layers,
|
|
120
125
|
vacuum=0,
|
|
121
|
-
termination_formula=None,
|
|
122
126
|
)
|
|
123
127
|
|
|
124
128
|
substrate_slab = SlabBuilder().get_material(substrate_slab_config)
|
|
@@ -129,7 +129,7 @@ def test_create_zsl_interface_between_slabs(substrate, film, gap, vacuum, max_ar
|
|
|
129
129
|
miller_indices=substrate.miller_indices,
|
|
130
130
|
number_of_layers=substrate.number_of_layers,
|
|
131
131
|
vacuum=0.0,
|
|
132
|
-
|
|
132
|
+
termination_top_formula=None,
|
|
133
133
|
use_conventional_cell=True,
|
|
134
134
|
)
|
|
135
135
|
film_slab_config = SlabConfiguration.from_parameters(
|
|
@@ -137,7 +137,7 @@ def test_create_zsl_interface_between_slabs(substrate, film, gap, vacuum, max_ar
|
|
|
137
137
|
miller_indices=film.miller_indices,
|
|
138
138
|
number_of_layers=film.number_of_layers,
|
|
139
139
|
vacuum=0.0,
|
|
140
|
-
|
|
140
|
+
termination_bottom_formula=None,
|
|
141
141
|
use_conventional_cell=True,
|
|
142
142
|
)
|
|
143
143
|
|
|
@@ -17,7 +17,7 @@ from mat3ra.made.tools.build.pristine_structures.two_dimensional.slab import (
|
|
|
17
17
|
SlabBuilderParameters,
|
|
18
18
|
SlabConfiguration,
|
|
19
19
|
)
|
|
20
|
-
from mat3ra.made.tools.build.pristine_structures.two_dimensional.slab.helpers import create_slab
|
|
20
|
+
from mat3ra.made.tools.build.pristine_structures.two_dimensional.slab.helpers import create_slab
|
|
21
21
|
from mat3ra.made.tools.build.pristine_structures.two_dimensional.slab.termination_utils import select_slab_termination
|
|
22
22
|
from mat3ra.made.tools.build.pristine_structures.two_dimensional.slab_strained_supercell.builder import (
|
|
23
23
|
SlabStrainedSupercellBuilder,
|
|
@@ -39,6 +39,7 @@ from unit.fixtures.slab import (
|
|
|
39
39
|
SI_PRIMITIVE_SLAB_001,
|
|
40
40
|
SLAB_SI_CONVENTIONAL_001_NO_VACUUM,
|
|
41
41
|
SLAB_SrTiO3_011_TERMINATION_O2,
|
|
42
|
+
SLAB_SrTiO3_011_TERMINATION_O2_BOTTOM,
|
|
42
43
|
SLAB_SrTiO3_011_TERMINATION_SrTiO,
|
|
43
44
|
)
|
|
44
45
|
|
|
@@ -79,6 +80,7 @@ PARAMS_BUILD_SLAB_CONVENTIONAL_SrTiO_SrTiO: Final = (
|
|
|
79
80
|
BULK_SrTiO3,
|
|
80
81
|
(0, 1, 1),
|
|
81
82
|
"SrTiO",
|
|
83
|
+
None,
|
|
82
84
|
2,
|
|
83
85
|
5.0,
|
|
84
86
|
[[1, 0], [0, 1]],
|
|
@@ -88,6 +90,18 @@ PARAMS_BUILD_SLAB_CONVENTIONAL_SrTiO_O2: Final = (
|
|
|
88
90
|
BULK_SrTiO3,
|
|
89
91
|
(0, 1, 1),
|
|
90
92
|
"O2",
|
|
93
|
+
None,
|
|
94
|
+
2,
|
|
95
|
+
5.0,
|
|
96
|
+
[[1, 0], [0, 1]],
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
PARAMS_BUILD_SLAB_CONVENTIONAL_SrTiO_O2_BOTTOM: Final = (
|
|
101
|
+
BULK_SrTiO3,
|
|
102
|
+
(0, 1, 1),
|
|
103
|
+
None,
|
|
104
|
+
"O2",
|
|
91
105
|
2,
|
|
92
106
|
5.0,
|
|
93
107
|
[[1, 0], [0, 1]],
|
|
@@ -97,6 +111,7 @@ PARAMS_CREATE_SLAB: Final = (
|
|
|
97
111
|
BULK_Si_CONVENTIONAL,
|
|
98
112
|
(0, 0, 1),
|
|
99
113
|
"Si",
|
|
114
|
+
None,
|
|
100
115
|
2,
|
|
101
116
|
5,
|
|
102
117
|
[[1, 0], [0, 1]],
|
|
@@ -107,7 +122,8 @@ PARAMS_CREATE_SLAB: Final = (
|
|
|
107
122
|
def get_slab_with_builder(
|
|
108
123
|
material: Material,
|
|
109
124
|
miller_indices: Tuple[int, int, int],
|
|
110
|
-
|
|
125
|
+
termination_top_formula: str,
|
|
126
|
+
termination_bottom_formula: str,
|
|
111
127
|
number_of_layers: int,
|
|
112
128
|
vacuum: float,
|
|
113
129
|
xy_supercell_matrix: list,
|
|
@@ -116,12 +132,20 @@ def get_slab_with_builder(
|
|
|
116
132
|
material=material, miller_indices=miller_indices
|
|
117
133
|
)
|
|
118
134
|
terminations = crystal_lattice_planes_analyzer.terminations
|
|
119
|
-
|
|
135
|
+
termination_top = (
|
|
136
|
+
select_slab_termination(terminations, termination_top_formula) if termination_top_formula is not None else None
|
|
137
|
+
)
|
|
138
|
+
termination_bottom = (
|
|
139
|
+
select_slab_termination(terminations, termination_bottom_formula)
|
|
140
|
+
if termination_bottom_formula is not None
|
|
141
|
+
else None
|
|
142
|
+
)
|
|
120
143
|
|
|
121
144
|
atomic_layers_repeated_configuration = AtomicLayersUniqueRepeatedConfiguration(
|
|
122
145
|
crystal=material,
|
|
123
146
|
miller_indices=miller_indices,
|
|
124
|
-
termination_top=
|
|
147
|
+
termination_top=termination_top,
|
|
148
|
+
termination_bottom=termination_bottom,
|
|
125
149
|
number_of_repetitions=number_of_layers,
|
|
126
150
|
)
|
|
127
151
|
atomic_layers_repeated_orthogonal_c = AtomicLayersUniqueRepeatedBuilder().get_material(
|
|
@@ -159,7 +183,7 @@ def test_build_slab_primitive(
|
|
|
159
183
|
):
|
|
160
184
|
material = MaterialWithBuildMetadata.create(material_config)
|
|
161
185
|
slab = get_slab_with_builder(
|
|
162
|
-
material, miller_indices, termination_formula, number_of_layers, vacuum, xy_supercell_matrix
|
|
186
|
+
material, miller_indices, termination_formula, None, number_of_layers, vacuum, xy_supercell_matrix
|
|
163
187
|
)
|
|
164
188
|
slab.metadata.build = [] # Remove build metadata for comparison
|
|
165
189
|
expected_slab_config.get("metadata", {}).pop("build", None) # Remove build metadata for comparison
|
|
@@ -198,6 +222,7 @@ def test_build_slab_conventional(
|
|
|
198
222
|
conventional_material,
|
|
199
223
|
miller_indices,
|
|
200
224
|
termination_formula,
|
|
225
|
+
None,
|
|
201
226
|
number_of_layers,
|
|
202
227
|
vacuum,
|
|
203
228
|
xy_supercell_matrix,
|
|
@@ -207,7 +232,7 @@ def test_build_slab_conventional(
|
|
|
207
232
|
|
|
208
233
|
|
|
209
234
|
@pytest.mark.parametrize(
|
|
210
|
-
"material_config, miller_indices,
|
|
235
|
+
"material_config, miller_indices, termination_top_formula,termination_bottom_formula, number_of_layers,"
|
|
211
236
|
+ " vacuum, xy_supercell_matrix, expected_slab_config",
|
|
212
237
|
[
|
|
213
238
|
(
|
|
@@ -218,12 +243,17 @@ def test_build_slab_conventional(
|
|
|
218
243
|
*PARAMS_BUILD_SLAB_CONVENTIONAL_SrTiO_O2,
|
|
219
244
|
SLAB_SrTiO3_011_TERMINATION_O2,
|
|
220
245
|
),
|
|
246
|
+
(
|
|
247
|
+
*PARAMS_BUILD_SLAB_CONVENTIONAL_SrTiO_O2_BOTTOM,
|
|
248
|
+
SLAB_SrTiO3_011_TERMINATION_O2_BOTTOM,
|
|
249
|
+
),
|
|
221
250
|
],
|
|
222
251
|
)
|
|
223
252
|
def test_build_slab_conventional_with_multiple_terminations(
|
|
224
253
|
material_config,
|
|
225
254
|
miller_indices,
|
|
226
|
-
|
|
255
|
+
termination_top_formula,
|
|
256
|
+
termination_bottom_formula,
|
|
227
257
|
number_of_layers,
|
|
228
258
|
vacuum,
|
|
229
259
|
xy_supercell_matrix,
|
|
@@ -236,7 +266,8 @@ def test_build_slab_conventional_with_multiple_terminations(
|
|
|
236
266
|
slab = get_slab_with_builder(
|
|
237
267
|
conventional_material,
|
|
238
268
|
miller_indices,
|
|
239
|
-
|
|
269
|
+
termination_top_formula,
|
|
270
|
+
termination_bottom_formula,
|
|
240
271
|
number_of_layers,
|
|
241
272
|
vacuum,
|
|
242
273
|
xy_supercell_matrix,
|
|
@@ -248,7 +279,7 @@ def test_build_slab_conventional_with_multiple_terminations(
|
|
|
248
279
|
|
|
249
280
|
|
|
250
281
|
@pytest.mark.parametrize(
|
|
251
|
-
"material_config, miller_indices,
|
|
282
|
+
"material_config, miller_indices, termination_top_formula, termination_bottom_formula, number_of_layers,"
|
|
252
283
|
+ " vacuum, xy_supercell, use_conventional_cell, expected_slab_config",
|
|
253
284
|
[
|
|
254
285
|
(
|
|
@@ -260,7 +291,8 @@ def test_build_slab_conventional_with_multiple_terminations(
|
|
|
260
291
|
def test_create_slab(
|
|
261
292
|
material_config,
|
|
262
293
|
miller_indices,
|
|
263
|
-
|
|
294
|
+
termination_top_formula,
|
|
295
|
+
termination_bottom_formula,
|
|
264
296
|
number_of_layers,
|
|
265
297
|
vacuum,
|
|
266
298
|
xy_supercell,
|
|
@@ -268,13 +300,12 @@ def test_create_slab(
|
|
|
268
300
|
expected_slab_config,
|
|
269
301
|
):
|
|
270
302
|
crystal = Material.create(material_config)
|
|
271
|
-
terminations = get_slab_terminations(material=crystal, miller_indices=miller_indices)
|
|
272
|
-
termination = select_slab_termination(terminations, termination_formula)
|
|
273
303
|
slab = create_slab(
|
|
274
304
|
crystal=crystal,
|
|
275
305
|
miller_indices=miller_indices,
|
|
276
306
|
use_conventional_cell=use_conventional_cell,
|
|
277
|
-
|
|
307
|
+
termination_top_formula=termination_top_formula,
|
|
308
|
+
termination_bottom_formula=termination_bottom_formula,
|
|
278
309
|
number_of_layers=number_of_layers,
|
|
279
310
|
vacuum=vacuum,
|
|
280
311
|
xy_supercell_matrix=xy_supercell,
|
|
@@ -326,7 +357,7 @@ def test_build_slab_strained(
|
|
|
326
357
|
config = SlabStrainedSupercellConfiguration.from_parameters(
|
|
327
358
|
material_or_dict=material,
|
|
328
359
|
miller_indices=miller_indices,
|
|
329
|
-
|
|
360
|
+
termination_top_formula=termination_formula,
|
|
330
361
|
number_of_layers=number_of_layers,
|
|
331
362
|
vacuum=vacuum,
|
|
332
363
|
)
|