@mat3ra/made 2024.12.25-1 → 2024.12.28-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/src/py/mat3ra/made/basis.py +2 -3
- package/src/py/mat3ra/made/material.py +7 -8
- package/src/py/mat3ra/made/tools/build/interface/builders.py +20 -7
- package/src/py/mat3ra/made/tools/build/nanoribbon/builders.py +8 -6
- package/src/py/mat3ra/made/tools/build/perturbation/builders.py +1 -7
- package/src/py/mat3ra/made/tools/convert/__init__.py +2 -1
- package/tests/py/unit/fixtures.py +23 -39
- package/tests/py/unit/test_material.py +5 -13
- package/tests/py/unit/test_tools_build_defect.py +11 -4
- package/tests/py/unit/test_tools_build_interface.py +3 -3
- package/tests/py/unit/test_tools_build_perturbation.py +7 -8
- package/tests/py/unit/test_tools_modify.py +0 -1
package/package.json
CHANGED
|
@@ -41,15 +41,14 @@ class Basis(RoundNumericValuesMixin, BaseModel):
|
|
|
41
41
|
"elements": self.elements.to_json(),
|
|
42
42
|
"coordinates": self.coordinates.to_json(skip_rounding=skip_rounding),
|
|
43
43
|
"units": self.units,
|
|
44
|
-
"cell": self.cell.to_json(skip_rounding=skip_rounding) if self.cell else None,
|
|
45
44
|
"labels": self.labels.to_json(),
|
|
46
45
|
}
|
|
47
46
|
return json.loads(json.dumps(json_value))
|
|
48
47
|
|
|
49
48
|
def clone(self):
|
|
50
49
|
return Basis(
|
|
51
|
-
elements=self.
|
|
52
|
-
coordinates=self.
|
|
50
|
+
elements=self.elements,
|
|
51
|
+
coordinates=self.coordinates,
|
|
53
52
|
units=self.units,
|
|
54
53
|
cell=self.cell,
|
|
55
54
|
isEmpty=False,
|
|
@@ -67,7 +67,9 @@ class Material(HasDescriptionHasMetadataNamedDefaultableInMemoryEntity):
|
|
|
67
67
|
|
|
68
68
|
@property
|
|
69
69
|
def basis(self) -> Basis:
|
|
70
|
-
|
|
70
|
+
config = self.get_prop("basis")
|
|
71
|
+
config["cell"] = config.get("cell", self.lattice.vector_arrays)
|
|
72
|
+
return Basis.from_dict(**config)
|
|
71
73
|
|
|
72
74
|
@basis.setter
|
|
73
75
|
def basis(self, basis: Basis) -> None:
|
|
@@ -99,15 +101,12 @@ class Material(HasDescriptionHasMetadataNamedDefaultableInMemoryEntity):
|
|
|
99
101
|
def set_new_lattice_vectors(
|
|
100
102
|
self, lattice_vector1: List[float], lattice_vector2: List[float], lattice_vector3: List[float]
|
|
101
103
|
) -> None:
|
|
102
|
-
new_basis = self.basis.copy()
|
|
103
|
-
new_basis.to_cartesian()
|
|
104
|
-
new_basis.cell.vector1 = lattice_vector1
|
|
105
|
-
new_basis.cell.vector2 = lattice_vector2
|
|
106
|
-
new_basis.cell.vector3 = lattice_vector3
|
|
107
|
-
new_basis.to_crystal()
|
|
108
|
-
self.basis = new_basis
|
|
109
104
|
lattice = Lattice.from_vectors_array([lattice_vector1, lattice_vector2, lattice_vector3])
|
|
105
|
+
original_is_in_crystal = self.basis.is_in_crystal_units
|
|
106
|
+
self.to_cartesian()
|
|
110
107
|
self.lattice = lattice
|
|
108
|
+
if original_is_in_crystal:
|
|
109
|
+
self.to_crystal()
|
|
111
110
|
|
|
112
111
|
def add_atom(self, element: str, coordinate: List[float], use_cartesian_coordinates=False) -> None:
|
|
113
112
|
new_basis = self.basis.copy()
|
|
@@ -62,7 +62,8 @@ class InterfaceBuilder(BaseBuilder):
|
|
|
62
62
|
# Simple Interface Builder #
|
|
63
63
|
########################################################################################
|
|
64
64
|
class SimpleInterfaceBuilderParameters(InterfaceBuilderParameters):
|
|
65
|
-
scale_film: bool = True
|
|
65
|
+
scale_film: bool = True # Whether to scale the film to match the substrate
|
|
66
|
+
create_slabs: bool = True # Whether to create slabs from the configurations or use the bulk
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
class SimpleInterfaceBuilder(ConvertGeneratedItemsASEAtomsMixin, InterfaceBuilder):
|
|
@@ -74,15 +75,20 @@ class SimpleInterfaceBuilder(ConvertGeneratedItemsASEAtomsMixin, InterfaceBuilde
|
|
|
74
75
|
_DefaultBuildParameters = SimpleInterfaceBuilderParameters(scale_film=True)
|
|
75
76
|
_GeneratedItemType: type(ASEAtoms) = ASEAtoms # type: ignore
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
def __preprocess_slab_configuration(
|
|
79
|
+
self, configuration: SlabConfiguration, termination: Termination, create_slabs=False
|
|
80
|
+
) -> ASEAtoms:
|
|
81
|
+
slab = create_slab(configuration, termination) if create_slabs else configuration.bulk
|
|
80
82
|
ase_slab = to_ase(slab)
|
|
83
|
+
|
|
81
84
|
niggli_reduce(ase_slab)
|
|
82
85
|
return ase_slab
|
|
83
86
|
|
|
84
87
|
@staticmethod
|
|
85
88
|
def __combine_two_slabs_ase(substrate_slab_ase: ASEAtoms, film_slab_ase: ASEAtoms, distance_z: float) -> ASEAtoms:
|
|
89
|
+
total_z_height = substrate_slab_ase.cell[2][2] + film_slab_ase.cell[2][2] + distance_z
|
|
90
|
+
substrate_slab_ase.cell[2][2] = total_z_height
|
|
91
|
+
film_slab_ase.cell[2][2] = total_z_height
|
|
86
92
|
max_z_substrate = max(substrate_slab_ase.positions[:, 2])
|
|
87
93
|
min_z_film = min(film_slab_ase.positions[:, 2])
|
|
88
94
|
shift_z = max_z_substrate - min_z_film + distance_z
|
|
@@ -99,14 +105,21 @@ class SimpleInterfaceBuilder(ConvertGeneratedItemsASEAtomsMixin, InterfaceBuilde
|
|
|
99
105
|
|
|
100
106
|
def _generate(self, configuration: InterfaceBuilder._ConfigurationType) -> List[_GeneratedItemType]: # type: ignore
|
|
101
107
|
film_slab_ase = self.__preprocess_slab_configuration(
|
|
102
|
-
configuration.film_configuration,
|
|
108
|
+
configuration.film_configuration,
|
|
109
|
+
configuration.film_termination,
|
|
110
|
+
create_slabs=self.build_parameters.create_slabs,
|
|
103
111
|
)
|
|
104
112
|
substrate_slab_ase = self.__preprocess_slab_configuration(
|
|
105
|
-
configuration.substrate_configuration,
|
|
113
|
+
configuration.substrate_configuration,
|
|
114
|
+
configuration.substrate_termination,
|
|
115
|
+
create_slabs=self.build_parameters.create_slabs,
|
|
106
116
|
)
|
|
107
117
|
|
|
108
118
|
if self.build_parameters.scale_film:
|
|
109
|
-
|
|
119
|
+
temp_cell = [substrate_slab_ase.cell[0], substrate_slab_ase.cell[1], film_slab_ase.cell[2]]
|
|
120
|
+
# We scale the film in XY direction only, and use two scaling steps and a temporary cell
|
|
121
|
+
film_slab_ase.set_cell(temp_cell, scale_atoms=True)
|
|
122
|
+
film_slab_ase.set_cell(substrate_slab_ase.cell, scale_atoms=False)
|
|
110
123
|
film_slab_ase.wrap()
|
|
111
124
|
|
|
112
125
|
interface_ase = self.__combine_two_slabs_ase(substrate_slab_ase, film_slab_ase, configuration.distance_z)
|
|
@@ -7,7 +7,7 @@ from mat3ra.made.tools.build import BaseBuilder
|
|
|
7
7
|
from mat3ra.made.tools.build.supercell import create_supercell
|
|
8
8
|
from mat3ra.made.tools.modify import filter_by_rectangle_projection, wrap_to_unit_cell
|
|
9
9
|
|
|
10
|
-
from ...modify import translate_to_center
|
|
10
|
+
from ...modify import translate_to_center, rotate
|
|
11
11
|
from .configuration import NanoribbonConfiguration
|
|
12
12
|
from .enums import EdgeTypes
|
|
13
13
|
|
|
@@ -73,11 +73,11 @@ class NanoribbonBuilder(BaseBuilder):
|
|
|
73
73
|
nanoribbon_length, nanoribbon_width = nanoribbon_width, nanoribbon_length
|
|
74
74
|
vacuum_width, vacuum_length = vacuum_length, vacuum_width
|
|
75
75
|
|
|
76
|
-
length_cartesian = nanoribbon_length * np.dot(np.array(material.
|
|
77
|
-
width_cartesian = nanoribbon_width * np.dot(np.array(material.
|
|
78
|
-
height_cartesian = np.dot(np.array(material.
|
|
79
|
-
vacuum_length_cartesian = vacuum_length * np.dot(np.array(material.
|
|
80
|
-
vacuum_width_cartesian = vacuum_width * np.dot(np.array(material.
|
|
76
|
+
length_cartesian = nanoribbon_length * np.dot(np.array(material.lattice.vectors[0]), np.array([1, 0, 0]))
|
|
77
|
+
width_cartesian = nanoribbon_width * np.dot(np.array(material.lattice.vectors[1]), np.array([0, 1, 0]))
|
|
78
|
+
height_cartesian = np.dot(np.array(material.lattice.vectors[2]), np.array([0, 0, 1]))
|
|
79
|
+
vacuum_length_cartesian = vacuum_length * np.dot(np.array(material.lattice.vectors[0]), np.array([1, 0, 0]))
|
|
80
|
+
vacuum_width_cartesian = vacuum_width * np.dot(np.array(material.lattice.vectors[1]), np.array([0, 1, 0]))
|
|
81
81
|
|
|
82
82
|
return length_cartesian, width_cartesian, height_cartesian, vacuum_length_cartesian, vacuum_width_cartesian
|
|
83
83
|
|
|
@@ -134,6 +134,8 @@ class NanoribbonBuilder(BaseBuilder):
|
|
|
134
134
|
|
|
135
135
|
def _generate(self, configuration: NanoribbonConfiguration) -> List[_GeneratedItemType]:
|
|
136
136
|
nanoribbon = self.create_nanoribbon(configuration)
|
|
137
|
+
if configuration.edge_type == EdgeTypes.armchair:
|
|
138
|
+
nanoribbon = rotate(nanoribbon, [0, 0, 1], 90)
|
|
137
139
|
return [nanoribbon]
|
|
138
140
|
|
|
139
141
|
def _post_process(
|
|
@@ -65,7 +65,7 @@ class DistancePreservingSlabPerturbationBuilder(SlabPerturbationBuilder):
|
|
|
65
65
|
|
|
66
66
|
class CellMatchingDistancePreservingSlabPerturbationBuilder(DistancePreservingSlabPerturbationBuilder):
|
|
67
67
|
def _transform_lattice_vectors(self, configuration: PerturbationConfiguration) -> List[List[float]]:
|
|
68
|
-
cell_vectors = configuration.material.
|
|
68
|
+
cell_vectors = configuration.material.lattice.vectors
|
|
69
69
|
return [configuration.perturbation_function_holder.transform_coordinates(coord) for coord in cell_vectors]
|
|
70
70
|
|
|
71
71
|
def create_perturbed_slab(self, configuration: PerturbationConfiguration) -> Material:
|
|
@@ -74,10 +74,4 @@ class CellMatchingDistancePreservingSlabPerturbationBuilder(DistancePreservingSl
|
|
|
74
74
|
new_lattice = new_material.lattice.copy()
|
|
75
75
|
new_lattice = new_lattice.from_vectors_array(new_lattice_vectors)
|
|
76
76
|
new_material.lattice = new_lattice
|
|
77
|
-
|
|
78
|
-
new_basis = new_material.basis.copy()
|
|
79
|
-
new_basis.to_cartesian()
|
|
80
|
-
new_basis.cell = new_basis.cell.from_vectors_array(new_lattice_vectors)
|
|
81
|
-
new_basis.to_crystal()
|
|
82
|
-
new_material.basis = new_basis
|
|
83
77
|
return new_material
|
|
@@ -85,7 +85,8 @@ def from_pymatgen(structure: Union[PymatgenStructure, PymatgenInterface]) -> Dic
|
|
|
85
85
|
{"id": i, "value": __round__(list(site.frac_coords))} for i, site in enumerate(structure.sites)
|
|
86
86
|
],
|
|
87
87
|
"units": "crystal",
|
|
88
|
-
|
|
88
|
+
# `cell` is assigned by the `lattice` object during Material initialization
|
|
89
|
+
# "cell": __round__(structure.lattice.matrix.tolist()),
|
|
89
90
|
"constraints": [],
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import copy
|
|
2
|
+
from functools import reduce
|
|
2
3
|
from typing import Any, Dict
|
|
3
4
|
|
|
4
5
|
from ase.build import bulk
|
|
@@ -56,7 +57,6 @@ INTERFACE_PROPERTIES_JSON = {
|
|
|
56
57
|
"mean_abs_strain": 0.00105,
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
60
|
# Add properties to interface structure
|
|
61
61
|
INTERFACE_STRUCTURE.interface_properties = INTERFACE_PROPERTIES_MOCK
|
|
62
62
|
INTERFACE_NAME = "Cu4(001)-Si8(001), Interface, Strain 0.062pct"
|
|
@@ -86,7 +86,6 @@ SI_CONVENTIONAL_CELL: Dict[str, Any] = {
|
|
|
86
86
|
{"id": 7, "value": [0.75, 0.75, 0.75]},
|
|
87
87
|
],
|
|
88
88
|
"units": "crystal",
|
|
89
|
-
"cell": [[5.468763846, 0.0, 0.0], [-0.0, 5.468763846, 0.0], [0.0, 0.0, 5.468763846]],
|
|
90
89
|
"constraints": [],
|
|
91
90
|
"labels": [],
|
|
92
91
|
},
|
|
@@ -137,7 +136,6 @@ SI_SUPERCELL_2X2X1: Dict[str, Any] = {
|
|
|
137
136
|
{"id": 7, "value": [0.625, 0.625, 0.25]},
|
|
138
137
|
],
|
|
139
138
|
"units": "crystal",
|
|
140
|
-
"cell": [[6.697840473, 0.0, 3.867], [2.232613491, 6.314784557, 3.867], [0.0, 0.0, 3.867]],
|
|
141
139
|
"constraints": [],
|
|
142
140
|
"labels": [],
|
|
143
141
|
},
|
|
@@ -176,7 +174,6 @@ SI_SLAB_CONFIGURATION: Dict[str, Any] = {
|
|
|
176
174
|
"make_primitive": True,
|
|
177
175
|
}
|
|
178
176
|
|
|
179
|
-
|
|
180
177
|
SI_SLAB_100: Dict[str, Any] = {
|
|
181
178
|
"name": "Si8(001), termination Si_P4/mmm_1, Slab",
|
|
182
179
|
"basis": {
|
|
@@ -201,7 +198,6 @@ SI_SLAB_100: Dict[str, Any] = {
|
|
|
201
198
|
{"id": 7, "value": [0.0, 0.5, 0.643382864]},
|
|
202
199
|
],
|
|
203
200
|
"units": "crystal",
|
|
204
|
-
"cell": [[3.867, 0.0, 0.0], [-0.0, 3.867, 0.0], [0.0, 0.0, 15.937527692]],
|
|
205
201
|
"constraints": [],
|
|
206
202
|
"labels": [],
|
|
207
203
|
},
|
|
@@ -254,7 +250,6 @@ SI_SLAB_100: Dict[str, Any] = {
|
|
|
254
250
|
{"id": 7, "value": [0.75, 0.75, 0.75]},
|
|
255
251
|
],
|
|
256
252
|
"units": "crystal",
|
|
257
|
-
"cell": [[5.468763846, 0.0, 0.0], [-0.0, 5.468763846, 0.0], [0.0, 0.0, 5.468763846]],
|
|
258
253
|
"constraints": [],
|
|
259
254
|
"labels": [],
|
|
260
255
|
},
|
|
@@ -293,7 +288,6 @@ SI_SLAB_100: Dict[str, Any] = {
|
|
|
293
288
|
"isUpdated": True,
|
|
294
289
|
}
|
|
295
290
|
|
|
296
|
-
|
|
297
291
|
SI_SLAB: Dict[str, Any] = {
|
|
298
292
|
"name": "Si8(001), termination Si_P4/mmm_1, Slab",
|
|
299
293
|
"basis": {
|
|
@@ -303,7 +297,6 @@ SI_SLAB: Dict[str, Any] = {
|
|
|
303
297
|
{"id": 1, "value": [0.25, 0.5, 0.145147133]},
|
|
304
298
|
],
|
|
305
299
|
"units": "crystal",
|
|
306
|
-
"cell": [[3.867, 0.0, 0.0], [1.9335, 3.348920236, 0.0], [0.0, 0.0, 8.157392279]],
|
|
307
300
|
"constraints": [],
|
|
308
301
|
"labels": [],
|
|
309
302
|
},
|
|
@@ -333,7 +326,6 @@ SI_SLAB: Dict[str, Any] = {
|
|
|
333
326
|
"isUpdated": True,
|
|
334
327
|
}
|
|
335
328
|
|
|
336
|
-
|
|
337
329
|
SI_SLAB_PASSIVATED = {
|
|
338
330
|
"name": "Si8(001), termination Si_P4/mmm_1, Slab H-passivated",
|
|
339
331
|
"basis": {
|
|
@@ -350,7 +342,6 @@ SI_SLAB_PASSIVATED = {
|
|
|
350
342
|
{"id": 3, "value": [0.583333333, 0.833333333, 0.729812904]},
|
|
351
343
|
],
|
|
352
344
|
"units": "crystal",
|
|
353
|
-
"cell": [[3.867, 0.0, 0.0], [1.9335, 3.34892, 0.0], [0.0, 0.0, 8.157392]],
|
|
354
345
|
"labels": [],
|
|
355
346
|
},
|
|
356
347
|
"lattice": {
|
|
@@ -377,7 +368,8 @@ SI_SLAB_PASSIVATED = {
|
|
|
377
368
|
"build": {
|
|
378
369
|
"configuration": {
|
|
379
370
|
"type": "PassivationConfiguration",
|
|
380
|
-
"
|
|
371
|
+
# TODO: `basis` retains "cell" leading to a mismatch in the test
|
|
372
|
+
"slab": reduce(lambda d, key: d.get(key, {}), ["basis"], SI_SLAB).pop("cell", None),
|
|
381
373
|
"passivant": "H",
|
|
382
374
|
"bond_length": 1.48,
|
|
383
375
|
"surface": "both",
|
|
@@ -388,17 +380,15 @@ SI_SLAB_PASSIVATED = {
|
|
|
388
380
|
"isUpdated": True,
|
|
389
381
|
}
|
|
390
382
|
|
|
391
|
-
|
|
392
383
|
SI_SLAB_VACUUM = copy.deepcopy(SI_SLAB)
|
|
393
384
|
SI_SLAB_VACUUM["basis"]["coordinates"] = [
|
|
394
385
|
{"id": 0, "value": [0.583333333, 0.833333333, 0.149981861]},
|
|
395
386
|
{"id": 1, "value": [0.25, 0.5, 0.089989116]},
|
|
396
387
|
]
|
|
397
|
-
SI_SLAB_VACUUM["basis"]["cell"] = [[3.867, 0.0, 0.0], [1.9335, 3.348920236, 0.0], [0.0, 0.0, 13.157392279]]
|
|
388
|
+
# SI_SLAB_VACUUM["basis"]["cell"] = [[3.867, 0.0, 0.0], [1.9335, 3.348920236, 0.0], [0.0, 0.0, 13.157392279]]
|
|
398
389
|
SI_SLAB_VACUUM["lattice"]["c"] = 13.157392279
|
|
399
390
|
SI_SLAB_VACUUM["lattice"]["vectors"]["c"] = [0.0, 0.0, 13.157392279]
|
|
400
391
|
|
|
401
|
-
|
|
402
392
|
clean_material = Material.create(Material.default_config)
|
|
403
393
|
slab_111_config = SlabConfiguration(
|
|
404
394
|
bulk=clean_material,
|
|
@@ -428,7 +418,6 @@ GRAPHENE = {
|
|
|
428
418
|
"elements": [{"id": 0, "value": "C"}, {"id": 1, "value": "C"}],
|
|
429
419
|
"coordinates": [{"id": 0, "value": [0, 0, 0]}, {"id": 1, "value": [0.333333, 0.666667, 0]}],
|
|
430
420
|
"units": "crystal",
|
|
431
|
-
"cell": [[2.467291, 0, 0], [-1.2336454999, 2.1367366845, 0], [0, 0, 20]],
|
|
432
421
|
"constraints": [],
|
|
433
422
|
},
|
|
434
423
|
"lattice": {
|
|
@@ -451,7 +440,7 @@ GRAPHENE = {
|
|
|
451
440
|
"isNonPeriodic": False,
|
|
452
441
|
}
|
|
453
442
|
|
|
454
|
-
GRAPHENE_ZIGZAG_NANORIBBON = {
|
|
443
|
+
GRAPHENE_ZIGZAG_NANORIBBON: Dict[str, Any] = {
|
|
455
444
|
"name": "Graphene (Zigzag nanoribbon)",
|
|
456
445
|
"basis": {
|
|
457
446
|
"elements": [
|
|
@@ -491,7 +480,6 @@ GRAPHENE_ZIGZAG_NANORIBBON = {
|
|
|
491
480
|
{"id": 15, "value": [0.812500063, 0.6333333, 0.5]},
|
|
492
481
|
],
|
|
493
482
|
"units": "crystal",
|
|
494
|
-
"cell": [[9.869164, 0.0, 0.0], [-0.0, 10.683683422, 0.0], [0.0, 0.0, 20.0]],
|
|
495
483
|
"constraints": [],
|
|
496
484
|
"labels": [],
|
|
497
485
|
},
|
|
@@ -552,25 +540,24 @@ GRAPHENE_ARMCHAIR_NANORIBBON = {
|
|
|
552
540
|
{"id": 15, "value": "C"},
|
|
553
541
|
],
|
|
554
542
|
"coordinates": [
|
|
555
|
-
{"id": 0, "value": [0.
|
|
556
|
-
{"id": 1, "value": [0.
|
|
557
|
-
{"id": 2, "value": [0.
|
|
558
|
-
{"id": 3, "value": [0.
|
|
559
|
-
{"id": 4, "value": [0.
|
|
560
|
-
{"id": 5, "value": [0.
|
|
561
|
-
{"id": 6, "value": [0.
|
|
562
|
-
{"id": 7, "value": [0.
|
|
563
|
-
{"id": 8, "value": [0.
|
|
564
|
-
{"id": 9, "value": [0.
|
|
565
|
-
{"id": 10, "value": [0.
|
|
566
|
-
{"id": 11, "value": [0.
|
|
567
|
-
{"id": 12, "value": [0.
|
|
568
|
-
{"id": 13, "value": [0.
|
|
569
|
-
{"id": 14, "value": [0.
|
|
570
|
-
{"id": 15, "value": [0.
|
|
543
|
+
{"id": 0, "value": [0.958333362, 0.35000006, 0.5]},
|
|
544
|
+
{"id": 1, "value": [0.791666617, 0.34999996, 0.5]},
|
|
545
|
+
{"id": 2, "value": [0.958333362, 0.550000054, 0.5]},
|
|
546
|
+
{"id": 3, "value": [0.791666617, 0.549999954, 0.5]},
|
|
547
|
+
{"id": 4, "value": [0.708333369, 0.450000057, 0.5]},
|
|
548
|
+
{"id": 5, "value": [0.541666624, 0.449999957, 0.5]},
|
|
549
|
+
{"id": 6, "value": [0.458333376, 0.35000006, 0.5]},
|
|
550
|
+
{"id": 7, "value": [0.291666631, 0.34999996, 0.5]},
|
|
551
|
+
{"id": 8, "value": [0.708333369, 0.650000051, 0.5]},
|
|
552
|
+
{"id": 9, "value": [0.541666624, 0.649999951, 0.5]},
|
|
553
|
+
{"id": 10, "value": [0.458333376, 0.550000054, 0.5]},
|
|
554
|
+
{"id": 11, "value": [0.291666631, 0.549999954, 0.5]},
|
|
555
|
+
{"id": 12, "value": [0.208333383, 0.450000057, 0.5]},
|
|
556
|
+
{"id": 13, "value": [0.041666638, 0.449999957, 0.5]},
|
|
557
|
+
{"id": 14, "value": [0.208333383, 0.650000051, 0.5]},
|
|
558
|
+
{"id": 15, "value": [0.041666638, 0.649999951, 0.5]},
|
|
571
559
|
],
|
|
572
560
|
"units": "crystal",
|
|
573
|
-
"cell": [[8.546946738, 0.0, 0.0], [-0.0, 12.336455, 0.0], [0.0, 0.0, 20.0]],
|
|
574
561
|
"constraints": [],
|
|
575
562
|
"labels": [],
|
|
576
563
|
},
|
|
@@ -665,7 +652,6 @@ GRAPHENE_ZIGZAG_NANORIBBON_PASSIVATED = {
|
|
|
665
652
|
{"id": 23, "value": [0.812499933, 0.771862307, 0.5]},
|
|
666
653
|
],
|
|
667
654
|
"units": "crystal",
|
|
668
|
-
"cell": [[9.869164, 0.0, 0.0], [-0.0, 10.683683, 0.0], [0.0, 0.0, 20.0]],
|
|
669
655
|
"labels": [],
|
|
670
656
|
},
|
|
671
657
|
"lattice": {
|
|
@@ -692,7 +678,8 @@ GRAPHENE_ZIGZAG_NANORIBBON_PASSIVATED = {
|
|
|
692
678
|
"build": {
|
|
693
679
|
"configuration": {
|
|
694
680
|
"type": "PassivationConfiguration",
|
|
695
|
-
"
|
|
681
|
+
# TODO: `basis` retains "cell" leading to a mismatch in the test (as above)
|
|
682
|
+
"slab": reduce(lambda d, key: d.get(key, {}), ["basis"], GRAPHENE_ZIGZAG_NANORIBBON).pop("cell", None),
|
|
696
683
|
"passivant": "H",
|
|
697
684
|
"bond_length": 1.48,
|
|
698
685
|
"surface": "both",
|
|
@@ -702,7 +689,6 @@ GRAPHENE_ZIGZAG_NANORIBBON_PASSIVATED = {
|
|
|
702
689
|
"isUpdated": True,
|
|
703
690
|
}
|
|
704
691
|
|
|
705
|
-
|
|
706
692
|
GRAPHENE_NICKEL_INTERFACE = {
|
|
707
693
|
"name": "C2(001)-Ni4(111), Interface, Strain 0.105pct",
|
|
708
694
|
"basis": {
|
|
@@ -721,7 +707,6 @@ GRAPHENE_NICKEL_INTERFACE = {
|
|
|
721
707
|
{"id": 4, "value": [0.666666667, 0.666666667, 0.611447347]},
|
|
722
708
|
],
|
|
723
709
|
"units": "crystal",
|
|
724
|
-
"cell": [[2.478974, 0.0, 0.0], [1.239487, 2.14685446, 0.0], [0.0, 0.0, 27.048147591]],
|
|
725
710
|
"constraints": [],
|
|
726
711
|
"labels": [
|
|
727
712
|
{"id": 0, "value": 0},
|
|
@@ -799,7 +784,6 @@ GRAPHENE_NICKEL_INTERFACE = {
|
|
|
799
784
|
{"id": 3, "value": [0.5, 0.5, 0.0]},
|
|
800
785
|
],
|
|
801
786
|
"units": "crystal",
|
|
802
|
-
"cell": [[3.505798652, 0.0, 0.0], [-0.0, 3.505798652, 0.0], [0.0, 0.0, 3.505798652]],
|
|
803
787
|
"constraints": [],
|
|
804
788
|
"labels": [],
|
|
805
789
|
},
|
|
@@ -10,27 +10,19 @@ def test_create():
|
|
|
10
10
|
material = Material.create(Material.default_config)
|
|
11
11
|
assert isinstance(material.basis, Basis)
|
|
12
12
|
assert isinstance(material.lattice, Lattice)
|
|
13
|
-
assert material.to_json() == Material.default_config
|
|
14
13
|
assert material.name == Material.default_config["name"]
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
def test_material_to_json():
|
|
18
17
|
material = Material.create(Material.default_config)
|
|
19
|
-
|
|
20
|
-
config_with_labels = {
|
|
21
|
-
**Material.default_config,
|
|
22
|
-
"basis": {**Material.default_config["basis"], "labels": labels_array},
|
|
23
|
-
}
|
|
24
|
-
expected_config = {
|
|
25
|
-
**Material.default_config,
|
|
26
|
-
"basis": {**Material.default_config["basis"], "cell": None, "labels": labels_array},
|
|
27
|
-
}
|
|
28
|
-
material.basis = Basis.from_dict(**config_with_labels["basis"])
|
|
29
|
-
assertion_utils.assert_deep_almost_equal(expected_config, material.to_json())
|
|
18
|
+
assertion_utils.assert_deep_almost_equal(Material.default_config, material.to_json())
|
|
30
19
|
|
|
31
20
|
|
|
32
21
|
def test_basis_to_json():
|
|
33
22
|
material = Material.create(Material.default_config)
|
|
34
23
|
basis = material.basis
|
|
35
|
-
expected_basis_config = {**Material.default_config["basis"], "
|
|
24
|
+
expected_basis_config = {**Material.default_config["basis"], "labels": []}
|
|
36
25
|
assertion_utils.assert_deep_almost_equal(expected_basis_config, basis.to_json())
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# TODO: Add test to check if basis.cell is changed when lattice of material is changed, and vice versa
|
|
@@ -114,10 +114,17 @@ def test_create_adatom_equidistant():
|
|
|
114
114
|
defect = create_slab_defect(configuration=configuration, builder=EquidistantAdatomSlabDefectBuilder())
|
|
115
115
|
|
|
116
116
|
assert defect.basis.elements.values[-1] == "Si"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
assert (len(configuration.crystal.basis.coordinates.values) + 1) == len(defect.basis.coordinates.values)
|
|
118
|
+
defect.to_cartesian()
|
|
119
|
+
# TODO: resolve the problem with the test in GH pipeline
|
|
120
|
+
# on MacOS slab atoms have different coordinates than in GH and pyodide
|
|
121
|
+
# for the same versions of packages
|
|
122
|
+
coordinate_macosx = [6.477224996, 3.739627331, 14.234895469]
|
|
123
|
+
coordinate_linux_and_emscripten = [5.123775004, 3.739627331, 14.234895469]
|
|
124
|
+
defect_coordinate = defect.basis.coordinates.values[-1]
|
|
125
|
+
is_passing_on_macosx = coordinate_macosx == defect_coordinate
|
|
126
|
+
is_passing_on_linux_and_emscripten = coordinate_linux_and_emscripten == defect_coordinate
|
|
127
|
+
assert is_passing_on_macosx or is_passing_on_linux_and_emscripten
|
|
121
128
|
|
|
122
129
|
|
|
123
130
|
@pytest.mark.skip(reason="This test is failing due to the difference in slab generation between GHA and local")
|
|
@@ -62,9 +62,9 @@ def test_create_twisted_nanoribbon_interface():
|
|
|
62
62
|
builder = NanoRibbonTwistedInterfaceBuilder()
|
|
63
63
|
interface = builder.get_material(configuration)
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
expected_cell_vectors = [[15.102811, 0.0, 0.0], [0.0, 16.108175208, 0.0], [0.0, 0.0, 20.0]]
|
|
66
66
|
expected_coordinate = [0.704207885, 0.522108183, 0.65]
|
|
67
|
-
assertion_utils.assert_deep_almost_equal(
|
|
67
|
+
assertion_utils.assert_deep_almost_equal(expected_cell_vectors, interface.lattice.vectors)
|
|
68
68
|
assertion_utils.assert_deep_almost_equal(expected_coordinate, interface.basis.coordinates.values[42])
|
|
69
69
|
|
|
70
70
|
|
|
@@ -79,7 +79,7 @@ def test_create_commensurate_supercell_twisted_interface():
|
|
|
79
79
|
interfaces = builder.get_materials(config, post_process_parameters=config)
|
|
80
80
|
assert len(interfaces) == 1
|
|
81
81
|
interface = interfaces[0]
|
|
82
|
-
expected_cell_vectors = [[
|
|
82
|
+
expected_cell_vectors = [[10.754672133, 0.0, 0.0], [5.377336066500001, 9.313819276550575, 0.0], [0.0, 0.0, 20.0]]
|
|
83
83
|
assertion_utils.assert_deep_almost_equal(expected_cell_vectors, interface.basis.cell.vectors_as_array)
|
|
84
84
|
expected_angle = 13.174
|
|
85
85
|
assert interface.metadata["build"]["configuration"]["actual_twist_angle"] == expected_angle
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from mat3ra.made.cell import Cell
|
|
2
1
|
from mat3ra.made.material import Material
|
|
3
2
|
from mat3ra.made.tools.build.perturbation import create_perturbation
|
|
4
3
|
from mat3ra.made.tools.build.perturbation.builders import SlabPerturbationBuilder
|
|
@@ -39,12 +38,12 @@ def test_distance_preserved_sine_perturbation():
|
|
|
39
38
|
# Check selected atoms to avoid using 100+ atoms fixture
|
|
40
39
|
assertion_utils.assert_deep_almost_equal([0.0, 0.0, 0.5], perturbed_slab.basis.coordinates.values[0])
|
|
41
40
|
assertion_utils.assert_deep_almost_equal(
|
|
42
|
-
[0.
|
|
41
|
+
[0.194051947, 0.1, 0.546942315], perturbed_slab.basis.coordinates.values[42]
|
|
43
42
|
)
|
|
44
43
|
# Value taken from visually inspected notebook
|
|
45
|
-
expected_cell =
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
assertion_utils.assert_deep_almost_equal(expected_cell
|
|
44
|
+
expected_cell = [
|
|
45
|
+
[24.087442, 0.0, 0.0],
|
|
46
|
+
[-12.043583, 21.367367, 0.0],
|
|
47
|
+
[0.0, 0.0, 20.0],
|
|
48
|
+
]
|
|
49
|
+
assertion_utils.assert_deep_almost_equal(expected_cell, perturbed_slab.lattice.vectors)
|