@mat3ra/made 2024.7.31-0 → 2024.7.31-1
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/src/py/mat3ra/made/tools/analyze.py +8 -4
- package/src/py/mat3ra/made/tools/build/defect/__init__.py +1 -9
- package/src/py/mat3ra/made/tools/build/defect/builders.py +77 -15
- package/src/py/mat3ra/made/tools/build/defect/configuration.py +28 -2
- package/src/py/mat3ra/made/tools/build/defect/enums.py +15 -0
- package/src/py/mat3ra/made/tools/build/defect/factories.py +12 -0
- package/tests/py/unit/fixtures.py +25 -1
- package/tests/py/unit/test_tools_build_defect.py +38 -31
package/package.json
CHANGED
|
@@ -246,10 +246,12 @@ def get_atom_indices_with_condition_on_coordinates(
|
|
|
246
246
|
List[int]: List of indices of atoms whose coordinates satisfy the condition.
|
|
247
247
|
"""
|
|
248
248
|
new_material = material.clone()
|
|
249
|
+
new_basis = new_material.basis
|
|
249
250
|
if use_cartesian_coordinates:
|
|
250
|
-
new_basis = new_material.basis
|
|
251
251
|
new_basis.to_cartesian()
|
|
252
|
-
|
|
252
|
+
else:
|
|
253
|
+
new_basis.to_crystal()
|
|
254
|
+
new_material.basis = new_basis
|
|
253
255
|
coordinates = new_material.basis.coordinates.to_array_of_values_with_ids()
|
|
254
256
|
|
|
255
257
|
selected_indices = []
|
|
@@ -313,10 +315,12 @@ def get_atomic_coordinates_extremum(
|
|
|
313
315
|
float: Minimum or maximum of coordinates along the specified axis.
|
|
314
316
|
"""
|
|
315
317
|
new_material = material.clone()
|
|
318
|
+
new_basis = new_material.basis
|
|
316
319
|
if use_cartesian_coordinates:
|
|
317
|
-
new_basis = new_material.basis
|
|
318
320
|
new_basis.to_cartesian()
|
|
319
|
-
|
|
321
|
+
else:
|
|
322
|
+
new_basis.to_crystal()
|
|
323
|
+
new_material.basis = new_basis
|
|
320
324
|
coordinates = new_material.basis.coordinates.to_array_of_values_with_ids()
|
|
321
325
|
values = [coord.value[{"x": 0, "y": 1, "z": 2}[axis]] for coord in coordinates]
|
|
322
326
|
return getattr(np, extremum)(values)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import Optional, Union
|
|
2
2
|
|
|
3
|
-
from mat3ra.utils.factory import BaseFactory
|
|
4
3
|
from mat3ra.made.material import Material
|
|
5
4
|
|
|
6
5
|
from .builders import (
|
|
@@ -14,14 +13,7 @@ from .builders import (
|
|
|
14
13
|
)
|
|
15
14
|
from .configuration import PointDefectConfiguration, AdatomSlabPointDefectConfiguration, IslandSlabDefectConfiguration
|
|
16
15
|
from .enums import PointDefectTypeEnum
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class DefectBuilderFactory(BaseFactory):
|
|
20
|
-
__class_registry__ = {
|
|
21
|
-
PointDefectTypeEnum.VACANCY: "mat3ra.made.tools.build.defect.builders.VacancyPointDefectBuilder",
|
|
22
|
-
PointDefectTypeEnum.SUBSTITUTION: "mat3ra.made.tools.build.defect.builders.SubstitutionPointDefectBuilder",
|
|
23
|
-
PointDefectTypeEnum.INTERSTITIAL: "mat3ra.made.tools.build.defect.builders.InterstitialPointDefectBuilder",
|
|
24
|
-
}
|
|
16
|
+
from .factories import DefectBuilderFactory
|
|
25
17
|
|
|
26
18
|
|
|
27
19
|
def create_defect(
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from typing import List, Callable, Optional
|
|
1
|
+
from typing import List, Callable, Optional, Union
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from pydantic import BaseModel
|
|
5
5
|
from mat3ra.made.material import Material
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
from ...third_party import (
|
|
8
9
|
PymatgenStructure,
|
|
9
10
|
PymatgenPeriodicSite,
|
|
@@ -39,7 +40,9 @@ from .configuration import (
|
|
|
39
40
|
AdatomSlabPointDefectConfiguration,
|
|
40
41
|
IslandSlabDefectConfiguration,
|
|
41
42
|
TerraceSlabDefectConfiguration,
|
|
43
|
+
PointDefectPairConfiguration,
|
|
42
44
|
)
|
|
45
|
+
from .factories import DefectBuilderFactory
|
|
43
46
|
|
|
44
47
|
|
|
45
48
|
class PointDefectBuilderParameters(BaseModel):
|
|
@@ -47,7 +50,7 @@ class PointDefectBuilderParameters(BaseModel):
|
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
class DefectBuilder(BaseBuilder):
|
|
50
|
-
def create_isolated_defect(self,
|
|
53
|
+
def create_isolated_defect(self, defect_configuration: PointDefectConfiguration) -> Material:
|
|
51
54
|
raise NotImplementedError
|
|
52
55
|
|
|
53
56
|
|
|
@@ -171,8 +174,7 @@ class AdatomSlabDefectBuilder(SlabDefectBuilder):
|
|
|
171
174
|
def _calculate_coordinate_from_position_and_distance(
|
|
172
175
|
self, material: Material, position_on_surface: List[float], distance_z: float
|
|
173
176
|
) -> List[float]:
|
|
174
|
-
max_z = get_atomic_coordinates_extremum(material)
|
|
175
|
-
distance_z = distance_z
|
|
177
|
+
max_z = get_atomic_coordinates_extremum(material, use_cartesian_coordinates=False)
|
|
176
178
|
distance_in_crystal_units = distance_z / material.lattice.c
|
|
177
179
|
return [position_on_surface[0], position_on_surface[1], max_z + distance_in_crystal_units]
|
|
178
180
|
|
|
@@ -272,12 +274,16 @@ class CrystalSiteAdatomSlabDefectBuilder(AdatomSlabDefectBuilder):
|
|
|
272
274
|
)
|
|
273
275
|
return approximate_adatom_coordinate_cartesian
|
|
274
276
|
|
|
275
|
-
def
|
|
277
|
+
def create_isolated_adatom(
|
|
276
278
|
self,
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
chemical_element: Optional[str] = None,
|
|
279
|
+
original_material: Material,
|
|
280
|
+
configuration: AdatomSlabPointDefectConfiguration,
|
|
280
281
|
) -> Material:
|
|
282
|
+
material: Material = configuration.crystal
|
|
283
|
+
approximate_adatom_coordinate_cartesian: List[float] = self.calculate_approximate_adatom_coordinate(
|
|
284
|
+
original_material, configuration.position_on_surface, configuration.distance_z
|
|
285
|
+
)
|
|
286
|
+
chemical_element: Optional[str] = configuration.chemical_element or None
|
|
281
287
|
if chemical_element is None:
|
|
282
288
|
closest_site_id = get_closest_site_id_from_coordinate(material, approximate_adatom_coordinate_cartesian)
|
|
283
289
|
else:
|
|
@@ -310,21 +316,77 @@ class CrystalSiteAdatomSlabDefectBuilder(AdatomSlabDefectBuilder):
|
|
|
310
316
|
position_on_surface = [0.5, 0.5]
|
|
311
317
|
|
|
312
318
|
new_material = material.clone()
|
|
313
|
-
|
|
314
|
-
approximate_adatom_coordinate_cartesian = self.calculate_approximate_adatom_coordinate(
|
|
315
|
-
new_material, position_on_surface, distance_z
|
|
316
|
-
)
|
|
317
|
-
|
|
318
319
|
material_with_additional_layer = self.create_material_with_additional_layers(new_material)
|
|
319
320
|
material_with_additional_layer.to_cartesian()
|
|
320
321
|
|
|
321
|
-
only_adatom_material = self.
|
|
322
|
-
|
|
322
|
+
only_adatom_material = self.create_isolated_adatom(
|
|
323
|
+
original_material=new_material,
|
|
324
|
+
configuration=AdatomSlabPointDefectConfiguration(
|
|
325
|
+
crystal=material_with_additional_layer,
|
|
326
|
+
chemical_element=chemical_element,
|
|
327
|
+
position_on_surface=position_on_surface,
|
|
328
|
+
distance_z=distance_z,
|
|
329
|
+
),
|
|
323
330
|
)
|
|
324
331
|
|
|
325
332
|
return self.merge_slab_and_defect(new_material, only_adatom_material)
|
|
326
333
|
|
|
327
334
|
|
|
335
|
+
class DefectPairBuilder(DefectBuilder):
|
|
336
|
+
def create_defect_pair(
|
|
337
|
+
self,
|
|
338
|
+
primary_defect_configuration: Union[PointDefectConfiguration, AdatomSlabPointDefectConfiguration],
|
|
339
|
+
secondary_defect_configuration: Union[PointDefectConfiguration, AdatomSlabPointDefectConfiguration],
|
|
340
|
+
) -> Material:
|
|
341
|
+
"""
|
|
342
|
+
Create a pair of point defects in the material.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
primary_defect_configuration: The configuration of the first defect.
|
|
346
|
+
secondary_defect_configuration: The configuration of the second defect.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
Material: The material with both defects added.
|
|
350
|
+
"""
|
|
351
|
+
primary_material = self.create_isolated_defect(primary_defect_configuration)
|
|
352
|
+
# Remove metadata to allow for independent defect creation
|
|
353
|
+
primary_material.metadata["build"] = primary_defect_configuration.crystal.metadata["build"]
|
|
354
|
+
primary_material.name = primary_defect_configuration.crystal.name
|
|
355
|
+
secondary_defect_configuration.crystal = primary_material
|
|
356
|
+
secondary_material = self.create_isolated_defect(secondary_defect_configuration)
|
|
357
|
+
|
|
358
|
+
return secondary_material
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class PointDefectPairBuilder(PointDefectBuilder, DefectPairBuilder):
|
|
362
|
+
_ConfigurationType: type(PointDefectPairConfiguration) = PointDefectPairConfiguration # type: ignore
|
|
363
|
+
_GeneratedItemType: Material = Material
|
|
364
|
+
|
|
365
|
+
def create_isolated_defect(self, defect_configuration: PointDefectConfiguration) -> Material:
|
|
366
|
+
key = defect_configuration.defect_type.value
|
|
367
|
+
if hasattr(defect_configuration, "placement_method") and defect_configuration.placement_method is not None:
|
|
368
|
+
key += f":{defect_configuration.placement_method.name}".lower()
|
|
369
|
+
builder_class = DefectBuilderFactory.get_class_by_name(key)
|
|
370
|
+
defect_builder = builder_class()
|
|
371
|
+
return defect_builder.get_material(defect_configuration)
|
|
372
|
+
|
|
373
|
+
def _generate(self, configuration: _ConfigurationType) -> List[_GeneratedItemType]:
|
|
374
|
+
return [
|
|
375
|
+
self.create_defect_pair(
|
|
376
|
+
primary_defect_configuration=configuration.primary_defect_configuration,
|
|
377
|
+
secondary_defect_configuration=configuration.secondary_defect_configuration,
|
|
378
|
+
)
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
def _update_material_name(self, material: Material, configuration: _ConfigurationType) -> Material:
|
|
382
|
+
updated_material = super()._update_material_name(material, configuration)
|
|
383
|
+
name_1 = configuration.primary_defect_configuration.defect_type.name.capitalize()
|
|
384
|
+
name_2 = configuration.secondary_defect_configuration.defect_type.name.capitalize()
|
|
385
|
+
new_name = f"{updated_material.name}, {name_1} and {name_2} Defect Pair"
|
|
386
|
+
updated_material.name = new_name
|
|
387
|
+
return updated_material
|
|
388
|
+
|
|
389
|
+
|
|
328
390
|
class IslandSlabDefectBuilder(SlabDefectBuilder):
|
|
329
391
|
_ConfigurationType: type(IslandSlabDefectConfiguration) = IslandSlabDefectConfiguration # type: ignore
|
|
330
392
|
_GeneratedItemType: Material = Material
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional, List, Any, Callable, Dict, Tuple
|
|
1
|
+
from typing import Optional, List, Any, Callable, Dict, Tuple, Union
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
|
|
4
4
|
from mat3ra.code.entity import InMemoryEntity
|
|
@@ -6,7 +6,7 @@ from mat3ra.made.material import Material
|
|
|
6
6
|
|
|
7
7
|
from ...analyze import get_closest_site_id_from_coordinate, get_atomic_coordinates_extremum
|
|
8
8
|
from ...utils import CoordinateConditionBuilder
|
|
9
|
-
from .enums import PointDefectTypeEnum, SlabDefectTypeEnum
|
|
9
|
+
from .enums import PointDefectTypeEnum, SlabDefectTypeEnum, AtomPlacementMethodEnum, ComplexDefectTypeEnum
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class BaseDefectConfiguration(BaseModel):
|
|
@@ -144,12 +144,15 @@ class AdatomSlabPointDefectConfiguration(SlabPointDefectConfiguration):
|
|
|
144
144
|
"""
|
|
145
145
|
|
|
146
146
|
defect_type: PointDefectTypeEnum = PointDefectTypeEnum.ADATOM
|
|
147
|
+
placement_method: AtomPlacementMethodEnum = AtomPlacementMethodEnum.COORDINATE
|
|
147
148
|
|
|
148
149
|
@property
|
|
149
150
|
def _json(self):
|
|
150
151
|
return {
|
|
151
152
|
**super()._json,
|
|
152
153
|
"type": self.get_cls_name(),
|
|
154
|
+
"defect_type": self.defect_type.name,
|
|
155
|
+
"placement_method": self.placement_method.name,
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
|
|
@@ -212,3 +215,26 @@ class TerraceSlabDefectConfiguration(SlabDefectConfiguration):
|
|
|
212
215
|
"use_cartesian_coordinates": self.use_cartesian_coordinates,
|
|
213
216
|
"rotate_to_match_pbc": self.rotate_to_match_pbc,
|
|
214
217
|
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class PointDefectPairConfiguration(BaseDefectConfiguration, InMemoryEntity):
|
|
221
|
+
"""
|
|
222
|
+
Configuration for a pair of point defects.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
primary_defect_configuration: The first defect configuration.
|
|
226
|
+
secondary_defect_configuration: The second defect configuration. Material is used from the primary defect.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
defect_type: ComplexDefectTypeEnum = ComplexDefectTypeEnum.PAIR
|
|
230
|
+
primary_defect_configuration: Union[PointDefectConfiguration, AdatomSlabPointDefectConfiguration]
|
|
231
|
+
secondary_defect_configuration: Union[PointDefectConfiguration, AdatomSlabPointDefectConfiguration]
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def _json(self):
|
|
235
|
+
return {
|
|
236
|
+
"type": self.get_cls_name(),
|
|
237
|
+
"defect_type": self.defect_type.name,
|
|
238
|
+
"primary_defect_configuration": self.primary_defect_configuration.to_json(),
|
|
239
|
+
"secondary_defect_configuration": self.secondary_defect_configuration.to_json(),
|
|
240
|
+
}
|
|
@@ -11,3 +11,18 @@ class PointDefectTypeEnum(str, Enum):
|
|
|
11
11
|
class SlabDefectTypeEnum(str, Enum):
|
|
12
12
|
ISLAND = "island"
|
|
13
13
|
TERRACE = "terrace"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ComplexDefectTypeEnum(str, Enum):
|
|
17
|
+
PAIR = "pair"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AtomPlacementMethodEnum(str, Enum):
|
|
21
|
+
# Places the atom at the exact given coordinate.
|
|
22
|
+
COORDINATE = "coordinate"
|
|
23
|
+
# Among existing atoms, selects the closest one to the given coordinate.
|
|
24
|
+
CLOSEST_SITE = "closest_site"
|
|
25
|
+
# Places the atom at the equal distance from the closest atoms to the given coordinate.
|
|
26
|
+
EQUIDISTANT = "equidistant"
|
|
27
|
+
# Places the atom at the existing or extrapolated crystal site closest to the given coordinate.
|
|
28
|
+
CRYSTAL_SITE = "crystal_site"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from mat3ra.utils.factory import BaseFactory
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DefectBuilderFactory(BaseFactory):
|
|
5
|
+
__class_registry__ = {
|
|
6
|
+
"vacancy": "mat3ra.made.tools.build.defect.builders.VacancyPointDefectBuilder",
|
|
7
|
+
"substitution": "mat3ra.made.tools.build.defect.builders.SubstitutionPointDefectBuilder",
|
|
8
|
+
"interstitial": "mat3ra.made.tools.build.defect.builders.InterstitialPointDefectBuilder",
|
|
9
|
+
"adatom:coordinate": "mat3ra.made.tools.build.defect.builders.AdatomSlabDefectBuilder",
|
|
10
|
+
"adatom:crystal_site": "mat3ra.made.tools.build.defect.builders.CrystalSiteAdatomSlabDefectBuilder",
|
|
11
|
+
"adatom:equidistant": "mat3ra.made.tools.build.defect.builders.EquidistantAdatomSlabDefectBuilder",
|
|
12
|
+
}
|
|
@@ -4,7 +4,7 @@ from typing import Any, Dict
|
|
|
4
4
|
from ase.build import bulk
|
|
5
5
|
from mat3ra.made.material import Material
|
|
6
6
|
from mat3ra.made.tools.build.interface.termination_pair import TerminationPair
|
|
7
|
-
from mat3ra.made.tools.build.slab import SlabConfiguration, get_terminations
|
|
7
|
+
from mat3ra.made.tools.build.slab import SlabConfiguration, create_slab, get_terminations
|
|
8
8
|
from mat3ra.made.tools.convert import from_ase
|
|
9
9
|
from pymatgen.analysis.elasticity.strain import Strain
|
|
10
10
|
from pymatgen.core.interface import Interface
|
|
@@ -236,3 +236,27 @@ SI_SLAB_VACUUM["basis"]["coordinates"] = [
|
|
|
236
236
|
SI_SLAB_VACUUM["basis"]["cell"] = [[3.867, 0.0, 0.0], [-0.0, 3.867, 0.0], [0.0, 0.0, 15.937527692]]
|
|
237
237
|
SI_SLAB_VACUUM["lattice"]["c"] = 15.937527692
|
|
238
238
|
SI_SLAB_VACUUM["lattice"]["vectors"]["c"] = [0.0, 0.0, 15.937527692]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
clean_material = Material.create(Material.default_config)
|
|
242
|
+
slab_111_config = SlabConfiguration(
|
|
243
|
+
bulk=clean_material,
|
|
244
|
+
miller_indices=(1, 1, 1),
|
|
245
|
+
thickness=4,
|
|
246
|
+
vacuum=6,
|
|
247
|
+
xy_supercell_matrix=[[1, 0], [0, 1]],
|
|
248
|
+
use_orthogonal_z=True,
|
|
249
|
+
)
|
|
250
|
+
t_111 = get_terminations(slab_111_config)[0]
|
|
251
|
+
SLAB_111 = create_slab(slab_111_config, t_111)
|
|
252
|
+
|
|
253
|
+
slab_001_config = SlabConfiguration(
|
|
254
|
+
bulk=clean_material,
|
|
255
|
+
miller_indices=(0, 0, 1),
|
|
256
|
+
thickness=3,
|
|
257
|
+
vacuum=3,
|
|
258
|
+
xy_supercell_matrix=[[2, 0], [0, 1]],
|
|
259
|
+
use_orthogonal_z=True,
|
|
260
|
+
)
|
|
261
|
+
t_001 = get_terminations(slab_001_config)[0]
|
|
262
|
+
SLAB_001 = create_slab(slab_001_config, t_001)
|
|
@@ -5,27 +5,26 @@ from mat3ra.made.tools.build.defect import (
|
|
|
5
5
|
EquidistantAdatomSlabDefectBuilder,
|
|
6
6
|
PointDefectBuilderParameters,
|
|
7
7
|
PointDefectConfiguration,
|
|
8
|
+
PointDefectTypeEnum,
|
|
8
9
|
create_defect,
|
|
9
10
|
create_slab_defect,
|
|
10
11
|
)
|
|
11
|
-
from mat3ra.made.tools.build.defect.builders import
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
from mat3ra.made.tools.build.defect.builders import (
|
|
13
|
+
IslandSlabDefectBuilder,
|
|
14
|
+
PointDefectPairBuilder,
|
|
15
|
+
TerraceSlabDefectBuilder,
|
|
16
|
+
)
|
|
17
|
+
from mat3ra.made.tools.build.defect.configuration import (
|
|
18
|
+
IslandSlabDefectConfiguration,
|
|
19
|
+
PointDefectPairConfiguration,
|
|
20
|
+
TerraceSlabDefectConfiguration,
|
|
21
|
+
)
|
|
14
22
|
from mat3ra.made.tools.utils import CoordinateConditionBuilder
|
|
15
23
|
from mat3ra.utils import assertion as assertion_utils
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
from .fixtures import SLAB_001, SLAB_111
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
bulk=clean_material,
|
|
21
|
-
miller_indices=(1, 1, 1),
|
|
22
|
-
thickness=4,
|
|
23
|
-
vacuum=6,
|
|
24
|
-
xy_supercell_matrix=[[1, 0], [0, 1]],
|
|
25
|
-
use_orthogonal_z=True,
|
|
26
|
-
)
|
|
27
|
-
t = get_terminations(slab_config)[0]
|
|
28
|
-
slab = create_slab(slab_config, t)
|
|
27
|
+
clean_material = Material.create(Material.default_config)
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
def test_create_vacancy():
|
|
@@ -78,7 +77,7 @@ def test_create_defect_from_site_id():
|
|
|
78
77
|
def test_create_adatom():
|
|
79
78
|
# Adatom of Si at 0.5, 0.5 position
|
|
80
79
|
configuration = AdatomSlabPointDefectConfiguration(
|
|
81
|
-
crystal=
|
|
80
|
+
crystal=SLAB_111, position_on_surface=[0.5, 0.5], distance_z=2, chemical_element="Si"
|
|
82
81
|
)
|
|
83
82
|
defect = create_slab_defect(configuration=configuration, builder=None)
|
|
84
83
|
|
|
@@ -89,7 +88,7 @@ def test_create_adatom():
|
|
|
89
88
|
def test_create_adatom_equidistant():
|
|
90
89
|
# Adatom of Si at approximate 0.5, 0.5 position
|
|
91
90
|
configuration = AdatomSlabPointDefectConfiguration(
|
|
92
|
-
crystal=
|
|
91
|
+
crystal=SLAB_111, position_on_surface=[0.5, 0.5], distance_z=2, chemical_element="Si"
|
|
93
92
|
)
|
|
94
93
|
defect = create_slab_defect(configuration=configuration, builder=EquidistantAdatomSlabDefectBuilder())
|
|
95
94
|
|
|
@@ -103,7 +102,7 @@ def test_create_adatom_equidistant():
|
|
|
103
102
|
def test_create_crystal_site_adatom():
|
|
104
103
|
# Adatom of Si (autodetect) at approximate 0.5, 0.5 position
|
|
105
104
|
configuration = AdatomSlabPointDefectConfiguration(
|
|
106
|
-
crystal=
|
|
105
|
+
crystal=SLAB_111, position_on_surface=[0.5, 0.5], distance_z=2, chemical_element=None
|
|
107
106
|
)
|
|
108
107
|
builder = CrystalSiteAdatomSlabDefectBuilder()
|
|
109
108
|
defect = create_slab_defect(configuration=configuration, builder=builder)
|
|
@@ -117,7 +116,7 @@ def test_create_crystal_site_adatom():
|
|
|
117
116
|
def test_create_island():
|
|
118
117
|
condition = CoordinateConditionBuilder.cylinder(center_position=[0.625, 0.5], radius=0.25, min_z=0, max_z=1)
|
|
119
118
|
island_config = IslandSlabDefectConfiguration(
|
|
120
|
-
crystal=
|
|
119
|
+
crystal=SLAB_111,
|
|
121
120
|
defect_type="island",
|
|
122
121
|
condition=condition,
|
|
123
122
|
thickness=1,
|
|
@@ -126,27 +125,35 @@ def test_create_island():
|
|
|
126
125
|
defect = create_slab_defect(configuration=island_config, builder=IslandSlabDefectBuilder())
|
|
127
126
|
|
|
128
127
|
# Only one atom is in the island for this configuration
|
|
129
|
-
assert len(defect.basis.elements.values) == len(
|
|
128
|
+
assert len(defect.basis.elements.values) == len(SLAB_111.basis.elements.values) + 1
|
|
130
129
|
assert defect.basis.elements.values[-1] == "Si"
|
|
131
130
|
|
|
132
131
|
|
|
133
132
|
def test_create_terrace():
|
|
134
|
-
slab_config = SlabConfiguration(
|
|
135
|
-
bulk=clean_material,
|
|
136
|
-
miller_indices=(0, 0, 1),
|
|
137
|
-
thickness=3,
|
|
138
|
-
vacuum=3,
|
|
139
|
-
xy_supercell_matrix=[[2, 0], [0, 1]],
|
|
140
|
-
use_orthogonal_z=True,
|
|
141
|
-
)
|
|
142
|
-
t = get_terminations(slab_config)[0]
|
|
143
|
-
slab = create_slab(slab_config, t)
|
|
144
|
-
|
|
145
133
|
config = TerraceSlabDefectConfiguration(
|
|
146
|
-
crystal=
|
|
134
|
+
crystal=SLAB_001,
|
|
147
135
|
cut_direction=[1, 0, 0],
|
|
148
136
|
pivot_coordinate=[0.5, 0.5, 0.5],
|
|
149
137
|
number_of_added_layers=1,
|
|
150
138
|
)
|
|
151
139
|
new_slab = TerraceSlabDefectBuilder().get_material(configuration=config)
|
|
152
140
|
assertion_utils.assert_deep_almost_equal([0.720082355, 0.5, 0.461401798], new_slab.basis.coordinates.values[42])
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_create_defect_pair():
|
|
144
|
+
defect1_config = PointDefectConfiguration.from_approximate_position(
|
|
145
|
+
crystal=SLAB_001,
|
|
146
|
+
defect_type=PointDefectTypeEnum.VACANCY,
|
|
147
|
+
approximate_coordinate=[0.5, 0.5, 0.25],
|
|
148
|
+
)
|
|
149
|
+
defect2_config = PointDefectConfiguration(
|
|
150
|
+
defect_type=PointDefectTypeEnum.INTERSTITIAL, coordinate=[0.5, 0.55, 0.35], chemical_element="P"
|
|
151
|
+
)
|
|
152
|
+
defect_pair_config = PointDefectPairConfiguration(
|
|
153
|
+
primary_defect_configuration=defect1_config,
|
|
154
|
+
secondary_defect_configuration=defect2_config,
|
|
155
|
+
)
|
|
156
|
+
defect_material = PointDefectPairBuilder().get_material(defect_pair_config)
|
|
157
|
+
|
|
158
|
+
assertion_utils.assert_deep_almost_equal("P", defect_material.basis.elements.values[0])
|
|
159
|
+
assertion_utils.assert_deep_almost_equal([0.5, 0.55, 0.35], defect_material.basis.coordinates.values[0])
|