@mat3ra/made 2024.8.16-0 → 2024.8.20-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/material.py +13 -0
- package/src/py/mat3ra/made/tools/build/__init__.py +18 -0
- package/src/py/mat3ra/made/tools/build/interface/termination_pair.py +6 -2
- package/src/py/mat3ra/made/tools/build/nanoribbon/__init__.py +9 -0
- package/src/py/mat3ra/made/tools/build/nanoribbon/builders.py +149 -0
- package/src/py/mat3ra/made/tools/build/nanoribbon/configuration.py +37 -0
- package/src/py/mat3ra/made/tools/build/nanoribbon/enums.py +10 -0
- package/src/py/mat3ra/made/tools/modify.py +25 -0
- package/tests/py/unit/fixtures.py +158 -0
- package/tests/py/unit/test_tools_build_nanoribbon.py +32 -0
package/package.json
CHANGED
|
@@ -95,3 +95,16 @@ class Material(HasDescriptionHasMetadataNamedDefaultableInMemoryEntity):
|
|
|
95
95
|
new_basis = self.basis.copy()
|
|
96
96
|
new_basis.coordinates.values = coordinates
|
|
97
97
|
self.basis = new_basis
|
|
98
|
+
|
|
99
|
+
def set_new_lattice_vectors(
|
|
100
|
+
self, lattice_vector1: List[float], lattice_vector2: List[float], lattice_vector3: List[float]
|
|
101
|
+
) -> 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
|
+
lattice = Lattice.from_vectors_array([lattice_vector1, lattice_vector2, lattice_vector3])
|
|
110
|
+
self.lattice = lattice
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
from typing import List, Optional, Any
|
|
2
2
|
|
|
3
|
+
from mat3ra.code.entity import InMemoryEntity
|
|
3
4
|
from pydantic import BaseModel
|
|
4
5
|
|
|
5
6
|
from ...material import Material
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
class BaseConfiguration(BaseModel, InMemoryEntity):
|
|
10
|
+
"""
|
|
11
|
+
Base class for material build configurations.
|
|
12
|
+
This class provides an interface for defining the configuration parameters.
|
|
13
|
+
|
|
14
|
+
The class is designed to be subclassed and the subclass should define the following attributes:
|
|
15
|
+
- `_json`: The JSON representation of the configuration.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
class Config:
|
|
19
|
+
arbitrary_types_allowed = True
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def _json(self):
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
|
|
8
26
|
class BaseBuilder(BaseModel):
|
|
9
27
|
"""
|
|
10
28
|
Base class for material builders.
|
|
@@ -40,7 +40,8 @@ def safely_select_termination_pair(
|
|
|
40
40
|
) -> TerminationPair:
|
|
41
41
|
"""
|
|
42
42
|
Attempt finding provided in generated terminations to find a complete match,
|
|
43
|
-
if match isn't found, get terminations with equivalent chemical elements
|
|
43
|
+
if match isn't found, get terminations with equivalent chemical elements,
|
|
44
|
+
if that fails, return the first generated termination pair.
|
|
44
45
|
"""
|
|
45
46
|
provided_film_termination = provided_termination_pair.film_termination
|
|
46
47
|
provided_substrate_termination = provided_termination_pair.substrate_termination
|
|
@@ -55,5 +56,8 @@ def safely_select_termination_pair(
|
|
|
55
56
|
== provided_substrate_termination.chemical_elements
|
|
56
57
|
):
|
|
57
58
|
hotfix_termination_pair = termination_pair
|
|
58
|
-
|
|
59
|
+
else:
|
|
60
|
+
hotfix_termination_pair = generated_termination_pairs[0]
|
|
61
|
+
print("Interface will be built with terminations: ", hotfix_termination_pair)
|
|
62
|
+
|
|
59
63
|
return hotfix_termination_pair
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from mat3ra.made.material import Material
|
|
2
|
+
|
|
3
|
+
from .builders import NanoribbonBuilder
|
|
4
|
+
from .configuration import NanoribbonConfiguration
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_nanoribbon(configuration: NanoribbonConfiguration) -> Material:
|
|
8
|
+
builder = NanoribbonBuilder()
|
|
9
|
+
return builder.get_material(configuration)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
from typing import List, Optional, Any, Tuple
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from mat3ra.made.material import Material
|
|
6
|
+
from mat3ra.made.tools.build import BaseBuilder
|
|
7
|
+
from mat3ra.made.tools.build.supercell import create_supercell
|
|
8
|
+
from mat3ra.made.tools.modify import filter_by_rectangle_projection, wrap_to_unit_cell
|
|
9
|
+
|
|
10
|
+
from ...modify import translate_to_center
|
|
11
|
+
from .configuration import NanoribbonConfiguration
|
|
12
|
+
from .enums import EdgeTypes
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NanoribbonBuilder(BaseBuilder):
|
|
16
|
+
"""
|
|
17
|
+
Builder class for creating a nanoribbon from a material.
|
|
18
|
+
|
|
19
|
+
The process creates a supercell with large enough dimensions to contain the nanoribbon and then
|
|
20
|
+
filters the supercell to only include the nanoribbon. The supercell is then centered and returned as the nanoribbon.
|
|
21
|
+
The nanoribbon can have either Armchair or Zigzag edge. The edge is defined along the vector 1 of the material cell,
|
|
22
|
+
which corresponds to [1,0,0] direction.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
_ConfigurationType: type(NanoribbonConfiguration) = NanoribbonConfiguration # type: ignore
|
|
26
|
+
_GeneratedItemType: Material = Material
|
|
27
|
+
_PostProcessParametersType: Any = None
|
|
28
|
+
|
|
29
|
+
def create_nanoribbon(self, config: NanoribbonConfiguration) -> Material:
|
|
30
|
+
material = config.material
|
|
31
|
+
(
|
|
32
|
+
length_cartesian,
|
|
33
|
+
width_cartesian,
|
|
34
|
+
height_cartesian,
|
|
35
|
+
vacuum_length_cartesian,
|
|
36
|
+
vacuum_width_cartesian,
|
|
37
|
+
) = self._calculate_cartesian_dimensions(config, material)
|
|
38
|
+
length_lattice_vector, width_lattice_vector, height_lattice_vector = self._get_new_lattice_vectors(
|
|
39
|
+
length_cartesian,
|
|
40
|
+
width_cartesian,
|
|
41
|
+
height_cartesian,
|
|
42
|
+
vacuum_length_cartesian,
|
|
43
|
+
vacuum_width_cartesian,
|
|
44
|
+
config.edge_type,
|
|
45
|
+
)
|
|
46
|
+
n = max(config.length, config.width)
|
|
47
|
+
large_supercell_to_cut = create_supercell(material, np.diag([2 * n, 2 * n, 1]))
|
|
48
|
+
|
|
49
|
+
min_coordinate, max_coordinate = self._calculate_coordinates_of_cut(
|
|
50
|
+
length_cartesian, width_cartesian, height_cartesian, config.edge_type
|
|
51
|
+
)
|
|
52
|
+
nanoribbon = filter_by_rectangle_projection(
|
|
53
|
+
large_supercell_to_cut,
|
|
54
|
+
min_coordinate=min_coordinate,
|
|
55
|
+
max_coordinate=max_coordinate,
|
|
56
|
+
use_cartesian_coordinates=True,
|
|
57
|
+
)
|
|
58
|
+
nanoribbon.set_new_lattice_vectors(length_lattice_vector, width_lattice_vector, height_lattice_vector)
|
|
59
|
+
return translate_to_center(nanoribbon)
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _calculate_cartesian_dimensions(config: NanoribbonConfiguration, material: Material):
|
|
63
|
+
"""
|
|
64
|
+
Calculate the dimensions of the nanoribbon in the cartesian coordinate system.
|
|
65
|
+
"""
|
|
66
|
+
nanoribbon_width = config.width
|
|
67
|
+
nanoribbon_length = config.length
|
|
68
|
+
vacuum_width = config.vacuum_width
|
|
69
|
+
vacuum_length = config.vacuum_length
|
|
70
|
+
edge_type = config.edge_type
|
|
71
|
+
|
|
72
|
+
if edge_type == EdgeTypes.armchair:
|
|
73
|
+
nanoribbon_length, nanoribbon_width = nanoribbon_width, nanoribbon_length
|
|
74
|
+
vacuum_width, vacuum_length = vacuum_length, vacuum_width
|
|
75
|
+
|
|
76
|
+
length_cartesian = nanoribbon_length * np.dot(np.array(material.basis.cell.vector1), np.array([1, 0, 0]))
|
|
77
|
+
width_cartesian = nanoribbon_width * np.dot(np.array(material.basis.cell.vector2), np.array([0, 1, 0]))
|
|
78
|
+
height_cartesian = np.dot(np.array(material.basis.cell.vector3), np.array([0, 0, 1]))
|
|
79
|
+
vacuum_length_cartesian = vacuum_length * np.dot(np.array(material.basis.cell.vector1), np.array([1, 0, 0]))
|
|
80
|
+
vacuum_width_cartesian = vacuum_width * np.dot(np.array(material.basis.cell.vector2), np.array([0, 1, 0]))
|
|
81
|
+
|
|
82
|
+
return length_cartesian, width_cartesian, height_cartesian, vacuum_length_cartesian, vacuum_width_cartesian
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def _get_new_lattice_vectors(
|
|
86
|
+
length: float, width: float, height: float, vacuum_length: float, vacuum_width: float, edge_type: EdgeTypes
|
|
87
|
+
) -> Tuple[List[float], List[float], List[float]]:
|
|
88
|
+
"""
|
|
89
|
+
Calculate the new lattice vectors for the nanoribbon.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
length: Length of the nanoribbon.
|
|
93
|
+
width: Width of the nanoribbon.
|
|
94
|
+
height: Height of the nanoribbon.
|
|
95
|
+
vacuum_length: Length of the vacuum region.
|
|
96
|
+
vacuum_width: Width of the vacuum region.
|
|
97
|
+
edge_type: Type of the edge of the nanoribbon.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Tuple of the new lattice vectors.
|
|
101
|
+
"""
|
|
102
|
+
length_lattice_vector = [length + vacuum_length, 0, 0]
|
|
103
|
+
width_lattice_vector = [0, width + vacuum_width, 0]
|
|
104
|
+
height_lattice_vector = [0, 0, height]
|
|
105
|
+
|
|
106
|
+
if edge_type == EdgeTypes.armchair:
|
|
107
|
+
length_lattice_vector, width_lattice_vector = width_lattice_vector, length_lattice_vector
|
|
108
|
+
|
|
109
|
+
return length_lattice_vector, width_lattice_vector, height_lattice_vector
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _calculate_coordinates_of_cut(
|
|
113
|
+
length: float, width: float, height: float, edge_type: EdgeTypes
|
|
114
|
+
) -> Tuple[List[float], List[float]]:
|
|
115
|
+
"""
|
|
116
|
+
Calculate the coordinates of the rectangular nanoribbon cut from the supercell.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
length: Length of the nanoribbon.
|
|
120
|
+
width: Width of the nanoribbon.
|
|
121
|
+
height: Height of the nanoribbon.
|
|
122
|
+
edge_type: Type of the edge of the nanoribbon.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Tuple of the minimum and maximum coordinates of the cut.
|
|
126
|
+
"""
|
|
127
|
+
edge_nudge_value = 0.01
|
|
128
|
+
conditional_nudge_value = edge_nudge_value * (
|
|
129
|
+
-1 * (edge_type == EdgeTypes.armchair) + 1 * (edge_type == EdgeTypes.zigzag)
|
|
130
|
+
)
|
|
131
|
+
min_coordinate = [-edge_nudge_value, conditional_nudge_value, 0]
|
|
132
|
+
max_coordinate = [length - edge_nudge_value, width + conditional_nudge_value, height]
|
|
133
|
+
return min_coordinate, max_coordinate
|
|
134
|
+
|
|
135
|
+
def _generate(self, configuration: NanoribbonConfiguration) -> List[_GeneratedItemType]:
|
|
136
|
+
nanoribbon = self.create_nanoribbon(configuration)
|
|
137
|
+
return [nanoribbon]
|
|
138
|
+
|
|
139
|
+
def _post_process(
|
|
140
|
+
self,
|
|
141
|
+
items: List[_GeneratedItemType],
|
|
142
|
+
post_process_parameters: Optional[_PostProcessParametersType],
|
|
143
|
+
) -> List[Material]:
|
|
144
|
+
return [wrap_to_unit_cell(item) for item in items]
|
|
145
|
+
|
|
146
|
+
def _update_material_name(self, material: Material, configuration: NanoribbonConfiguration) -> Material:
|
|
147
|
+
edge_type = configuration.edge_type.capitalize()
|
|
148
|
+
material.name = f"{material.name} ({edge_type} nanoribbon)"
|
|
149
|
+
return material
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from mat3ra.made.material import Material
|
|
2
|
+
from mat3ra.made.tools.build.nanoribbon.enums import EdgeTypes
|
|
3
|
+
|
|
4
|
+
from ...build import BaseConfiguration
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class NanoribbonConfiguration(BaseConfiguration):
|
|
8
|
+
"""
|
|
9
|
+
Configuration for building a nanoribbon from a material.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
material (Material): The material to build the nanoribbon from.
|
|
14
|
+
width (int): The width of the nanoribbon in number of unit cells.
|
|
15
|
+
length (int): The length of the nanoribbon in number of unit cells.
|
|
16
|
+
vacuum_width (int): The width of the vacuum region in number of unit cells.
|
|
17
|
+
vacuum_length (int): The length of the vacuum region in number of unit cells.
|
|
18
|
+
edge_type (EdgeTypes): The type of edge to use for the nanoribbon, either zigzag or armchair.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
material: Material
|
|
22
|
+
width: int # in number of unit cells
|
|
23
|
+
length: int # in number of unit cells
|
|
24
|
+
vacuum_width: int = 3 # in number of unit cells
|
|
25
|
+
vacuum_length: int = 0 # in number of unit cells
|
|
26
|
+
edge_type: EdgeTypes = EdgeTypes.zigzag
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def _json(self):
|
|
30
|
+
return {
|
|
31
|
+
"material": self.material.to_json(),
|
|
32
|
+
"width": self.width,
|
|
33
|
+
"length": self.length,
|
|
34
|
+
"vacuum_width": self.vacuum_width,
|
|
35
|
+
"vacuum_length": self.vacuum_length,
|
|
36
|
+
"edge_type": self.edge_type,
|
|
37
|
+
}
|
|
@@ -87,6 +87,31 @@ def translate_by_vector(
|
|
|
87
87
|
return Material(from_ase(atoms))
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def translate_to_center(material: Material, axes: Optional[List[str]] = None) -> Material:
|
|
91
|
+
"""
|
|
92
|
+
Center the material in the unit cell.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
material (Material): The material object to center.
|
|
96
|
+
axes (List[str]): The axes to center the material along.
|
|
97
|
+
Returns:
|
|
98
|
+
Material: The centered material object.
|
|
99
|
+
"""
|
|
100
|
+
new_material = material.clone()
|
|
101
|
+
new_material.to_crystal()
|
|
102
|
+
if axes is None:
|
|
103
|
+
axes = ["x", "y", "z"]
|
|
104
|
+
min_x = get_atomic_coordinates_extremum(material, axis="x", extremum="min") if "x" in axes else 0
|
|
105
|
+
max_x = get_atomic_coordinates_extremum(material, axis="x", extremum="max") if "x" in axes else 1
|
|
106
|
+
min_y = get_atomic_coordinates_extremum(material, axis="y", extremum="min") if "y" in axes else 0
|
|
107
|
+
max_y = get_atomic_coordinates_extremum(material, axis="y", extremum="max") if "y" in axes else 1
|
|
108
|
+
if "z" in axes:
|
|
109
|
+
material = translate_to_z_level(material, z_level="center")
|
|
110
|
+
|
|
111
|
+
material = translate_by_vector(material, vector=[(1 - min_x - max_x) / 2, (1 - min_y - max_y) / 2, 0])
|
|
112
|
+
return material
|
|
113
|
+
|
|
114
|
+
|
|
90
115
|
def wrap_to_unit_cell(material: Material) -> Material:
|
|
91
116
|
"""
|
|
92
117
|
Wrap the material to the unit cell.
|
|
@@ -289,3 +289,161 @@ GRAPHENE = {
|
|
|
289
289
|
},
|
|
290
290
|
"isNonPeriodic": False,
|
|
291
291
|
}
|
|
292
|
+
|
|
293
|
+
GRAPHENE_ZIGZAG_NANORIBBON = {
|
|
294
|
+
"name": "Graphene (Zigzag nanoribbon)",
|
|
295
|
+
"basis": {
|
|
296
|
+
"elements": [
|
|
297
|
+
{"id": 0, "value": "C"},
|
|
298
|
+
{"id": 1, "value": "C"},
|
|
299
|
+
{"id": 2, "value": "C"},
|
|
300
|
+
{"id": 3, "value": "C"},
|
|
301
|
+
{"id": 4, "value": "C"},
|
|
302
|
+
{"id": 5, "value": "C"},
|
|
303
|
+
{"id": 6, "value": "C"},
|
|
304
|
+
{"id": 7, "value": "C"},
|
|
305
|
+
{"id": 8, "value": "C"},
|
|
306
|
+
{"id": 9, "value": "C"},
|
|
307
|
+
{"id": 10, "value": "C"},
|
|
308
|
+
{"id": 11, "value": "C"},
|
|
309
|
+
{"id": 12, "value": "C"},
|
|
310
|
+
{"id": 13, "value": "C"},
|
|
311
|
+
{"id": 14, "value": "C"},
|
|
312
|
+
{"id": 15, "value": "C"},
|
|
313
|
+
],
|
|
314
|
+
"coordinates": [
|
|
315
|
+
{"id": 0, "value": [0.062499937, 0.366666681, 0.5]},
|
|
316
|
+
{"id": 1, "value": [0.312499937, 0.366666681, 0.5]},
|
|
317
|
+
{"id": 2, "value": [0.187500062, 0.433333286, 0.5]},
|
|
318
|
+
{"id": 3, "value": [0.187499937, 0.566666695, 0.5]},
|
|
319
|
+
{"id": 4, "value": [0.062500062, 0.6333333, 0.5]},
|
|
320
|
+
{"id": 5, "value": [0.562499937, 0.366666681, 0.5]},
|
|
321
|
+
{"id": 6, "value": [0.437500062, 0.433333286, 0.5]},
|
|
322
|
+
{"id": 7, "value": [0.437499937, 0.566666695, 0.5]},
|
|
323
|
+
{"id": 8, "value": [0.312500062, 0.6333333, 0.5]},
|
|
324
|
+
{"id": 9, "value": [0.812499938, 0.366666681, 0.5]},
|
|
325
|
+
{"id": 10, "value": [0.687500062, 0.433333286, 0.5]},
|
|
326
|
+
{"id": 11, "value": [0.687499937, 0.566666695, 0.5]},
|
|
327
|
+
{"id": 12, "value": [0.562500062, 0.6333333, 0.5]},
|
|
328
|
+
{"id": 13, "value": [0.937500063, 0.433333286, 0.5]},
|
|
329
|
+
{"id": 14, "value": [0.937499937, 0.566666695, 0.5]},
|
|
330
|
+
{"id": 15, "value": [0.812500063, 0.6333333, 0.5]},
|
|
331
|
+
],
|
|
332
|
+
"units": "crystal",
|
|
333
|
+
"cell": [[9.869164, 0.0, 0.0], [-0.0, 10.683683422, 0.0], [0.0, 0.0, 20.0]],
|
|
334
|
+
"constraints": [],
|
|
335
|
+
"labels": [],
|
|
336
|
+
},
|
|
337
|
+
"lattice": {
|
|
338
|
+
"a": 9.869164,
|
|
339
|
+
"b": 10.683683422,
|
|
340
|
+
"c": 20.0,
|
|
341
|
+
"alpha": 90.0,
|
|
342
|
+
"beta": 90.0,
|
|
343
|
+
"gamma": 90.0,
|
|
344
|
+
"units": {"length": "angstrom", "angle": "degree"},
|
|
345
|
+
"type": "TRI",
|
|
346
|
+
"vectors": {
|
|
347
|
+
"a": [9.869164, 0.0, 0.0],
|
|
348
|
+
"b": [-0.0, 10.683683422, 0.0],
|
|
349
|
+
"c": [0.0, 0.0, 20.0],
|
|
350
|
+
"alat": 1,
|
|
351
|
+
"units": "angstrom",
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
"isNonPeriodic": False,
|
|
355
|
+
"_id": "",
|
|
356
|
+
"metadata": {
|
|
357
|
+
"boundaryConditions": {"type": "pbc", "offset": 0},
|
|
358
|
+
"build": {
|
|
359
|
+
"configuration": {
|
|
360
|
+
"material": GRAPHENE,
|
|
361
|
+
"width": 2,
|
|
362
|
+
"length": 4,
|
|
363
|
+
"vacuum_width": 3,
|
|
364
|
+
"vacuum_length": 0,
|
|
365
|
+
"edge_type": "zigzag",
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
"isUpdated": True,
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
GRAPHENE_ARMCHAIR_NANORIBBON = {
|
|
373
|
+
"name": "Graphene (Armchair nanoribbon)",
|
|
374
|
+
"basis": {
|
|
375
|
+
"elements": [
|
|
376
|
+
{"id": 0, "value": "C"},
|
|
377
|
+
{"id": 1, "value": "C"},
|
|
378
|
+
{"id": 2, "value": "C"},
|
|
379
|
+
{"id": 3, "value": "C"},
|
|
380
|
+
{"id": 4, "value": "C"},
|
|
381
|
+
{"id": 5, "value": "C"},
|
|
382
|
+
{"id": 6, "value": "C"},
|
|
383
|
+
{"id": 7, "value": "C"},
|
|
384
|
+
{"id": 8, "value": "C"},
|
|
385
|
+
{"id": 9, "value": "C"},
|
|
386
|
+
{"id": 10, "value": "C"},
|
|
387
|
+
{"id": 11, "value": "C"},
|
|
388
|
+
{"id": 12, "value": "C"},
|
|
389
|
+
{"id": 13, "value": "C"},
|
|
390
|
+
{"id": 14, "value": "C"},
|
|
391
|
+
{"id": 15, "value": "C"},
|
|
392
|
+
],
|
|
393
|
+
"coordinates": [
|
|
394
|
+
{"id": 0, "value": [0.041666626, 0.35000005, 0.5]},
|
|
395
|
+
{"id": 1, "value": [0.208333376, 0.34999995, 0.5]},
|
|
396
|
+
{"id": 2, "value": [0.041666626, 0.55000005, 0.5]},
|
|
397
|
+
{"id": 3, "value": [0.208333376, 0.54999995, 0.5]},
|
|
398
|
+
{"id": 4, "value": [0.291666626, 0.45000005, 0.5]},
|
|
399
|
+
{"id": 5, "value": [0.458333376, 0.44999995, 0.5]},
|
|
400
|
+
{"id": 6, "value": [0.541666626, 0.35000005, 0.5]},
|
|
401
|
+
{"id": 7, "value": [0.708333376, 0.34999995, 0.5]},
|
|
402
|
+
{"id": 8, "value": [0.291666626, 0.65000005, 0.5]},
|
|
403
|
+
{"id": 9, "value": [0.458333376, 0.64999995, 0.5]},
|
|
404
|
+
{"id": 10, "value": [0.541666626, 0.55000005, 0.5]},
|
|
405
|
+
{"id": 11, "value": [0.708333376, 0.54999995, 0.5]},
|
|
406
|
+
{"id": 12, "value": [0.791666626, 0.45000005, 0.5]},
|
|
407
|
+
{"id": 13, "value": [0.958333376, 0.44999995, 0.5]},
|
|
408
|
+
{"id": 14, "value": [0.791666626, 0.65000005, 0.5]},
|
|
409
|
+
{"id": 15, "value": [0.958333376, 0.64999995, 0.5]},
|
|
410
|
+
],
|
|
411
|
+
"units": "crystal",
|
|
412
|
+
"cell": [[8.546946738, 0.0, 0.0], [-0.0, 12.336455, 0.0], [0.0, 0.0, 20.0]],
|
|
413
|
+
"constraints": [],
|
|
414
|
+
"labels": [],
|
|
415
|
+
},
|
|
416
|
+
"lattice": {
|
|
417
|
+
"a": 8.546946738,
|
|
418
|
+
"b": 12.336455,
|
|
419
|
+
"c": 20.0,
|
|
420
|
+
"alpha": 90.0,
|
|
421
|
+
"beta": 90.0,
|
|
422
|
+
"gamma": 90.0,
|
|
423
|
+
"units": {"length": "angstrom", "angle": "degree"},
|
|
424
|
+
"type": "TRI",
|
|
425
|
+
"vectors": {
|
|
426
|
+
"a": [8.546946738, 0.0, 0.0],
|
|
427
|
+
"b": [-0.0, 12.336455, 0.0],
|
|
428
|
+
"c": [0.0, 0.0, 20.0],
|
|
429
|
+
"alat": 1,
|
|
430
|
+
"units": "angstrom",
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
"isNonPeriodic": False,
|
|
434
|
+
"_id": "",
|
|
435
|
+
"metadata": {
|
|
436
|
+
"boundaryConditions": {"type": "pbc", "offset": 0},
|
|
437
|
+
"build": {
|
|
438
|
+
"configuration": {
|
|
439
|
+
"material": GRAPHENE,
|
|
440
|
+
"width": 2,
|
|
441
|
+
"length": 4,
|
|
442
|
+
"vacuum_width": 3,
|
|
443
|
+
"vacuum_length": 0,
|
|
444
|
+
"edge_type": "armchair",
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
"isUpdated": True,
|
|
449
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from mat3ra.made.material import Material
|
|
2
|
+
from mat3ra.made.tools.build.nanoribbon import NanoribbonConfiguration, create_nanoribbon
|
|
3
|
+
from mat3ra.made.tools.build.nanoribbon.enums import EdgeTypes
|
|
4
|
+
from mat3ra.utils import assertion as assertion_utils
|
|
5
|
+
|
|
6
|
+
from .fixtures import GRAPHENE, GRAPHENE_ARMCHAIR_NANORIBBON, GRAPHENE_ZIGZAG_NANORIBBON
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_build_zigzag_nanoribbon():
|
|
10
|
+
config = NanoribbonConfiguration(
|
|
11
|
+
material=Material(GRAPHENE),
|
|
12
|
+
width=2,
|
|
13
|
+
length=4,
|
|
14
|
+
vacuum_width=3,
|
|
15
|
+
edge_type=EdgeTypes.zigzag,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
nanoribbon = create_nanoribbon(config)
|
|
19
|
+
assertion_utils.assert_deep_almost_equal(GRAPHENE_ZIGZAG_NANORIBBON, nanoribbon.to_json())
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_build_armchair_nanoribbon():
|
|
23
|
+
config = NanoribbonConfiguration(
|
|
24
|
+
material=Material(GRAPHENE),
|
|
25
|
+
width=2,
|
|
26
|
+
length=4,
|
|
27
|
+
vacuum_width=3,
|
|
28
|
+
edge_type=EdgeTypes.armchair,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
nanoribbon = create_nanoribbon(config)
|
|
32
|
+
assertion_utils.assert_deep_almost_equal(GRAPHENE_ARMCHAIR_NANORIBBON, nanoribbon.to_json())
|