Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from math import sqrt
3import numpy as np
5from ase.atoms import Atoms
8def graphene_nanoribbon(n, m, type='zigzag', saturated=False, C_H=1.09,
9 C_C=1.42, vacuum=None, magnetic=False, initial_mag=1.12,
10 sheet=False, main_element='C', saturate_element='H'):
11 """Create a graphene nanoribbon.
13 Creates a graphene nanoribbon in the x-z plane, with the nanoribbon
14 running along the z axis.
16 Parameters:
18 n: int
19 The width of the nanoribbon. For armchair nanoribbons, this
20 n may be half-integer to repeat by half a cell.
21 m: int
22 The length of the nanoribbon.
23 type: str
24 The orientation of the ribbon. Must be either 'zigzag'
25 or 'armchair'.
26 saturated: bool
27 If true, hydrogen atoms are placed along the edge.
28 C_H: float
29 Carbon-hydrogen bond length. Default: 1.09 Angstrom.
30 C_C: float
31 Carbon-carbon bond length. Default: 1.42 Angstrom.
32 vacuum: None (default) or float
33 Amount of vacuum added to non-periodic directions, if present.
34 magnetic: bool
35 Make the edges magnetic.
36 initial_mag: float
37 Magnitude of magnetic moment if magnetic.
38 sheet: bool
39 If true, make an infinite sheet instead of a ribbon (default: False)
40 """
42 if m % 1 != 0:
43 raise ValueError('m must be integer')
44 if type == 'zigzag' and n % 1 != 0:
45 raise ValueError('n must be an integer for zigzag ribbons')
47 b = sqrt(3) * C_C / 4
48 arm_unit = Atoms(main_element + '4',
49 pbc=(1, 0, 1),
50 cell=[4 * b, 0, 3 * C_C])
51 arm_unit.positions = [[0, 0, 0],
52 [b * 2, 0, C_C / 2.],
53 [b * 2, 0, 3 * C_C / 2.],
54 [0, 0, 2 * C_C]]
55 arm_unit_half = Atoms(main_element + '2',
56 pbc=(1, 0, 1),
57 cell=[2 * b, 0, 3 * C_C])
58 arm_unit_half.positions = [[b * 2, 0, C_C / 2.],
59 [b * 2, 0, 3 * C_C / 2.]]
60 zz_unit = Atoms(main_element + '2',
61 pbc=(1, 0, 1),
62 cell=[3 * C_C / 2.0, 0, b * 4])
63 zz_unit.positions = [[0, 0, 0],
64 [C_C / 2.0, 0, b * 2]]
65 atoms = Atoms()
67 if type == 'zigzag':
68 edge_index0 = np.arange(m) * 2
69 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 + 1
71 if magnetic:
72 mms = np.zeros(m * n * 2)
73 for i in edge_index0:
74 mms[i] = initial_mag
75 for i in edge_index1:
76 mms[i] = -initial_mag
78 for i in range(n):
79 layer = zz_unit.repeat((1, 1, m))
80 layer.positions[:, 0] += 3 * C_C / 2 * i
81 if i % 2 == 1:
82 layer.positions[:, 2] += 2 * b
83 layer[-1].position[2] -= b * 4 * m
84 atoms += layer
86 xmin = atoms.positions[0, 0]
88 if magnetic:
89 atoms.set_initial_magnetic_moments(mms)
90 if saturated:
91 H_atoms0 = Atoms(saturate_element + str(m))
92 H_atoms0.positions = atoms[edge_index0].positions
93 H_atoms0.positions[:, 0] -= C_H
94 H_atoms1 = Atoms(saturate_element + str(m))
95 H_atoms1.positions = atoms[edge_index1].positions
96 H_atoms1.positions[:, 0] += C_H
97 atoms += H_atoms0 + H_atoms1
98 atoms.cell = [n * 3 * C_C / 2, 0, m * 4 * b]
100 elif type == 'armchair':
101 n *= 2
102 n_int = int(round(n))
103 if abs(n_int - n) > 1e-10:
104 raise ValueError(
105 'The argument n has to be half-integer for armchair ribbons.')
106 n = n_int
108 for i in range(n // 2):
109 layer = arm_unit.repeat((1, 1, m))
110 layer.positions[:, 0] -= 4 * b * i
111 atoms += layer
112 if n % 2:
113 layer = arm_unit_half.repeat((1, 1, m))
114 layer.positions[:, 0] -= 4 * b * (n // 2)
115 atoms += layer
117 xmin = atoms.positions[-1, 0]
119 if saturated:
120 if n % 2:
121 arm_right_saturation = Atoms(saturate_element + '2',
122 pbc=(1, 0, 1),
123 cell=[2 * b, 0, 3 * C_C])
124 arm_right_saturation.positions = [
125 [- sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5],
126 [- sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]]
127 else:
128 arm_right_saturation = Atoms(saturate_element + '2',
129 pbc=(1, 0, 1),
130 cell=[4 * b, 0, 3 * C_C])
131 arm_right_saturation.positions = [
132 [- sqrt(3) / 2 * C_H, 0, C_H * 0.5],
133 [- sqrt(3) / 2 * C_H, 0, 2 * C_C - C_H * 0.5]]
134 arm_left_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1),
135 cell=[4 * b, 0, 3 * C_C])
136 arm_left_saturation.positions = [
137 [b * 2 + sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5],
138 [b * 2 + sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]]
139 arm_right_saturation.positions[:, 0] -= 4 * b * (n / 2.0 - 1)
141 atoms += arm_right_saturation.repeat((1, 1, m))
142 atoms += arm_left_saturation.repeat((1, 1, m))
144 atoms.cell = [b * 4 * n / 2.0, 0, 3 * C_C * m]
146 atoms.set_pbc([sheet, False, True])
148 # The ribbon was 'built' from x=0 towards negative x.
149 # Move the ribbon to positive x:
150 atoms.positions[:, 0] -= xmin
151 if not sheet:
152 atoms.cell[0] = 0.0
153 if vacuum is not None:
154 atoms.center(vacuum, axis=1)
155 if not sheet:
156 atoms.center(vacuum, axis=0)
157 return atoms