oILAB
Loading...
Searching...
No Matches
layers.py
Go to the documentation of this file.
1from dataclasses import dataclass
2import numpy as np
3import pyoilab as gb
4
5
6@dataclass(frozen=True)
8 label: str
9 frac_xy: np.ndarray
10 z_rel: float
11 atom_type: int
12 charge: float = 0.0
13
14 def __post_init__(self):
15 object.__setattr__(self, "frac_xy", np.asarray(self.frac_xyfrac_xy, dtype=float).reshape(2))
16
17
18@dataclass(frozen=True)
19class Layer2D:
20 name: str
21 lattice: gb.Lattice2D
22 basis_atoms: list[BasisAtom]
23 atom_style: str = "atomic"
24
25 @property
26 def A(self):
27 return np.array(self.lattice.latticeBasis, dtype=float)
28
29 def deform(self, F):
30 """
31 Apply in-plane deformation to the layer.
32 """
33 return Layer2D(
34 name=f"{self.name}_def",
35 lattice=gb.Lattice2D(self.A, F),
36 basis_atoms=self.basis_atoms,
37 atom_style=self.atom_style,
38 )
39
40 def box(self, lattice_vectors):
41 """
42 Build Cartesian atomic positions for this layer.
43 """
44 box_obj = self.lattice.box(lattice_vectors)
45
46 positions = []
47 atom_types = []
48 charges = []
49 labels = []
50
51 for site in box_obj:
52 site_xy = np.array(site.cartesian(), dtype=float)
53
54 for atom in self.basis_atoms:
55 basis_xy = self.A @ atom.frac_xy
56 xy = site_xy + basis_xy
57
58 positions.append((xy[0], xy[1], atom.z_rel))
59 atom_types.append(atom.atom_type)
60 charges.append(atom.charge)
61 labels.append(atom.label)
62
63 return positions, atom_types, charges, labels
64
65def triangular_lattice_structure_matrix(a: float) -> np.ndarray:
66 """
67 Structure matrix for the 2D triangular Bravais lattice used in the manuscript:
68 A = (a/2) [[0, -sqrt(3)],
69 [2, -1]]
70 """
71 return (a / 2.0) * np.array(
72 [[0.0, -np.sqrt(3.0)],
73 [2.0, -1.0]],
74 dtype=float,
75 )
76
77
78def make_graphene_layer_from_basis(name: str, basis_frac_xy: list[tuple[float, float]]) -> Layer2D:
79 """
80 Construct a graphene layer from a specified two-atom in-plane basis.
81 """
82 a = 2.46
84 lattice = gb.Lattice2D(A)
85
86 basis_atoms = [
87 BasisAtom(label="C", frac_xy=np.array(basis_frac_xy[0]), z_rel=0.0, atom_type=1, charge=0.0),
88 BasisAtom(label="C", frac_xy=np.array(basis_frac_xy[1]), z_rel=0.0, atom_type=1, charge=0.0),
89 ]
90
91 return Layer2D(
92 name=name,
93 lattice=lattice,
94 basis_atoms=basis_atoms,
95 atom_style="atomic",
96 )
97
98
99def make_mos2_layer_from_basis(
100 name: str,
101 basis_data: list[tuple[str, tuple[float, float], float, int, float]],
102) -> Layer2D:
103 """
104 Construct a MoS2 layer from a specified basis.
105
106 Each basis entry is:
107 (label, frac_xy, z_rel, atom_type, charge)
108 """
109 a = 3.19702
111 lattice = gb.Lattice2D(A)
112
113 basis_atoms = [
114 BasisAtom(
115 label=label,
116 frac_xy=np.array(frac_xy, dtype=float),
117 z_rel=float(z_rel),
118 atom_type=int(atom_type),
119 charge=float(charge),
120 )
121 for (label, frac_xy, z_rel, atom_type, charge) in basis_data
122 ]
123
124 return Layer2D(
125 name=name,
126 lattice=lattice,
127 basis_atoms=basis_atoms,
128 atom_style="full",
129 )
__post_init__(self)
Definition layers.py:14
list basis_atoms
Definition layers.py:22
str atom_style
Definition layers.py:23
box(self, lattice_vectors)
Definition layers.py:40
deform(self, F)
Definition layers.py:29
np.ndarray triangular_lattice_structure_matrix(float a)
Definition layers.py:65