def mx2(formula='MoS2', kind='2H', a=3.18, thickness=3.19, size=(1, 1, 1), vacuum=7.5): """Create three-layer 2D materials with hexagonal structure. For metal dichalcogenites, etc. The kind argument accepts '2H', which gives a mirror plane symmetry and '1T', which gives an inversion symmetry.""" if kind == '2H': basis = [(0, 0, 0), (2 / 3, 1 / 3, 0.5 * thickness), (2 / 3, 1 / 3, -0.5 * thickness)] elif kind == '1T': basis = [(0, 0, 0), (2 / 3, 1 / 3, 0.5 * thickness), (1 / 3, 2 / 3, -0.5 * thickness)] else: raise ValueError('Structure not recognized') cell = [[a, 0, 0], [-a / 2, a * 3**0.5 / 2, 0], [0, 0, 1]] atoms = Atoms(formula, cell=cell, scaled_positions=basis, pbc=(1, 1, 0)) atoms = atoms.repeat(size) atoms.center(vacuum=vacuum, axis=2) return atoms
def build_system(self, name): try: # Known molecule or atom? atoms = molecule(name) if len(atoms) == 2 and self.bond_length is not None: atoms.set_distance(0, 1, self.bond_length) except NotImplementedError: symbols = string2symbols(name) if len(symbols) == 1: magmom = ground_state_magnetic_moments[atomic_numbers[ symbols[0]]] atoms = Atoms(name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if self.bond_length is None: b = (covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]]) else: b = self.bond_length atoms = Atoms(name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError('Unknown molecule: ' + name) if self.unit_cell is None: atoms.center(vacuum=self.vacuum) else: atoms.cell = self.unit_cell atoms.center() return atoms
def get_structure(formula, prototype=None, base_dir="./", c=None, **filters): db_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../c2db.db") # Serial version, only on rank 0 candidates = {} # if world.rank == 0: db = ase.db.connect(db_file) if prototype is None: res = db.select(formula=formula, **filters) else: res = db.select(formula=formula, prototype=prototype) for mol in res: symbol = mol.formula pos = mol.positions cell = mol.cell pbc = mol.pbc # Change distance if (c is not None) and (isinstance(c, (float, int))): cell.setflags(write=True) cell[-1][-1] = c pbc = (True, True, True) # Use full periodic name = "{}-{}".format(symbol, mol.prototype) # name = os.path.join(os.path.abspath(base_dir), # "{}-{}.traj".format(symbol, mol.prototype)) atoms = Atoms(symbol, positions=pos, cell=cell, pbc=pbc) candidates[name] = atoms if (c is not None) and (isinstance(c, (float, int))): atoms.center() # center the atoms, although not really needed return candidates
def mx2(formula='MoS2', kind='2H', a=3.18, thickness=3.19, size=(1, 1, 1), vacuum=None): """Create three-layer 2D materials with hexagonal structure. For metal dichalcogenites, etc. The kind argument accepts '2H', which gives a mirror plane symmetry and '1T', which gives an inversion symmetry.""" if kind == '2H': basis = [(0, 0, 0), (2 / 3, 1 / 3, 0.5 * thickness), (2 / 3, 1 / 3, -0.5 * thickness)] elif kind == '1T': basis = [(0, 0, 0), (2 / 3, 1 / 3, 0.5 * thickness), (1 / 3, 2 / 3, -0.5 * thickness)] else: raise ValueError('Structure not recognized:', kind) cell = [[a, 0, 0], [-a / 2, a * 3**0.5 / 2, 0], [0, 0, 0]] atoms = Atoms(formula, cell=cell, pbc=(1, 1, 0)) atoms.set_scaled_positions(basis) if vacuum is not None: atoms.center(vacuum, axis=2) atoms = atoms.repeat(size) return atoms
def build_system(self, name): try: # Known molecule or atom? atoms = molecule(name) if len(atoms) == 2 and self.bond_length is not None: atoms.set_distance(0, 1, self.bond_length) except NotImplementedError: symbols = string2symbols(name) if len(symbols) == 1: Z = atomic_numbers[symbols[0]] magmom = ground_state_magnetic_moments[Z] atoms = Atoms(name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if self.bond_length is None: b = (covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]]) else: b = self.bond_length atoms = Atoms(name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError('Unknown molecule: ' + name) if self.unit_cell is None: atoms.center(vacuum=self.vacuum) else: atoms.cell = self.unit_cell atoms.center() return atoms
def graphene(formula='C2', a=2.460, size=(1, 1, 1), vacuum=None): """Create a graphene monolayer structure.""" cell = [[a, 0, 0], [-a / 2, a * 3**0.5 / 2, 0], [0, 0, 0]] basis = [[0, 0, 0], [2./3, 1./3, 0]] atoms = Atoms(formula, cell=cell, pbc=(1, 1, 0)) atoms.set_scaled_positions(basis) if vacuum is not None: atoms.center(vacuum, axis=2) atoms = atoms.repeat(size) return atoms
def molecule(name, vacuum=None, **kwargs): if name in extra: kwargs.update(extra[name]) mol = Atoms(**kwargs) else: mol = g2[name] if kwargs: mol = Atoms(mol, **kwargs) if vacuum is not None: mol.center(vacuum=vacuum) return mol
def build_molecule(self, name): args = self.args try: # Known molecule or atom? atoms = molecule(name) except NotImplementedError: symbols = string2symbols(name) if len(symbols) == 1: Z = atomic_numbers[symbols[0]] magmom = ground_state_magnetic_moments[Z] atoms = Atoms(name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if args.bond_length is None: b = covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]] else: b = args.bond_length atoms = Atoms(name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError("Unknown molecule: " + name) else: if len(atoms) == 2 and args.bond_length is not None: atoms.set_distance(0, 1, args.bond_length) if args.unit_cell is None: atoms.center(vacuum=args.vacuum) else: a = [float(x) for x in args.unit_cell.split(",")] if len(a) == 1: cell = [a[0], a[0], a[0]] elif len(a) == 3: cell = a else: a, b, c, alpha, beta, gamma = a degree = np.pi / 180.0 cosa = np.cos(alpha * degree) cosb = np.cos(beta * degree) sinb = np.sin(beta * degree) cosg = np.cos(gamma * degree) sing = np.sin(gamma * degree) cell = [ [a, 0, 0], [b * cosg, b * sing, 0], [ c * cosb, c * (cosa - cosb * cosg) / sing, c * np.sqrt(sinb ** 2 - ((cosa - cosb * cosg) / sing) ** 2), ], ] atoms.cell = cell atoms.center() return atoms
def setup_atom(symbol, vac=3.0, t=0.0, odd=0.0): from ase import Atoms from ase.data import chemical_symbols, atomic_numbers, ground_state_magnetic_moments assert symbol in chemical_symbols Z = atomic_numbers[symbol] m = ground_state_magnetic_moments[Z] atoms = Atoms(symbol) atoms.center(vacuum=vac) atoms.translate([t,t,t]) atoms.cell[1][1] += odd atoms.cell[2][2] += 2*odd atoms.set_initial_magnetic_moments([m]) return atoms
def build_molecule(name, opts): try: # Known molecule or atom? atoms = molecule(name) except NotImplementedError: symbols = string2symbols(name) if len(symbols) == 1: Z = atomic_numbers[symbols[0]] magmom = ground_state_magnetic_moments[Z] atoms = Atoms(name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if opts.bond_length is None: b = (covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]]) else: b = opts.bond_length atoms = Atoms(name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError('Unknown molecule: ' + name) else: if len(atoms) == 2 and opts.bond_length is not None: atoms.set_distance(0, 1, opts.bond_length) if opts.unit_cell is None: atoms.center(vacuum=opts.vacuum) else: a = [float(x) for x in opts.unit_cell.split(',')] if len(a) == 1: cell = [a[0], a[0], a[0]] elif len(a) == 3: cell = a else: a, b, c, alpha, beta, gamma = a degree = np.pi / 180.0 cosa = np.cos(alpha * degree) cosb = np.cos(beta * degree) sinb = np.sin(beta * degree) cosg = np.cos(gamma * degree) sing = np.sin(gamma * degree) cell = [[a, 0, 0], [b * cosg, b * sing, 0], [c * cosb, c * (cosa - cosb * cosg) / sing, c * np.sqrt( sinb**2 - ((cosa - cosb * cosg) / sing)**2)]] atoms.cell = cell atoms.center() return atoms
def test_md(cp2k_factory): calc = cp2k_factory.calc(label='test_H2_MD') positions = [(0, 0, 0), (0, 0, 0.7245595)] atoms = Atoms('HH', positions=positions, calculator=calc) atoms.center(vacuum=2.0) MaxwellBoltzmannDistribution(atoms, temperature_K=0.5 * 300, force_temp=True) energy_start = atoms.get_potential_energy() + atoms.get_kinetic_energy() with VelocityVerlet(atoms, 0.5 * units.fs) as dyn: dyn.run(20) energy_end = atoms.get_potential_energy() + atoms.get_kinetic_energy() assert abs(energy_start - energy_end) < 1e-4
def molecule(name, vacuum=None, **kwargs): """Create an atomic structure from a database. This is a helper function to easily create molecules from the g2 and extra databases. Parameters ---------- name : str Name of the molecule to build. vacuum : float, optional Amount of vacuum to pad the molecule with on all sides. Additional keyword arguments (kwargs) can be supplied, which are passed to ase.Atoms. Returns ------- ase.atoms.Atoms An ASE Atoms object corresponding to the specified molecule. Notes ----- To see a list of allowed names, try: >>> from ase.collections import g2 >>> print(g2.names) >>> from ase.build.molecule import extra >>> print(extra.keys()) Examples -------- >>> from ase.build import molecule >>> atoms = molecule('H2O') """ if name in extra: kwargs.update(extra[name]) mol = Atoms(**kwargs) else: mol = g2[name] if kwargs: mol = Atoms(mol, **kwargs) if vacuum is not None: mol.center(vacuum=vacuum) return mol
def test_md(cp2k_factory): calc = cp2k_factory.calc(label='test_H2_MD') positions = [(0, 0, 0), (0, 0, 0.7245595)] atoms = Atoms('HH', positions=positions, calculator=calc) atoms.center(vacuum=2.0) # Run MD MaxwellBoltzmannDistribution(atoms, 0.5 * 300 * units.kB, force_temp=True) energy_start = atoms.get_potential_energy() + atoms.get_kinetic_energy() dyn = VelocityVerlet(atoms, 0.5 * units.fs) #def print_md(): # energy = atoms.get_potential_energy() + atoms.get_kinetic_energy() # print("MD total-energy: %.10feV" % energy) #dyn.attach(print_md, interval=1) dyn.run(20) energy_end = atoms.get_potential_energy() + atoms.get_kinetic_energy() assert energy_start - energy_end < 1e-4 print('passed test "H2_MD"')
def main(): if "ASE_CP2K_COMMAND" not in os.environ: raise NotAvailable('$ASE_CP2K_COMMAND not defined') calc = CP2K(label='test_H2_MD') positions = [(0, 0, 0), (0, 0, 0.7245595)] atoms = Atoms('HH', positions=positions, calculator=calc) atoms.center(vacuum=2.0) # Run MD MaxwellBoltzmannDistribution(atoms, 0.5 * 300 * units.kB, force_temp=True) energy_start = atoms.get_potential_energy() + atoms.get_kinetic_energy() dyn = VelocityVerlet(atoms, 0.5 * units.fs) #def print_md(): # energy = atoms.get_potential_energy() + atoms.get_kinetic_energy() # print("MD total-energy: %.10feV" % energy) #dyn.attach(print_md, interval=1) dyn.run(20) energy_end = atoms.get_potential_energy() + atoms.get_kinetic_energy() assert energy_start - energy_end < 1e-4 print('passed test "H2_MD"')
def main(): if "ASE_CP2K_COMMAND" not in os.environ: raise NotAvailable('$ASE_CP2K_COMMAND not defined') calc = CP2K(label='test_H2_MD') positions = [(0, 0, 0), (0, 0, 0.7245595)] atoms = Atoms('HH', positions=positions, calculator=calc) atoms.center(vacuum=2.0) # Run MD MaxwellBoltzmannDistribution(atoms, 0.5 * 300 * units.kB, force_temp=True) energy_start = atoms.get_potential_energy() + atoms.get_kinetic_energy() dyn = VelocityVerlet(atoms, 0.5 * units.fs) #def print_md(): # energy = atoms.get_potential_energy() + atoms.get_kinetic_energy() # print("MD total-energy: %.10feV" % energy) #dyn.attach(print_md, interval=1) dyn.run(20) energy_end = atoms.get_potential_energy() + atoms.get_kinetic_energy() assert energy_start - energy_end < 1e-4 print('passed test "H2_MD"')
def graphene_nanoribbon(n, m, type='zigzag', saturated=False, C_H=1.09, C_C=1.42, vacuum=None, magnetic=False, initial_mag=1.12, sheet=False, main_element='C', saturate_element='H'): """Create a graphene nanoribbon. Creates a graphene nanoribbon in the x-z plane, with the nanoribbon running along the z axis. Parameters: n: int The width of the nanoribbon. For armchair nanoribbons, this n may be half-integer to repeat by half a cell. m: int The length of the nanoribbon. type: str The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated: bool If true, hydrogen atoms are placed along the edge. C_H: float Carbon-hydrogen bond length. Default: 1.09 Angstrom. C_C: float Carbon-carbon bond length. Default: 1.42 Angstrom. vacuum: None (default) or float Amount of vacuum added to non-periodic directions, if present. magnetic: bool Make the edges magnetic. initial_mag: float Magnitude of magnetic moment if magnetic. sheet: bool If true, make an infinite sheet instead of a ribbon (default: False) """ if m % 1 != 0: raise ValueError('m must be integer') if type == 'zigzag' and n % 1 != 0: raise ValueError('n must be an integer for zigzag ribbons') b = sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + '4', pbc=(1, 0, 1), cell=[4 * b, 0, 3 * C_C]) arm_unit.positions = [[0, 0, 0], [b * 2, 0, C_C / 2.], [b * 2, 0, 3 * C_C / 2.], [0, 0, 2 * C_C]] arm_unit_half = Atoms(main_element + '2', pbc=(1, 0, 1), cell=[2 * b, 0, 3 * C_C]) arm_unit_half.positions = [[b * 2, 0, C_C / 2.], [b * 2, 0, 3 * C_C / 2.]] zz_unit = Atoms(main_element + '2', pbc=(1, 0, 1), cell=[3 * C_C / 2.0, 0, b * 4]) zz_unit.positions = [[0, 0, 0], [C_C / 2.0, 0, b * 2]] atoms = Atoms() if type == 'zigzag': edge_index0 = np.arange(m) * 2 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 + 1 if magnetic: mms = np.zeros(m * n * 2) for i in edge_index0: mms[i] = initial_mag for i in edge_index1: mms[i] = -initial_mag for i in range(n): layer = zz_unit.repeat((1, 1, m)) layer.positions[:, 0] += 3 * C_C / 2 * i if i % 2 == 1: layer.positions[:, 2] += 2 * b layer[-1].position[2] -= b * 4 * m atoms += layer xmin = atoms.positions[0, 0] if magnetic: atoms.set_initial_magnetic_moments(mms) if saturated: H_atoms0 = Atoms(saturate_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 0] -= C_H H_atoms1 = Atoms(saturate_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 0] += C_H atoms += H_atoms0 + H_atoms1 atoms.cell = [n * 3 * C_C / 2, 0, m * 4 * b] elif type == 'armchair': n *= 2 n_int = int(round(n)) if abs(n_int - n) > 1e-10: raise ValueError( 'The argument n has to be half-integer for armchair ribbons.') n = n_int for i in range(n // 2): layer = arm_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 4 * b * i atoms += layer if n % 2: layer = arm_unit_half.repeat((1, 1, m)) layer.positions[:, 0] -= 4 * b * (n // 2) atoms += layer xmin = atoms.positions[-1, 0] if saturated: if n % 2: arm_right_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[2 * b, 0, 3 * C_C]) arm_right_saturation.positions = [[ -sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5 ], [-sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]] else: arm_right_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[4 * b, 0, 3 * C_C]) arm_right_saturation.positions = [[ -sqrt(3) / 2 * C_H, 0, C_H * 0.5 ], [-sqrt(3) / 2 * C_H, 0, 2 * C_C - C_H * 0.5]] arm_left_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[4 * b, 0, 3 * C_C]) arm_left_saturation.positions = [[ b * 2 + sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5 ], [b * 2 + sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]] arm_right_saturation.positions[:, 0] -= 4 * b * (n / 2.0 - 1) atoms += arm_right_saturation.repeat((1, 1, m)) atoms += arm_left_saturation.repeat((1, 1, m)) atoms.cell = [b * 4 * n / 2.0, 0, 3 * C_C * m] atoms.set_pbc([sheet, False, True]) # The ribbon was 'built' from x=0 towards negative x. # Move the ribbon to positive x: atoms.positions[:, 0] -= xmin if not sheet: atoms.cell[0] = 0.0 if vacuum is not None: atoms.center(vacuum, axis=1) if not sheet: atoms.center(vacuum, axis=0) return atoms
def graphene_nanoribbon(n, m, type='zigzag', saturated=False, C_H=1.09, C_C=1.42, vacuum=None, magnetic=False, initial_mag=1.12, sheet=False, main_element='C', saturate_element='H'): """Create a graphene nanoribbon. Creates a graphene nanoribbon in the x-z plane, with the nanoribbon running along the z axis. Parameters: n: int The width of the nanoribbon. m: int The length of the nanoribbon. type: str The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated: bool If true, hydrogen atoms are placed along the edge. C_H: float Carbon-hydrogen bond length. Default: 1.09 Angstrom. C_C: float Carbon-carbon bond length. Default: 1.42 Angstrom. vacuum: None (default) or float Amount of vacuum added to non-periodic directions, if present. magnetic: bool Make the edges magnetic. initial_mag: float Magnitude of magnetic moment if magnetic. sheet: bool If true, make an infinite sheet instead of a ribbon (default: False) """ b = sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + '4', pbc=(1, 0, 1), cell=[4 * b, 0, 3 * C_C]) arm_unit.positions = [[0, 0, 0], [b * 2, 0, C_C / 2.], [b * 2, 0, 3 * C_C / 2.], [0, 0, 2 * C_C]] zz_unit = Atoms(main_element + '2', pbc=(1, 0, 1), cell=[3 * C_C / 2.0, 0, b * 4]) zz_unit.positions = [[0, 0, 0], [C_C / 2.0, 0, b * 2]] atoms = Atoms() if type == 'zigzag': edge_index0 = np.arange(m) * 2 + 1 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 if magnetic: mms = np.zeros(m * n * 2) for i in edge_index0: mms[i] = initial_mag for i in edge_index1: mms[i] = -initial_mag for i in range(n): layer = zz_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 3 * C_C / 2 * i if i % 2 == 1: layer.positions[:, 2] += 2 * b layer[-1].position[2] -= b * 4 * m atoms += layer if magnetic: atoms.set_initial_magnetic_moments(mms) if saturated: H_atoms0 = Atoms(saturate_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 0] += C_H H_atoms1 = Atoms(saturate_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 0] -= C_H atoms += H_atoms0 + H_atoms1 atoms.cell = [n * 3 * C_C / 2, 0, m * 4 * b] elif type == 'armchair': for i in range(n): layer = arm_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 4 * b * i atoms += layer if saturated: arm_right_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[4 * b, 0, 3 * C_C]) arm_right_saturation.positions = [[ -sqrt(3) / 2 * C_H, 0, C_H * 0.5 ], [-sqrt(3) / 2 * C_H, 0, 2 * C_C - C_H * 0.5]] arm_left_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[4 * b, 0, 3 * C_C]) arm_left_saturation.positions = [[ b * 2 + sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5 ], [b * 2 + sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]] arm_right_saturation.positions[:, 0] -= 4 * b * (n - 1) atoms += arm_right_saturation.repeat((1, 1, m)) atoms += arm_left_saturation.repeat((1, 1, m)) atoms.cell = [b * 4 * n, 0, 3 * C_C * m] atoms.set_pbc([sheet, False, True]) atoms.set_scaled_positions(atoms.get_scaled_positions() % 1.0) if not sheet: atoms.cell[0] = 0.0 if vacuum: atoms.center(vacuum, axis=1) if not sheet: atoms.center(vacuum, axis=0) return atoms
def surface(symbol, structure, face, size, a, c, vacuum, orthogonal=True): """Function to build often used surfaces. Don't call this function directly - use fcc100, fcc110, bcc111, ...""" Z = atomic_numbers[symbol] if a is None: sym = reference_states[Z]['symmetry'].lower() if sym != structure: raise ValueError("Can't guess lattice constant for %s-%s!" % (structure, symbol)) a = reference_states[Z]['a'] if structure == 'hcp' and c is None: if reference_states[Z]['symmetry'].lower() == 'hcp': c = reference_states[Z]['c/a'] * a else: c = sqrt(8 / 3.0) * a positions = np.empty((size[2], size[1], size[0], 3)) positions[..., 0] = np.arange(size[0]).reshape((1, 1, -1)) positions[..., 1] = np.arange(size[1]).reshape((1, -1, 1)) positions[..., 2] = np.arange(size[2]).reshape((-1, 1, 1)) numbers = np.ones(size[0] * size[1] * size[2], int) * Z tags = np.empty((size[2], size[1], size[0]), int) tags[:] = np.arange(size[2], 0, -1).reshape((-1, 1, 1)) slab = Atoms(numbers, tags=tags.ravel(), pbc=(True, True, False), cell=size) surface_cell = None sites = {'ontop': (0, 0)} surf = structure + face if surf == 'fcc100': cell = (sqrt(0.5), sqrt(0.5), 0.5) positions[-2::-2, ..., :2] += 0.5 sites.update({'hollow': (0.5, 0.5), 'bridge': (0.5, 0)}) elif surf == 'fcc110': cell = (1.0, sqrt(0.5), sqrt(0.125)) positions[-2::-2, ..., :2] += 0.5 sites.update({ 'hollow': (0.5, 0.5), 'longbridge': (0.5, 0), 'shortbridge': (0, 0.5) }) elif surf == 'bcc100': cell = (1.0, 1.0, 0.5) positions[-2::-2, ..., :2] += 0.5 sites.update({'hollow': (0.5, 0.5), 'bridge': (0.5, 0)}) else: if orthogonal and size[1] % 2 == 1: raise ValueError(("Can't make orthorhombic cell with size=%r. " % (tuple(size), )) + 'Second number in size must be even.') if surf == 'fcc111': cell = (sqrt(0.5), sqrt(0.375), 1 / sqrt(3)) if orthogonal: positions[-1::-3, 1::2, :, 0] += 0.5 positions[-2::-3, 1::2, :, 0] += 0.5 positions[-3::-3, 1::2, :, 0] -= 0.5 positions[-2::-3, ..., :2] += (0.0, 2.0 / 3) positions[-3::-3, ..., :2] += (0.5, 1.0 / 3) else: positions[-2::-3, ..., :2] += (-1.0 / 3, 2.0 / 3) positions[-3::-3, ..., :2] += (1.0 / 3, 1.0 / 3) sites.update({ 'bridge': (0.5, 0), 'fcc': (1.0 / 3, 1.0 / 3), 'hcp': (2.0 / 3, 2.0 / 3) }) elif surf == 'hcp0001': cell = (1.0, sqrt(0.75), 0.5 * c / a) if orthogonal: positions[:, 1::2, :, 0] += 0.5 positions[-2::-2, ..., :2] += (0.0, 2.0 / 3) else: positions[-2::-2, ..., :2] += (-1.0 / 3, 2.0 / 3) sites.update({ 'bridge': (0.5, 0), 'fcc': (1.0 / 3, 1.0 / 3), 'hcp': (2.0 / 3, 2.0 / 3) }) elif surf == 'bcc110': cell = (1.0, sqrt(0.5), sqrt(0.5)) if orthogonal: positions[:, 1::2, :, 0] += 0.5 positions[-2::-2, ..., :2] += (0.0, 1.0) else: positions[-2::-2, ..., :2] += (-0.5, 1.0) sites.update({ 'shortbridge': (0, 0.5), 'longbridge': (0.5, 0), 'hollow': (0.375, 0.25) }) elif surf == 'bcc111': cell = (sqrt(2), sqrt(1.5), sqrt(3) / 6) if orthogonal: positions[-1::-3, 1::2, :, 0] += 0.5 positions[-2::-3, 1::2, :, 0] += 0.5 positions[-3::-3, 1::2, :, 0] -= 0.5 positions[-2::-3, ..., :2] += (0.0, 2.0 / 3) positions[-3::-3, ..., :2] += (0.5, 1.0 / 3) else: positions[-2::-3, ..., :2] += (-1.0 / 3, 2.0 / 3) positions[-3::-3, ..., :2] += (1.0 / 3, 1.0 / 3) sites.update({'hollow': (1.0 / 3, 1.0 / 3)}) surface_cell = a * np.array([(cell[0], 0), (cell[0] / 2, cell[1])]) if not orthogonal: cell = np.array([(cell[0], 0, 0), (cell[0] / 2, cell[1], 0), (0, 0, cell[2])]) if surface_cell is None: surface_cell = a * np.diag(cell[:2]) if isinstance(cell, tuple): cell = np.diag(cell) slab.set_positions(positions.reshape((-1, 3))) slab.set_cell([a * v * n for v, n in zip(cell, size)], scale_atoms=True) if vacuum is not None: slab.center(vacuum=vacuum, axis=2) slab.adsorbate_info['cell'] = surface_cell slab.adsorbate_info['sites'] = sites return slab
def nanotube(n, m, length=1, bond=1.42, symbol='C', verbose=False, vacuum=None): """Create an atomic structure. Creates a single-walled nanotube whose structure is specified using the standardized (n, m) notation. Parameters ---------- n : int n in the (n, m) notation. m : int m in the (n, m) notation. length : int, optional Length (axial repetitions) of the nanotube. bond : float, optional Bond length between neighboring atoms. symbol : str, optional Chemical element to construct the nanotube from. verbose : bool, optional If True, will display key geometric parameters. Returns ------- ase.atoms.Atoms An ASE Atoms object corresponding to the specified molecule. Examples -------- >>> from ase.build import nanotube >>> atoms1 = nanotube(6, 0, length=4) >>> atoms2 = nanotube(3, 3, length=6, bond=1.4, symbol='Si') """ if n < m: m, n = n, m sign = -1 else: sign = 1 nk = 6000 sq3 = sqrt(3.0) a = sq3 * bond l2 = n * n + m * m + n * m l = sqrt(l2) nd = gcd(n, m) if (n - m) % (3 * nd) == 0: ndr = 3 * nd else: ndr = nd nr = (2 * m + n) // ndr ns = -(2 * n + m) // ndr nn = 2 * l2 // ndr ichk = 0 if nr == 0: n60 = 1 else: n60 = nr * 4 absn = abs(n60) nnp = [] nnq = [] for i in range(-absn, absn + 1): for j in range(-absn, absn + 1): j2 = nr * j - ns * i if j2 == 1: j1 = m * i - n * j if j1 > 0 and j1 < nn: ichk += 1 nnp.append(i) nnq.append(j) if ichk == 0: raise RuntimeError('not found p, q strange!!') if ichk >= 2: raise RuntimeError('more than 1 pair p, q strange!!') nnnp = nnp[0] nnnq = nnq[0] if verbose: print('the symmetry vector is', nnnp, nnnq) lp = nnnp * nnnp + nnnq * nnnq + nnnp * nnnq r = a * sqrt(lp) c = a * l t = sq3 * c / ndr if 2 * nn > nk: raise RuntimeError('parameter nk is too small!') rs = c / (2.0 * np.pi) if verbose: print('radius=', rs, t) q1 = np.arctan((sq3 * m) / (2 * n + m)) q2 = np.arctan((sq3 * nnnq) / (2 * nnnp + nnnq)) q3 = q1 - q2 q4 = 2.0 * np.pi / nn q5 = bond * np.cos((np.pi / 6.0) - q1) / c * 2.0 * np.pi h1 = abs(t) / abs(np.sin(q3)) h2 = bond * np.sin((np.pi / 6.0) - q1) ii = 0 x, y, z = [], [], [] for i in range(nn): x1, y1, z1 = 0, 0, 0 k = np.floor(i * abs(r) / h1) x1 = rs * np.cos(i * q4) y1 = rs * np.sin(i * q4) z1 = (i * abs(r) - k * h1) * np.sin(q3) kk2 = abs(np.floor((z1 + 0.0001) / t)) if z1 >= t - 0.0001: z1 -= t * kk2 elif z1 < 0: z1 += t * kk2 ii += 1 x.append(x1) y.append(y1) z.append(z1) z3 = (i * abs(r) - k * h1) * np.sin(q3) - h2 ii += 1 if z3 >= 0 and z3 < t: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - k * h1) * np.sin(q3) - h2 x.append(x2) y.append(y2) z.append(z2) else: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - (k + 1) * h1) * np.sin(q3) - h2 kk = abs(np.floor(z2 / t)) if z2 >= t - 0.0001: z2 -= t * kk elif z2 < 0: z2 += t * kk x.append(x2) y.append(y2) z.append(z2) ntotal = 2 * nn X = [] for i in range(ntotal): X.append([x[i], y[i], sign * z[i]]) if length > 1: xx = X[:] for mnp in range(2, length + 1): for i in range(len(xx)): X.append(xx[i][:2] + [xx[i][2] + (mnp - 1) * t]) transvec = t numatom = ntotal * length diameter = rs * 2 chiralangle = np.arctan((sq3 * n) / (2 * m + n)) / np.pi * 180 cell = [[0, 0, 0], [0, 0, 0], [0, 0, length * t]] atoms = Atoms(symbol + str(numatom), positions=X, cell=cell, pbc=[False, False, True]) if vacuum: atoms.center(vacuum, axis=(0, 1)) if verbose: print('translation vector =', transvec) print('diameter = ', diameter) print('chiral angle = ', chiralangle) return atoms
def _surface(symbol, structure, face, size, a, c, vacuum, orthogonal=True): """Function to build often used surfaces. Don't call this function directly - use fcc100, fcc110, bcc111, ...""" Z = atomic_numbers[symbol] if a is None: sym = reference_states[Z]['symmetry'] if sym != structure: raise ValueError("Can't guess lattice constant for %s-%s!" % (structure, symbol)) a = reference_states[Z]['a'] if structure == 'hcp' and c is None: if reference_states[Z]['symmetry'] == 'hcp': c = reference_states[Z]['c/a'] * a else: c = sqrt(8 / 3.0) * a positions = np.empty((size[2], size[1], size[0], 3)) positions[..., 0] = np.arange(size[0]).reshape((1, 1, -1)) positions[..., 1] = np.arange(size[1]).reshape((1, -1, 1)) positions[..., 2] = np.arange(size[2]).reshape((-1, 1, 1)) numbers = np.ones(size[0] * size[1] * size[2], int) * Z tags = np.empty((size[2], size[1], size[0]), int) tags[:] = np.arange(size[2], 0, -1).reshape((-1, 1, 1)) slab = Atoms(numbers, tags=tags.ravel(), pbc=(True, True, False), cell=size) surface_cell = None sites = {'ontop': (0, 0)} surf = structure + face if surf == 'fcc100': cell = (sqrt(0.5), sqrt(0.5), 0.5) positions[-2::-2, ..., :2] += 0.5 sites.update({'hollow': (0.5, 0.5), 'bridge': (0.5, 0)}) elif surf == 'diamond100': cell = (sqrt(0.5), sqrt(0.5), 0.5 / 2) positions[-4::-4, ..., :2] += (0.5, 0.5) positions[-3::-4, ..., :2] += (0.0, 0.5) positions[-2::-4, ..., :2] += (0.0, 0.0) positions[-1::-4, ..., :2] += (0.5, 0.0) elif surf == 'fcc110': cell = (1.0, sqrt(0.5), sqrt(0.125)) positions[-2::-2, ..., :2] += 0.5 sites.update({'hollow': (0.5, 0.5), 'longbridge': (0.5, 0), 'shortbridge': (0, 0.5)}) elif surf == 'bcc100': cell = (1.0, 1.0, 0.5) positions[-2::-2, ..., :2] += 0.5 sites.update({'hollow': (0.5, 0.5), 'bridge': (0.5, 0)}) else: if orthogonal and size[1] % 2 == 1: raise ValueError(("Can't make orthorhombic cell with size=%r. " % (tuple(size),)) + 'Second number in size must be even.') if surf == 'fcc111': cell = (sqrt(0.5), sqrt(0.375), 1 / sqrt(3)) if orthogonal: positions[-1::-3, 1::2, :, 0] += 0.5 positions[-2::-3, 1::2, :, 0] += 0.5 positions[-3::-3, 1::2, :, 0] -= 0.5 positions[-2::-3, ..., :2] += (0.0, 2.0 / 3) positions[-3::-3, ..., :2] += (0.5, 1.0 / 3) else: positions[-2::-3, ..., :2] += (-1.0 / 3, 2.0 / 3) positions[-3::-3, ..., :2] += (1.0 / 3, 1.0 / 3) sites.update({'bridge': (0.5, 0), 'fcc': (1.0 / 3, 1.0 / 3), 'hcp': (2.0 / 3, 2.0 / 3)}) elif surf == 'diamond111': cell = (sqrt(0.5), sqrt(0.375), 1 / sqrt(3) / 2) assert not orthogonal positions[-1::-6, ..., :3] += (0.0, 0.0, 0.5) positions[-2::-6, ..., :2] += (0.0, 0.0) positions[-3::-6, ..., :3] += (-1.0 / 3, 2.0 / 3, 0.5) positions[-4::-6, ..., :2] += (-1.0 / 3, 2.0 / 3) positions[-5::-6, ..., :3] += (1.0 / 3, 1.0 / 3, 0.5) positions[-6::-6, ..., :2] += (1.0 / 3, 1.0 / 3) elif surf == 'hcp0001': cell = (1.0, sqrt(0.75), 0.5 * c / a) if orthogonal: positions[:, 1::2, :, 0] += 0.5 positions[-2::-2, ..., :2] += (0.0, 2.0 / 3) else: positions[-2::-2, ..., :2] += (-1.0 / 3, 2.0 / 3) sites.update({'bridge': (0.5, 0), 'fcc': (1.0 / 3, 1.0 / 3), 'hcp': (2.0 / 3, 2.0 / 3)}) elif surf == 'hcp10m10': cell = (1.0, 0.5 * c / a, sqrt(0.75)) assert orthogonal positions[-2::-2, ..., 0] += 0.5 positions[:, ::2, :, 2] += 2.0 / 3 elif surf == 'bcc110': cell = (1.0, sqrt(0.5), sqrt(0.5)) if orthogonal: positions[:, 1::2, :, 0] += 0.5 positions[-2::-2, ..., :2] += (0.0, 1.0) else: positions[-2::-2, ..., :2] += (-0.5, 1.0) sites.update({'shortbridge': (0, 0.5), 'longbridge': (0.5, 0), 'hollow': (0.375, 0.25)}) elif surf == 'bcc111': cell = (sqrt(2), sqrt(1.5), sqrt(3) / 6) if orthogonal: positions[-1::-3, 1::2, :, 0] += 0.5 positions[-2::-3, 1::2, :, 0] += 0.5 positions[-3::-3, 1::2, :, 0] -= 0.5 positions[-2::-3, ..., :2] += (0.0, 2.0 / 3) positions[-3::-3, ..., :2] += (0.5, 1.0 / 3) else: positions[-2::-3, ..., :2] += (-1.0 / 3, 2.0 / 3) positions[-3::-3, ..., :2] += (1.0 / 3, 1.0 / 3) sites.update({'hollow': (1.0 / 3, 1.0 / 3)}) else: 2 / 0 surface_cell = a * np.array([(cell[0], 0), (cell[0] / 2, cell[1])]) if not orthogonal: cell = np.array([(cell[0], 0, 0), (cell[0] / 2, cell[1], 0), (0, 0, cell[2])]) if surface_cell is None: surface_cell = a * np.diag(cell[:2]) if isinstance(cell, tuple): cell = np.diag(cell) slab.set_positions(positions.reshape((-1, 3))) slab.set_cell([a * v * n for v, n in zip(cell, size)], scale_atoms=True) if vacuum is not None: slab.center(vacuum=vacuum, axis=2) slab.adsorbate_info['cell'] = surface_cell slab.adsorbate_info['sites'] = sites return slab
import numpy as np debug = False use_hdf5 = True try: import _gpaw_hdf5 restart_file = 'Al2_gs.hdf5' except ImportError: restart_file = 'Al2_gs.gpw' d = 2.563 atoms = Atoms('Al2', positions=((0, 0, 0), (0, 0, d)) ) atoms.center(4.0) calc = GPAW(h=0.24, eigensolver='cg', basis='dzp', occupations=FermiDirac(width=0.01), convergence={'eigenstates': 4.0e-5, 'density' : 1.0e-2, 'bands' : 'all'}, nbands=20) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write(restart_file, mode='all') # Try to run parallel over eh-pairs if size % 2 == 0: eh_size = 2 domain_size = size // eh_size else: eh_size = 1
def nanotube(n, m, length=1, bond=1.42, symbol='C', verbose=False): if n < m: m, n = n, m sign = -1 else: sign = 1 nk = 6000 sq3 = sqrt(3.0) a = sq3 * bond l2 = n * n + m * m + n * m l = sqrt(l2) nd = gcd(n, m) if (n - m) % (3 * nd) == 0: ndr = 3 * nd else: ndr = nd nr = (2 * m + n) / ndr ns = -(2 * n + m) / ndr nn = 2 * l2 / ndr ichk = 0 if nr == 0: n60 = 1 else: n60 = nr * 4 absn = abs(n60) nnp = [] nnq = [] for i in range(-absn, absn + 1): for j in range(-absn, absn + 1): j2 = nr * j - ns * i if j2 == 1: j1 = m * i - n * j if j1 > 0 and j1 < nn: ichk += 1 nnp.append(i) nnq.append(j) if ichk == 0: raise RuntimeError('not found p, q strange!!') if ichk >= 2: raise RuntimeError('more than 1 pair p, q strange!!') nnnp = nnp[0] nnnq = nnq[0] if verbose: print 'the symmetry vector is', nnnp, nnnq lp = nnnp * nnnp + nnnq * nnnq + nnnp * nnnq r = a * sqrt(lp) c = a * l t = sq3 * c / ndr if 2 * nn > nk: raise RuntimeError('parameter nk is too small!') rs = c / (2.0 * np.pi) if verbose: print 'radius=', rs, t q1 = np.arctan((sq3 * m) / (2 * n + m)) q2 = np.arctan((sq3 * nnnq) / (2 * nnnp + nnnq)) q3 = q1 - q2 q4 = 2.0 * np.pi / nn q5 = bond * np.cos((np.pi / 6.0) - q1) / c * 2.0 * np.pi h1 = abs(t) / abs(np.sin(q3)) h2 = bond * np.sin((np.pi / 6.0) - q1) ii = 0 x, y, z = [], [], [] for i in range(nn): x1, y1, z1 = 0, 0, 0 k = np.floor(i * abs(r) / h1) x1 = rs * np.cos(i * q4) y1 = rs * np.sin(i * q4) z1 = (i * abs(r) - k * h1) * np.sin(q3) kk2 = abs(np.floor((z1 + 0.0001) / t)) if z1 >= t - 0.0001: z1 -= t * kk2 elif z1 < 0: z1 += t * kk2 ii += 1 x.append(x1) y.append(y1) z.append(z1) z3 = (i * abs(r) - k * h1) * np.sin(q3) - h2 ii += 1 if z3 >= 0 and z3 < t: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - k * h1) * np.sin(q3) - h2 x.append(x2) y.append(y2) z.append(z2) else: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - (k + 1) * h1) * np.sin(q3) - h2 kk = abs(np.floor(z2 / t)) if z2 >= t - 0.0001: z2 -= t * kk elif z2 < 0: z2 += t * kk x.append(x2) y.append(y2) z.append(z2) ntotal = 2 * nn X = [] for i in range(ntotal): X.append([x[i], y[i], sign * z[i]]) if length > 1: xx = X[:] for mnp in range(2, length + 1): for i in range(len(xx)): X.append(xx[i][:2] + [xx[i][2] + (mnp - 1) * t]) TransVec = t NumAtom = ntotal * length Diameter = rs * 2 ChiralAngle = np.arctan((sq3 * n) / (2 * m + n)) / (np.pi * 180) cell = [Diameter * 2, Diameter * 2, length * t] atoms = Atoms(symbol + str(NumAtom), positions=X, cell=cell, pbc=[False, False, True]) atoms.center() if verbose: print 'translation vector =', TransVec print 'diameter = ', Diameter print 'chiral angle = ', ChiralAngle return atoms
class execution(object): def __init__(self, executionInput, xyz=None, stateFile='state.json'): ''' Setup a new execution Name: input file xyz: xyz coordinates (for future automated execution) stateFile: state file to use for tracking of executions TODO: - only ground state in non-periodic cell supported NOW, more to add! - inputs from a dict to better handle automated executions ''' if isinstance(executionInput, str): self.inp = self.json(executionInput) self.inputFileName = executionInput if isinstance(executionInput, dict): self.inp = executionInput self.inputFileName = 'dict' # TODO: generate meaningful name here (how?) self.setup() def setup(self): '''setup''' self.functional = self.inp.get('functional') or 'LDA' self.runtype = self.inp.get('runtype') or 'calc' # this actually can't be none! _xyz = self.inp.get('xyz') if isinstance(_xyz, str): self.inputXYZ = _xyz self.atoms = read(self.inputXYZ) else: # support reading frm a dict (TODO: other type of objects - ?) from ase.atoms import Atoms from ase.atom import Atom self.atoms = \ Atoms([Atom(a[0],(a[1],a[2],a[3])) for a in _xyz]) # TODO: support multiple cell types self.atoms.cell = (self.inp['cell']['x'], self.inp['cell']['y'], self.inp['cell']['z']) # Mixer setup - only "broyden" supported self.mixer = self.inp.get('mixer') if self.mixer is None: self.mixer = Mixer else: self.mixer = BroydenMixer # Custom ID: allow to trace parameter set using a custom id self.custom_id = self.inp.get('custom_id') # Periodic Boundary Conditions self.atoms.pbc = False # This should not be done always self.atoms.center() self.nbands = self.inp.get('nbands') self.gpts = None self.setup_gpts() self.max_iterations = self.inp.get('maxiter') or 333 # Name: to be set by __str__ first time it is run self.name = None # self.logExtension = 'txt' self.dataExtension = 'gpw' # Timing / statistics self.lastElapsed = None # def get_optimizer(self, name='QuasiNewton'): from importlib import import_module name = name.lower() _optimMap = \ { 'mdmin': 'MDMin', 'hesslbfgs': 'HessLBFGS', 'linelbfgs': 'LineLBFGS', 'fire': 'FIRE', 'lbfgs': 'LBFGS', 'lbfgsls': 'LBFGSLineSearch', 'bfgsls': 'BFGSLineSearch', 'bfgs': 'BFGS', 'quasinewton': 'QuasiNewton' } _class = _optimMap[name] _m = import_module('ase.optimize') return getattr(_m, _class) # def setup_gpts(self): self.gpts = h2gpts(self.inp.get('spacing') or 0.20, self.atoms.get_cell(), idiv=self.inp.get('idiv') or 8) def filename(self, force_id=None, extension='txt'): '''to correctly support this: stateFile support must be completed as it isn't just add "_0" to __str__() for now ''' base = self.__str__() if self.custom_id is not None: base = base + '_' + self.custom_id if force_id is None: _fn = base + '_0.' + extension else: _fn = '{}_{}.{}'.format(base, force_id, extension) return _fn # @property def xyz(self): return self.inp['xyz'] # @property def spacegroup(self): '''international ID of determined spacegroup''' sg = spglib.get_symmetry_dataset(spglib.refine_cell( self.atoms))['international'] return sg.replace('/', ':') # def __str__(self): '''get execution name - to be used for log filename Components: - Number atoms - Volume - Spacegroup number - Functional name ''' if self.name is None: self.name = '{}_{}_{}_{}'.format( len(self.atoms), int(self.atoms.get_volume() * 100), self.spacegroup, self.functional) _gpaw = os.environ['GPAW'] _pwd = os.environ['PWD'] self.procname = '{} ({})'.format(self.name, _pwd.replace(_gpaw + '/', '')) setproctitle(self.procname) return self.name ## def print(self, *args, **kwargs): '''print wrapper - initial step before logger''' r = print(*args, *kwargs) return r # def pretty(self): '''pretty print original parameters''' _p = pformat(self.inp) self.print(_p) # def json(self, filename): '''load parameters from json''' with open(filename, 'rb') as f: s = f.read() j = json.loads(s) return j # def run(self, force_id=None, runtype=None): ''' perform execution - only calc or optim supported now ''' _lastStart = time.time() if runtype is None and self.runtype is 'calc': _f = self.calc else: _f = self.optim # calculate try: result = _f(force_id) finally: _lastEnd = time.time() self.lastElapsed = _lastEnd - _lastStart return result # def calc(self, force_id=None, functional=None): '''prepare and launch execution force_id: use this id for filename generation ''' # Allow to override the funtional _fnl = functional or self.functional # generate filenames _fn = self.filename(force_id) _dn = self.filename(force_id, extension=self.dataExtension) self.print('Calculation with {} log and Input: {}.'.format( _fn, self.inputFileName)) if self.nbands is None: _calc = GPAW(xc=_fnl, txt=self.filename(force_id), mixer=self.mixer(), maxiter=self.max_iterations, gpts=self.gpts) else: _calc = GPAW(xc=_fnl, txt=self.filename(force_id), nbands=self.nbands, mixer=self.mixer(), maxiter=self.max_iterations, gpts=self.gpts) self.atoms.set_calculator(_calc) self.atoms.get_potential_energy() # write out wavefunctions _calc.write(_dn, 'all') return _calc ##### def optim(self, force_id=None, functional=None): '''prepare and launch execution force_id: use this id for filename generation ''' _optim_name = self.inp.get('optimizer') or 'QuasiNewton' optimizer = self.get_optimizer(_optim_name) # Allow to override the funtional _fnl = functional or self.functional # generate filenames _fn = self.filename(force_id) _dn = self.filename(force_id, extension=self.dataExtension) self.print('Optimization with {} log and Input: {}.'.format( _fn, self.inputFileName)) if self.nbands is None: _calc = GPAW(xc=_fnl, txt=self.filename(force_id), mixer=self.mixer(), maxiter=self.max_iterations, gpts=self.gpts) else: _calc = GPAW(xc=_fnl, txt=self.filename(force_id), nbands=self.nbands, mixer=self.mixer(), maxiter=self.max_iterations, gpts=self.gpts) self.atoms.set_calculator(_calc) self.opt = optimizer(self.atoms, trajectory=self.__str__() + '_emt.traj') self.opt.run(fmax=0.05) # write out wavefunctions _calc.write(_dn, 'all') return _calc
def graphene_nanoribbon(n, m, type='zigzag', saturated=False, C_H=1.09, C_C=1.42, vacuum=2.5, magnetic=None, initial_mag=1.12, sheet=False, main_element='C', saturate_element='H', vacc=None): """Create a graphene nanoribbon. Creates a graphene nanoribbon in the x-z plane, with the nanoribbon running along the z axis. Parameters: n: The width of the nanoribbon m: The length of the nanoribbon. type ('zigzag'): The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated (Falsi): If true, hydrogen atoms are placed along the edge. C_H: Carbon-hydrogen bond length. Default: 1.09 Angstrom C_C: Carbon-carbon bond length. Default: 1.42 Angstrom. vacuum: Amount of vacuum added to both sides. Default 2.5 Angstrom. magnetic: Make the edges magnetic. initial_mag: Magnitude of magnetic moment if magnetic=True. sheet: If true, make an infinite sheet instead of a ribbon. """ #This function creates the coordinates for a graphene nanoribbon, #n is width, m is length if vacc is not None: warnings.warn('Use vacuum=%f' % (0.5 * vacc)) vacuum = 0.5 * vacc assert vacuum > 0 b = sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + '4', pbc=(1, 0, 1), cell=[4 * b, 2 * vacuum, 3 * C_C]) arm_unit.positions = [[0, 0, 0], [b * 2, 0, C_C / 2.], [b * 2, 0, 3 * C_C / 2.], [0, 0, 2 * C_C]] zz_unit = Atoms(main_element + '2', pbc=(1, 0, 1), cell=[3 * C_C / 2., 2 * vacuum, b * 4]) zz_unit.positions = [[0, 0, 0], [C_C / 2., 0, b * 2]] atoms = Atoms() tol = 1e-4 if sheet: vacuum2 = 0.0 else: vacuum2 = vacuum if type == 'zigzag': edge_index0 = np.arange(m) * 2 + 1 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 if magnetic: mms = np.zeros(m * n * 2) for i in edge_index0: mms[i] = initial_mag for i in edge_index1: mms[i] = -initial_mag for i in range(n): layer = zz_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 3 * C_C / 2 * i if i % 2 == 1: layer.positions[:, 2] += 2 * b layer[-1].position[2] -= b * 4 * m atoms += layer if magnetic: atoms.set_initial_magnetic_moments(mms) if saturated: H_atoms0 = Atoms(saturate_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 0] += C_H H_atoms1 = Atoms(saturate_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 0] -= C_H atoms += H_atoms0 + H_atoms1 atoms.cell = [n * 3 * C_C / 2 + 2 * vacuum2, 2 * vacuum, m * 4 * b] elif type == 'armchair': for i in range(n): layer = arm_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 4 * b * i atoms += layer atoms.cell = [b * 4 * n + 2 * vacuum2, 2 * vacuum, 3 * C_C * m] atoms.center() atoms.set_pbc([sheet, False, True]) return atoms
def nanotube(n, m, length=1, bond=1.42, symbol="C", verbose=False): if n < m: m, n = n, m sign = -1 else: sign = 1 nk = 6000 sq3 = sqrt(3.0) a = sq3 * bond l2 = n * n + m * m + n * m l = sqrt(l2) dt = a * l / np.pi nd = gcd(n, m) if (n - m) % (3 * nd) == 0: ndr = 3 * nd else: ndr = nd nr = (2 * m + n) / ndr ns = -(2 * n + m) / ndr nt2 = 3 * l2 / ndr / ndr nt = np.floor(sqrt(nt2)) nn = 2 * l2 / ndr ichk = 0 if nr == 0: n60 = 1 else: n60 = nr * 4 absn = abs(n60) nnp = [] nnq = [] for i in range(-absn, absn + 1): for j in range(-absn, absn + 1): j2 = nr * j - ns * i if j2 == 1: j1 = m * i - n * j if j1 > 0 and j1 < nn: ichk += 1 nnp.append(i) nnq.append(j) if ichk == 0: raise RuntimeError("not found p, q strange!!") if ichk >= 2: raise RuntimeError("more than 1 pair p, q strange!!") nnnp = nnp[0] nnnq = nnq[0] if verbose: print "the symmetry vector is", nnnp, nnnq lp = nnnp * nnnp + nnnq * nnnq + nnnp * nnnq r = a * sqrt(lp) c = a * l t = sq3 * c / ndr if 2 * nn > nk: raise RuntimeError("parameter nk is too small!") rs = c / (2.0 * np.pi) if verbose: print "radius=", rs, t q1 = np.arctan((sq3 * m) / (2 * n + m)) q2 = np.arctan((sq3 * nnnq) / (2 * nnnp + nnnq)) q3 = q1 - q2 q4 = 2.0 * np.pi / nn q5 = bond * np.cos((np.pi / 6.0) - q1) / c * 2.0 * np.pi h1 = abs(t) / abs(np.sin(q3)) h2 = bond * np.sin((np.pi / 6.0) - q1) ii = 0 x, y, z = [], [], [] for i in range(nn): x1, y1, z1 = 0, 0, 0 k = np.floor(i * abs(r) / h1) x1 = rs * np.cos(i * q4) y1 = rs * np.sin(i * q4) z1 = (i * abs(r) - k * h1) * np.sin(q3) kk2 = abs(np.floor((z1 + 0.0001) / t)) if z1 >= t - 0.0001: z1 -= t * kk2 elif z1 < 0: z1 += t * kk2 ii += 1 x.append(x1) y.append(y1) z.append(z1) z3 = (i * abs(r) - k * h1) * np.sin(q3) - h2 ii += 1 if z3 >= 0 and z3 < t: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - k * h1) * np.sin(q3) - h2 x.append(x2) y.append(y2) z.append(z2) else: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - (k + 1) * h1) * np.sin(q3) - h2 kk = abs(np.floor(z2 / t)) if z2 >= t - 0.0001: z2 -= t * kk elif z2 < 0: z2 += t * kk x.append(x2) y.append(y2) z.append(z2) ntotal = 2 * nn X = [] for i in range(ntotal): X.append([x[i], y[i], sign * z[i]]) if length > 1: xx = X[:] for mnp in range(2, length + 1): for i in range(len(xx)): X.append(xx[i][:2] + [xx[i][2] + (mnp - 1) * t]) TransVec = t NumAtom = ntotal * length Diameter = rs * 2 ChiralAngle = np.arctan((sq3 * n) / (2 * m + n)) / (np.pi * 180) cell = [Diameter * 2, Diameter * 2, length * t] atoms = Atoms(symbol + str(NumAtom), positions=X, cell=cell, pbc=[False, False, True]) atoms.center() if verbose: print "translation vector =", TransVec print "diameter = ", Diameter print "chiral angle = ", ChiralAngle return atoms
def graphene_nanoribbon( n, m, type="zigzag", saturated=False, C_H=1.09, C_C=1.42, vacuum=2.5, magnetic=None, initial_mag=1.12, sheet=False, main_element="C", saturate_element="H", vacc=None, ): """Create a graphene nanoribbon. Creates a graphene nanoribbon in the x-z plane, with the nanoribbon running along the z axis. Parameters: n: The width of the nanoribbon m: The length of the nanoribbon. type ('zigzag'): The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated (Falsi): If true, hydrogen atoms are placed along the edge. C_H: Carbon-hydrogen bond length. Default: 1.09 Angstrom C_C: Carbon-carbon bond length. Default: 1.42 Angstrom. vacuum: Amount of vacuum added to both sides. Default 2.5 Angstrom. magnetic: Make the edges magnetic. initial_mag: Magnitude of magnetic moment if magnetic=True. sheet: If true, make an infinite sheet instead of a ribbon. """ # This function creates the coordinates for a graphene nanoribbon, # n is width, m is length if vacc is not None: warnings.warn("Use vacuum=%f" % (0.5 * vacc)) vacuum = 0.5 * vacc assert vacuum > 0 b = sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + "4", pbc=(1, 0, 1), cell=[4 * b, 2 * vacuum, 3 * C_C]) arm_unit.positions = [[0, 0, 0], [b * 2, 0, C_C / 2.0], [b * 2, 0, 3 * C_C / 2.0], [0, 0, 2 * C_C]] zz_unit = Atoms(main_element + "2", pbc=(1, 0, 1), cell=[3 * C_C / 2.0, 2 * vacuum, b * 4]) zz_unit.positions = [[0, 0, 0], [C_C / 2.0, 0, b * 2]] atoms = Atoms() tol = 1e-4 if sheet: vacuum2 = 0.0 else: vacuum2 = vacuum if type == "zigzag": edge_index0 = np.arange(m) * 2 + 1 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 if magnetic: mms = np.zeros(m * n * 2) for i in edge_index0: mms[i] = initial_mag for i in edge_index1: mms[i] = -initial_mag for i in range(n): layer = zz_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 3 * C_C / 2 * i if i % 2 == 1: layer.positions[:, 2] += 2 * b layer[-1].position[2] -= b * 4 * m atoms += layer if magnetic: atoms.set_initial_magnetic_moments(mms) if saturated: H_atoms0 = Atoms(saturate_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 0] += C_H H_atoms1 = Atoms(saturate_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 0] -= C_H atoms += H_atoms0 + H_atoms1 atoms.cell = [n * 3 * C_C / 2 + 2 * vacuum2, 2 * vacuum, m * 4 * b] elif type == "armchair": for i in range(n): layer = arm_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 4 * b * i atoms += layer atoms.cell = [b * 4 * n + 2 * vacuum2, 2 * vacuum, 3 * C_C * m] atoms.center() atoms.set_pbc([sheet, False, True]) return atoms
def graphene_nanoribbon(n, m, type='zigzag', saturated=False, C_H=1.09, C_C=1.42, vacuum=2.5, magnetic=None, initial_mag=1.12, sheet=False, main_element='C', saturate_element='H', vacc=None): """Create a graphene nanoribbon. Creates a graphene nanoribbon in the x-z plane, with the nanoribbon running along the z axis. Parameters: n: int The width of the nanoribbon. m: int The length of the nanoribbon. type: str The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated: bool If true, hydrogen atoms are placed along the edge. C_H: float Carbon-hydrogen bond length. Default: 1.09 Angstrom. C_C: float Carbon-carbon bond length. Default: 1.42 Angstrom. vacuum: float Amount of vacuum added to both sides. Default 2.5 Angstrom. magnetic: bool Make the edges magnetic. initial_mag: float Magnitude of magnetic moment if magnetic=True. sheet: bool If true, make an infinite sheet instead of a ribbon. """ if vacc is not None: warnings.warn('Use vacuum=%f' % (0.5 * vacc)) vacuum = 0.5 * vacc assert vacuum > 0 b = sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + '4', pbc=(1, 0, 1), cell=[4 * b, 2 * vacuum, 3 * C_C]) arm_unit.positions = [[0, 0, 0], [b * 2, 0, C_C / 2.], [b * 2, 0, 3 * C_C / 2.], [0, 0, 2 * C_C]] zz_unit = Atoms(main_element + '2', pbc=(1, 0, 1), cell=[3 * C_C / 2.0, 2 * vacuum, b * 4]) zz_unit.positions = [[0, 0, 0], [C_C / 2.0, 0, b * 2]] atoms = Atoms() if sheet: vacuum2 = 0.0 else: vacuum2 = vacuum if type == 'zigzag': edge_index0 = np.arange(m) * 2 + 1 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 if magnetic: mms = np.zeros(m * n * 2) for i in edge_index0: mms[i] = initial_mag for i in edge_index1: mms[i] = -initial_mag for i in range(n): layer = zz_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 3 * C_C / 2 * i if i % 2 == 1: layer.positions[:, 2] += 2 * b layer[-1].position[2] -= b * 4 * m atoms += layer if magnetic: atoms.set_initial_magnetic_moments(mms) if saturated: H_atoms0 = Atoms(saturate_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 0] += C_H H_atoms1 = Atoms(saturate_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 0] -= C_H atoms += H_atoms0 + H_atoms1 atoms.cell = [n * 3 * C_C / 2 + 2 * vacuum2, 2 * vacuum, m * 4 * b] elif type == 'armchair': for i in range(n): layer = arm_unit.repeat((1, 1, m)) layer.positions[:, 0] -= 4 * b * i atoms += layer if saturated: arm_right_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[4 * b, 2 * vacuum, 3 * C_C]) arm_right_saturation.positions = [ [- sqrt(3) / 2 * C_H, 0, C_H * 0.5], [- sqrt(3) / 2 * C_H, 0, 2 * C_C - C_H * 0.5]] arm_left_saturation = Atoms(saturate_element + '2', pbc=(1, 0, 1), cell=[4 * b, 2 * vacuum, 3 * C_C]) arm_left_saturation.positions = [ [b * 2 + sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5], [b * 2 + sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]] arm_right_saturation.positions[:, 0] -= 4 * b * (n - 1) atoms += arm_right_saturation.repeat((1, 1, m)) atoms += arm_left_saturation.repeat((1, 1, m)) atoms.cell = [b * 4 * n + 2 * vacuum2, 2 * vacuum, 3 * C_C * m] atoms.center() atoms.set_pbc([sheet, False, True]) return atoms
from gpaw import GPAW, FermiDirac from gpaw.mpi import world, size, rank from gpaw.lrtddft2 import LrTDDFT2 from gpaw.lrtddft2.lr_communicators import LrCommunicators from gpaw.test import equal from ase.atoms import Atoms debug = False restart_file = 'Al2_gs.gpw' d = 2.563 atoms = Atoms('Al2', positions=((0, 0, 0), (0, 0, d))) atoms.center(4.0) calc = GPAW(h=0.24, eigensolver='cg', basis='dzp', occupations=FermiDirac(width=0.01), convergence={ 'eigenstates': 4.0e-5, 'density': 1.0e-2, 'bands': 'all' }, nbands=20) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write(restart_file, mode='all') # Try to run parallel over eh-pairs if size % 2 == 0: eh_size = 2 domain_size = size // eh_size
if os.path.exists(base_dir) is not True: os.makedirs(base_dir) os.chdir(base_dir) calc = Vasp(restart=None, xc="vdw-df2", encut=800, kpts={ "gamma": True, "density": 5.0 }, setups="gw", ismear=0, sigma=0.001, ediff=1e-7, algo="Accurate") atoms = Atoms(symbols=mol.formula, positions=mol.positions, cell=mol.cell, pbc=[ True, ] * 3) atoms.cell[-1, -1] = start_guess atoms.center(axis=2) #center along z calc.set_atoms(atoms) calc.initialize(atoms) calc.clean() calc.write_input(atoms) # Done with the input os.chdir(curr_dir)
# + import numpy as np from ase.atoms import Atoms from ase.calculators.vasp import Vasp from ase.calculators.emt import EMT from ase.optimize import LBFGS from theforce.util.flake import generate_random_cluster from theforce.calculator.active import ActiveCalculator, kcal_mol # random cluster generation ngold = 20 min_dist = 2.5 positions = generate_random_cluster(ngold, min_dist) atoms = Atoms(numbers=ngold * [79], positions=positions) atoms.center(vacuum=5.) atoms.pbc = True # Ab initio calculator; for now we just use EMT instead of vasp # abinitio = Vasp(command="mpirun -n 16 vasp_std", directory='vasp') abinitio = EMT() # ML calculator active_kwargs = { 'calculator': abinitio, 'ediff': 1.0 * kcal_mol, # decrease for more accuracy but lower speed 'fdiff': 1.0 * kcal_mol, # decrease for more accuracy but lower speed 'kernel_kw': { 'cutoff': 6., 'lmax': 3, 'nmax': 3 },
from gpaw import GPAW from ase.atoms import Atoms atoms = Atoms("C", positions=[[0.0, 0.0, 0.0]]) atoms.center(vacuum=4.0) print(atoms) calc = GPAW(txt="-", hund=True) from ase.units import Hartree atoms.set_calculator(calc) Etot = atoms.get_potential_energy() # convert from eV to Ha print("Etot = %18.10f Ha\n" % (Etot / Hartree))