def chiral_nanotube(n, m, R=1.42, element='C'): """ Construct a nanotube with a chiral container. parameters: =========== n,m: chiral indices R: bond length element: element type """ from hotbit import Atoms a = np.sqrt(3) * R a1 = np.array([a, 0, 0]) a2 = np.array([0.5 * a, -1.5 * R, 0]) rl = [] shift = (a / 2, -0.5 * R, 0) for i in range(n): origin = i * a1 rl.append(origin) rl.append(origin + shift) for j in range(m): origin = (n - 1) * a1 + (j + 1) * a1 rl.append(origin) rl.append(origin + shift) atoms = Atoms() C = n * a1 + m * a2 Cn = np.linalg.norm(C) T = np.array([C[1], -C[0], 0]) t = T / np.linalg.norm(T) radius = Cn / (2 * pi) atoms = Atoms() for r in rl: phi = np.dot(r, C) / Cn**2 * 2 * pi atoms += Atom( element, (radius * np.cos(phi), radius * np.sin(phi), np.dot(r, t))) atoms = Atoms(atoms, container='Chiral') height = np.abs(np.dot(a1 - a2, t)) angle = -np.dot(a1 - a2, C) / Cn**2 * 2 * pi atoms.set_container(angle=angle, height=height) data = nanotube_data(n, m, R) T, Ntot = data['T'], 2 * data['hexagons_per_cell'] data['height'] = height data['twist'] = angle atoms.data = data return atoms
def graphene(n1, n2, R, height=5.0): """ Construct graphene lattice, multiply the primitive cell n1 x n2 times in corresponding directions. .-----. / / / X / a2 / / X-----> a1 """ from hotbit import Atoms if not isinstance(R, float): R = R[0] a1 = vec([R * np.cos(pi / 6) * 2, 0., 0.]) a2 = 0.5 * a1 + vec([0., 1.5 * R, 0.]) #assert n2%2==0 r = [] for i1 in range(n1): for i2 in range(n2): corner = i1 * a1 + i2 * a2 r.append(corner) r.append(corner + a1 + vec([0.0, R, 0.0])) cell = [[n1 * a1[0], 0, 0], [n2 * a2[0], n2 * a2[1], 0], [0, 0, 10]] atoms = Atoms('C' * len(r), positions=r, cell=cell) atoms.center(vacuum=height / 2, axis=2) atoms.set_pbc((True, True, False)) return atoms
def compare_trajectory(self, i_traj, calc, tables, i_par): """ Calculate the energies for the frames in the trajectory and plot them. """ frames = [] energies = [] trajectory = PickleTrajectory(self.trajectories[i_traj]) for i, image in enumerate(trajectory): e_tb = None try: atoms = Atoms(image) c = copy(calc) c.tables = tables atoms.set_calculator(c) e_tb = atoms.get_potential_energy() except Exception as ex: print(ex, file=self.txt) if e_tb != None: energies.append(e_tb) frames.append(i) delta_E = self.norm_to_isolated_atoms(trajectory[0]) for i in range(len(energies)): energies[i] += delta_E self.plot(frames, energies, i_traj, tables, i_par)
def append_dimer(self, weight, calc, R, comment=None, label='dimer', color=None): """ Use dimer bond length in fitting. parameters: =========== weight: fitting weight calc: Hotbit calculator used in calculation (remember Gamma-point and charge) R: dimer bond length (Angstroms) comment: fitting comment for par-file (replaced by label if None) label: plotting label (replaced by comment if None) color: plotting color """ if comment == None: comment = label self.r_dimer = R atoms = Atoms([self.sym1, self.sym2], [(0, 0, 0), (R, 0, 0)], pbc=False) atoms.center(vacuum=5) color = self._get_color(color) self.append_scalable_system(weight, calc, atoms, comment=comment, label=label, color=color)
def setup_bending(atoms, angle, radius, rotation=0.0, physical=True): """ Prepare a bending setup for a tube or slab. Tube should be originally periodic in z-direction with the correct cell, and optionally periodic in y-direction. Then atoms are set up for bending with hotbit.Wedge class with bending wrt. z-axis, and optionally periodic along z-axis. Atoms are first rotated pi/2 around -x-axis, then rotated an angle 'rotation' around y-axis, then transformed the distance 'radius' towards x-axis. The atoms are further adjusted for the wedge angle 'angle'. 'physical' tells if the angle should be 2*pi/integer. """ a = atoms.copy() a.rotate('-x', np.pi / 2) L = a.get_cell().diagonal() if abs(L.prod() - a.get_volume()) > 1E-10: raise AssertionError('Cell should be orthorhombic.') pbc = a.get_pbc() if not pbc[2] or pbc[0]: raise AssertionError( 'Should be periodic in z-direction and not periodic in x-direction' ) r = a.get_positions() if np.any(r[:, 1] < 0): # index 1 is correct here raise AssertionError('For bending, all atoms should be above xy-plane') # move and adjust a.rotate('y', rotation) for i in range(len(a)): x, y = r[i, 0:2] R = x + radius phi = y * angle / L[2] r[i, 0] = R * np.cos(phi) r[i, 1] = R * np.sin(phi) a.set_positions(r) a = Atoms(a, container='Wedge') a.set_container(angle=angle, height=L[1], pbcz=pbc[1], physical=physical) return a
def compare_trajectory(self, i_traj, calc, tables, i_par): """ Calculate the energies for the frames in the trajectory and plot them. """ frames = [] energies = [] trajectory = PickleTrajectory(self.trajectories[i_traj]) for i, image in enumerate(trajectory): e_tb = None try: atoms = Atoms(image) c = copy(calc) c.tables = tables atoms.set_calculator(c) e_tb = atoms.get_potential_energy() except Exception, ex: print >> self.txt, ex if e_tb != None: energies.append(e_tb) frames.append(i)
def get_isolated_energies(self, trajs, par): """ Return the energies of an isolated atoms. """ elements = [] energies = {} for t in trajs: traj = PickleTrajectory(t) for atom in traj[0]: if not atom.symbol in elements: elements.append(atom.symbol) el1, el2 = par.split("_")[0:2] for el in elements: ss = "%s%s" % (el, el) if el1 == el2 and el1 == el: tables = {ss:par, 'rest':'default'} calc = Hotbit(SCC=True, tables=tables) else: calc = Hotbit(SCC=True) atoms = Atoms(ss, ((0,0,0),(200,0,0))) atoms.center(vacuum=100) atoms.set_calculator(calc) energies[el] = atoms.get_potential_energy() / 2 return energies
def nanotube(n, m, R=1.42, length=1, element='C'): ''' Create a nanotube around z-axis. parameters: ----------- n,m: chiral indices R: nearest neighbor distance length: number of unit cells element: element symbol ''' from hotbit import Atoms at = Atoms(pbc=(False, False, True)) sq3 = sqrt(3.0) a0 = R gcn = gcd(n, m) a1 = np.array([sq3 / 2, 0.5]) * a0 * sq3 a2 = np.array([sq3 / 2, -0.5]) * a0 * sq3 h = float(float(n) - float(m)) / float(3 * gcn) if h - int(h) == 0.0: RR = 3 else: RR = 1 c = n * a1 + m * a2 abs_c = sqrt(dot(c, c)) a = (-(2 * m + n) * a1 + (2 * n + m) * a2) / (gcn * RR) abs_a = sqrt(dot(a, a)) eps = 0.01 b = [[1. / 3 - eps, 1. / 3 - eps], [2. / 3 - eps, 2. / 3 - eps]] nxy = max(n, m) + 100 eps = 0.00001 for x in xrange(-nxy, nxy): for y in xrange(-nxy, nxy): for b1, b2 in b: p = (x + b1) * a1 + (y + b2) * a2 abs_p = sqrt(dot(p, p)) sa = dot(p, a) / (abs_a**2) sc = dot(p, c) / (abs_c**2) if sa >= 0 and sa < 1 - eps and sc >= 0 and sc < 1 - eps: r = (cos(2 * pi * sc) * abs_c / (2 * pi), sin(2 * pi * sc) * abs_c / (2 * pi), sa * abs_a) at += Atom(element, r) at.set_cell((2 * abs_c / (2 * pi), 2 * abs_c / (2 * pi), length * abs_a)) b = at.copy() for i in range(length - 1): b.translate((0.0, 0.0, abs_a)) for j in b: at += j at.center(axis=2) rcm = at.get_center_of_mass() at.translate((-rcm[0], -rcm[1], 0)) at.set_pbc((False, False, True)) at.data = nanotube_data(n, m) return at