def _cubic_bulk(name, x, a): if x == 'fcc': atoms = Atoms(4 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0, 0.5, 0.5), (0.5, 0, 0.5), (0.5, 0.5, 0)]) elif x == 'diamond': atoms = _cubic_bulk(2 * name, 'zincblende', a) elif x == 'zincblende': atoms = Atoms(4 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.25, 0.25, 0.25), (0, 0.5, 0.5), (0.25, 0.75, 0.75), (0.5, 0, 0.5), (0.75, 0.25, 0.75), (0.5, 0.5, 0), (0.75, 0.75, 0.25)]) elif x == 'rocksalt': atoms = Atoms(4 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0, 0), (0, 0.5, 0.5), (0.5, 0.5, 0.5), (0.5, 0, 0.5), (0, 0, 0.5), (0.5, 0.5, 0), (0, 0.5, 0)]) else: raise RuntimeError return atoms
def read_pdb(fileobj, index=-1): """Read PDB files. The format is assumed to follow the description given in http://www.wwpdb.org/documentation/format32/sect9.html.""" if isinstance(fileobj, str): fileobj = open(fileobj) atoms = Atoms() positions = [] symbols = [] for line in fileobj.readlines(): if line.startswith('ATOM') or line.startswith('HETATM'): try: symbol = line[12:16].strip() # we assume that the second character is a label # in case that it is upper case if len(symbol) > 1 and symbol[1].isupper(): symbol = symbol[0] words = line[30:55].split() #charges.append(float(c)) symbols.append(symbol) positions.append( np.array( [float(words[0]), float(words[1]), float(words[2])])) except: print("Couldn't read entry in pdb") pass return Atoms(symbols=symbols, positions=positions)
def read_dacapo(filename): from ase_ext.io.pupynere import NetCDFFile nc = NetCDFFile(filename) dims = nc.dimensions vars = nc.variables cell = vars['UnitCell'][-1] try: magmoms = vars['InitialAtomicMagneticMoment'][:] except KeyError: magmoms = None try: tags = vars['AtomTags'][:] except KeyError: tags = None atoms = Atoms(scaled_positions=vars['DynamicAtomPositions'][-1], symbols=[(a + b).strip() for a, b in vars['DynamicAtomSpecies'][:]], cell=cell, magmoms=magmoms, tags=tags, pbc=True) try: energy = vars['TotalEnergy'][-1] force = vars['DynamicAtomForces'][-1] except KeyError: energy = None force = None calc = SinglePointCalculator(energy, force, None, None, atoms) ### Fixme magmoms atoms.set_calculator(calc) return atoms
def read_xsf(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) readline = fileobj.readline line = readline() if line.startswith('ANIMSTEPS'): nimages = int(line.split()[1]) line = readline() else: nimages = 1 if line.startswith('CRYSTAL'): pbc = True elif line.startswith('SLAB'): pbc = (True, True, Flase) elif line.startswith('POLYMER'): pbc = (True, False, Flase) else: pbc = False images = [] for n in range(nimages): cell = None if pbc: line = readline() assert line.startswith('PRIMVEC') cell = [] for i in range(3): cell.append([float(x) for x in readline().split()]) line = readline() assert line.startswith('PRIMCOORD') natoms = int(readline().split()[0]) numbers = [] positions = [] for a in range(natoms): line = readline().split() numbers.append(int(line[0])) positions.append([float(x) for x in line[1:]]) positions = np.array(positions) if len(positions[0]) == 3: forces = None else: positions = positions[:, :3] forces = positions[:, 3:] * Hartree image = Atoms(numbers, positions, cell=cell, pbc=pbc) if forces is not None: image.set_calculator(SinglePointCalculator(None, forces, None, None, image)) images.append(image) return images[index]
def read_xyz(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() L1 = lines[0].split() if len(L1) == 1: # del lines[:2] natoms = int(L1[0]) else: natoms = len(lines) energy=0 images = [] while len(lines) >= natoms: positions = [] symbols = [] forces = [] charges = [] L2 = lines[1].split() for line in lines[2:natoms+2]: linesplit = line.split() if len(linesplit)==5: symbol, x, y, z, c = linesplit[:5] charges.append(c) else: symbol, x, y, z = linesplit[:4] symbols.append(symbol) positions.append([float(x), float(y), float(z)]) if len(linesplit) > 9: fx,fy,fz = linesplit[7:10] forces.append([float(fx), float(fy), float(fz)]) cell=[] if forces==[]: forces=None if len(lines[1].split())>0: if len(lines[1].split("\""))>1: L = lines[1].split("\"")[1].split() else: L = lines[1].split() if len(L)>9: energy=float(L[9]) try: cell = ((float(L[0]),float(L[1]),float(L[2])),(float(L[3]),float(L[4]),float(L[5])),(float(L[6]),float(L[7]),float(L[8]))) except ValueError: cell = ((0,0,0),(0,0,0),(0,0,0)) images.append(Atoms(symbols=symbols, positions=positions,forces=forces, energy=energy,cell=cell)) else: images.append(Atoms(symbols=symbols, positions=positions,forces=forces, energy=energy)) if len(charges)>0: images[-1].set_charges(charges) del lines[:natoms + 2] if ((len(lines)>0) and (len(lines[0].split())>0)): natoms = int(lines[0].split()[0]) #return images[index] return images
def read_turbomole(filename='coord'): """Method to read turbomole coord file coords in bohr, atom types in lowercase, format: $coord x y z atomtype x y z atomtype f $end Above 'f' means a fixed atom. """ from ase_ext import Atoms, Atom from ase_ext.constraints import FixAtoms if isinstance(filename, str): f = open(filename) lines = f.readlines() atoms_pos = [] atom_symbols = [] dollar_count=0 myconstraints=[] for line in lines: if ('$' in line): dollar_count = dollar_count + 1 if (dollar_count >= 2): break else: x, y, z, symbolraw = line.split()[:4] symbolshort=symbolraw.strip() symbol=symbolshort[0].upper()+symbolshort[1:].lower() #print symbol atom_symbols.append(symbol) atoms_pos.append([float(x)*Bohr, float(y)*Bohr, float(z)*Bohr]) cols = line.split() if (len(cols) == 5): fixedstr = line.split()[4].strip() if (fixedstr == "f"): myconstraints.append(True) else: myconstraints.append(False) else: myconstraints.append(False) if type(filename) == str: f.close() atoms = Atoms(positions = atoms_pos, symbols = atom_symbols, pbc = False) c = FixAtoms(myconstraints) atoms.set_constraint(c) #print c return atoms
def read_cif(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) def search_key(fobj, key): for line in fobj: if key in line: return line return None def get_key(fobj, key, pos=1): line = search_key(fobj, key) if line: return float(line.split()[pos].split('(')[0]) return None a = get_key(fileobj, '_cell_length_a') b = get_key(fileobj, '_cell_length_b') c = get_key(fileobj, '_cell_length_c') alpha = pi * get_key(fileobj, '_cell_angle_alpha') / 180 beta = pi * get_key(fileobj, '_cell_angle_beta') / 180 gamma = pi * get_key(fileobj, '_cell_angle_gamma') / 180 va = a * np.array([1, 0, 0]) vb = b * np.array([cos(gamma), sin(gamma), 0]) cx = cos(beta) cy = (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma) cz = sqrt(1. - cx*cx - cy*cy) vc = c * np.array([cx, cy, cz]) cell = np.array([va, vb, vc]) atoms = Atoms(cell=cell) read = False for line in fileobj: if not read: if '_atom_site_disorder_group' in line: read = True else: word = line.split() if len(word) < 5: break symbol = word[1] pos = (float(word[2].split('(')[0]) * va + float(word[3].split('(')[0]) * vb + float(word[4].split('(')[0]) * vc ) atoms.append(Atom(symbol, pos)) return atoms
def read_vnl(filename): from io import StringIO vnl = VNLUnpickler(StringIO(ZipFile(filename).read('0_object'))).load() conf = vnl.data['__properties__']['Atomic Configuration'].data numbers = conf['_dataarray_'] positions = conf['_positions_'].data['_dataarray_'] return Atoms(numbers=numbers, positions=positions)
def bind(self, frame): if not self.ui.get_widget('/MenuBar/ViewMenu/ShowBonds').get_active(): self.bonds = np.empty((0, 5), int) return from ase_ext.atoms import Atoms from ase_ext.calculators.neighborlist import NeighborList nl = NeighborList(self.images.r * 1.5, skin=0, self_interaction=False) nl.update( Atoms(positions=self.images.P[frame], cell=(self.images.repeat[:, np.newaxis] * self.images.A[frame]), pbc=self.images.pbc)) nb = nl.nneighbors + nl.npbcneighbors self.bonds = np.empty((nb, 5), int) if nb == 0: return n1 = 0 for a in range(self.images.natoms): indices, offsets = nl.get_neighbors(a) n2 = n1 + len(indices) self.bonds[n1:n2, 0] = a self.bonds[n1:n2, 1] = indices self.bonds[n1:n2, 2:] = offsets n1 = n2 i = self.bonds[:n2, 2:].any(1) self.bonds[n2:, 0] = self.bonds[i, 1] self.bonds[n2:, 1] = self.bonds[i, 0] self.bonds[n2:, 2:] = -self.bonds[i, 2:]
def read_iwm(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() L1 = lines[1].split() if len(L1) == 1: del lines[:3] natoms = int(L1[0]) else: natoms = len(lines) images = [] positions = [] symbols = [] for line in lines[:natoms]: symbol, mass, x, y, z = line.split()[:5] if symbol in iwm_symbols: symbols.append(iwm_symbols[symbol]) else: symbols.append(chemical_symbols[int(symbol)]) positions.append([float(x), float(y), float(z)]) del (lines[natoms:3 * natoms + 3]) cell = [] for line in lines[natoms:natoms + 3]: x, y, z = line.split()[:3] cell.append(np.array([float(x), float(y), float(z)])) images.append(Atoms(symbols=symbols, positions=positions, cell=cell)) return images[index]
def make_test_dft_calculation(): a = b = 2.0 c = 6.0 atoms = Atoms(positions=[(0, 0, c / 2)], symbols='H', pbc=(1, 1, 0), cell=(a, b, c), calculator=TestCalculator()) return atoms
def read_I_info(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() del lines[0] finished = False s = Atoms() while not finished: w = lines.pop(0).split() if w[0].startswith('"'): position = Bohr * np.array([float(w[3]), float(w[4]), float(w[5])]) s.append(Atom(w[0].replace('"', ''), position)) else: finished = True return s
def read_dacapo_text(fileobj): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() i = lines.index(' Structure: A1 A2 A3\n') cell = np.array([[float(w) for w in line.split()[2:5]] for line in lines[i + 1:i + 4]]).transpose() i = lines.index(' Structure: >> Ionic positions/velocities ' + 'in cartesian coordinates <<\n') atoms = [] for line in lines[i + 4:]: words = line.split() if len(words) != 9: break Z, x, y, z = words[2:6] atoms.append(Atom(int(Z), [float(x), float(y), float(z)])) atoms = Atoms(atoms, cell=cell.tolist()) try: i = lines.index( ' DFT: CPU time Total energy\n') except ValueError: pass else: column = lines[i + 3].split().index('selfcons') - 1 try: i2 = lines.index(' ANALYSIS PART OF CODE\n', i) except ValueError: pass else: while i2 > i: if lines[i2].startswith(' DFT:'): break i2 -= 1 energy = float(lines[i2].split()[column]) atoms.set_calculator( SinglePointCalculator(energy, None, None, None, atoms)) return atoms
def _orthorhombic_bulk(name, x, a, covera=None): if x == 'fcc': b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif x == 'bcc': atoms = Atoms(2 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif x == 'hcp': atoms = Atoms(4 * name, cell=(a, a * sqrt(3), covera * a), scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 1.0 / 6.0, 0.5), (0, 2.0 / 3.0, 0.5)], pbc=True) elif x == 'diamond': atoms = _orthorhombic_bulk(2 * name, 'zincblende', a) elif x == 'zincblende': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0, 0.25), (0.5, 0.5, 0.5), (0, 0.5, 0.75)]) elif x == 'rocksalt': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 0.5, 0.5), (0, 0, 0.5)]) else: raise RuntimeError return atoms
def __getitem__(self, i=-1): N = len(self.offsets) if 0 <= i < N: self.fd.seek(self.offsets[i]) try: d = pickle.load(self.fd) except EOFError: raise IndexError if i == N - 1: self.offsets.append(self.fd.tell()) try: magmoms = d['magmoms'] except KeyError: magmoms = None atoms = Atoms(positions=d['positions'], numbers=self.numbers, cell=d['cell'], momenta=d['momenta'], magmoms=magmoms, tags=self.tags, masses=self.masses, pbc=self.pbc, constraint=[c.copy() for c in self.constraints]) if 'energy' in d: calc = SinglePointCalculator(d.get('energy', None), d.get('forces', None), d.get('stress', None), magmoms, atoms) atoms.set_calculator(calc) return atoms if i >= N: for j in range(N - 1, i + 1): atoms = self[j] return atoms i = len(self) + i if i < 0: raise IndexError('Trajectory index out of range.') return self[i]
def copy(self): from ase_ext.atoms import Atoms return Atoms(positions=self.get_positions(), numbers=self.get_atomic_numbers(), tags=self.get_tags(), momenta=self.get_momenta(), masses=self.get_masses(), magmoms=self.get_initial_magnetic_moments(), charges=self.get_charges(), cell=self.get_cell(), pbc=self.get_pbc(), constraint=None, calculator=None) # Don't copy the calculator
def read_mol(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() del (lines[:3]) L1 = lines[0].split() del (lines[0]) natoms = int(L1[0]) positions = [] symbols = [] for line in lines[:natoms]: x, y, z, symbol = line.split()[:4] symbols.append(symbol) positions.append([float(x), float(y), float(z)]) return Atoms(symbols=symbols, positions=positions)
def read_exciting(fileobj, index=-1): """Reads structure from exiting xml file. Parameters ---------- fileobj: file object Filehandle from which data should be read. Other parameters ---------------- index: integer -1 Not used in this implementation. """ from lxml import etree as ET #parse file into element tree doc = ET.parse(fileobj) root = doc.getroot() speciesnodes = root.find('structure').getiterator('species') symbols = [] positions = [] basevects = [] atoms = None #collect data from tree for speciesnode in speciesnodes: symbol = speciesnode.get('speciesfile').split('.')[0] natoms = speciesnode.getiterator('atom') for atom in natoms: x, y, z = atom.get('coord').split() positions.append([float(x), float(y), float(z)]) symbols.append(symbol) basevectsn = doc.xpath('//basevect/text()') for basevect in basevectsn: x, y, z = basevect.split() basevects.append([float(x) * Bohr, float(y) * Bohr, float(z) * Bohr]) atoms = Atoms(symbols=symbols, cell=basevects) atoms.set_scaled_positions(positions) if 'molecule' in list(root.find('structure').attrib.keys()): if root.find('structure').attrib['molecule']: atoms.set_pbc(False) else: atoms.set_pbc(True) return atoms
def read_sdf(fileobj): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() # first three lines header del lines[:3] # L1 = lines.pop(0).split() natoms = int(L1[0]) positions = [] symbols = [] for line in lines[:natoms]: x, y, z, symbol = line.split()[:4] symbols.append(symbol) positions.append([float(x), float(y), float(z)]) return Atoms(symbols=symbols, positions=positions)
def run(opt, args): images = Images() if opt.aneb: opt.image_number = '-1' if len(args) > 0: from ase_ext.io import string2index images.read(args, string2index(opt.image_number)) else: images.initialize([Atoms()]) if opt.interpolate: images.interpolate(opt.interpolate) if opt.aneb: images.aneb() if opt.repeat != '1': r = opt.repeat.split(',') if len(r) == 1: r = 3 * r images.repeat_images([int(c) for c in r]) if opt.output is not None: images.write(opt.output, rotations=opt.rotations, show_unit_cell=opt.show_unit_cell) opt.terminal = True if opt.terminal: if opt.graph is not None: data = images.graph(opt.graph) for line in data.T: for x in line: print(x, end=' ') print() else: from ase_ext.gui.gui import GUI gui = GUI(images, opt.rotations, opt.show_unit_cell, opt.bonds) gui.run(opt.graph)
def read_cube(fileobj, index=-1, read_data=False): if isinstance(fileobj, str): fileobj = open(fileobj) readline = fileobj.readline readline() axes = ['XYZ'.index(s[0]) for s in readline().split()[2::3]] if axes == []: axes = [0, 1, 2] line = readline().split() natoms = int(line[0]) corner = [Bohr * float(x) for x in line[1:]] cell = np.empty((3, 3)) shape = [] for i in range(3): n, x, y, z = [float(s) for s in readline().split()] shape.append(n) if n % 2 == 1: n += 1 cell[i] = n * Bohr * np.array([x, y, z]) numbers = np.empty(natoms, int) positions = np.empty((natoms, 3)) for i in range(natoms): line = readline().split() numbers[i] = int(line[0]) positions[i] = [float(s) for s in line[2:]] positions *= Bohr atoms = Atoms(numbers=numbers, positions=positions, cell=cell) if read_data: data = np.array([float(s) for s in fileobj.read().split()]).reshape(shape) if axes != [0, 1, 2]: data = data.transpose(axes).copy() return data, atoms return atoms
def get_atoms(self, frame): atoms = Atoms(positions=self.P[frame], numbers=self.Z, magmoms=self.M[0], tags=self.T, cell=self.A[frame], pbc=self.pbc) # check for constrained atoms and add them accordingly: if not self.dynamic.all(): atoms.set_constraint(FixAtoms(mask=1 - self.dynamic)) atoms.set_calculator( SinglePointCalculator(self.E[frame], self.F[frame], None, None, atoms)) return atoms
def bulk(name, crystalstructure, a=None, c=None, covera=None, orthorhombic=False, cubic=False): """Helper function for creating bulk systems. name: str Chemical symbol or symbols as in 'MgO' or 'NaCl'. crystalstructure: str Must be one of sc, fcc, bcc, hcp, diamond, zincblende or rocksalt. a: float Lattice constant. c: float Lattice constant. covera: float c/a raitio used for hcp. Defaults to ideal ratio. orthorhombic: bool Construct orthorhombic unit cell instead of primitive cell which is the default. cubic: bool Construct cubic unit cell. """ if covera is not None and c is not None: raise ValueError("Don't specify both c and c/a!") if covera is None and c is None: covera = sqrt(8.0 / 3.0) if a is None: a = estimate_lattice_constant(name, crystalstructure, covera) if covera is None and c is not None: covera = c / a x = crystalstructure.lower() if orthorhombic and x != 'sc': return _orthorhombic_bulk(name, x, a, covera) if cubic and x == 'bcc': return _orthorhombic_bulk(name, x, a, covera) if cubic and x != 'sc': return _cubic_bulk(name, x, a) if x == 'sc': atoms = Atoms(name, cell=(a, a, a), pbc=True) elif x == 'fcc': b = a / 2 atoms = Atoms(name, cell=[(0, b, b), (b, 0, b), (b, b, 0)], pbc=True) elif x == 'bcc': b = a / 2 atoms = Atoms(name, cell=[(-b, b, b), (b, -b, b), (b, b, -b)], pbc=True) elif x == 'hcp': atoms = Atoms(2 * name, scaled_positions=[(0, 0, 0), (1.0 / 3.0, 1.0 / 3.0, 0.5)], cell=[(a, 0, 0), (a / 2, a * sqrt(3) / 2, 0), (0, 0, covera * a)], pbc=True) elif x == 'diamond': atoms = bulk(2 * name, 'zincblende', a) elif x == 'zincblende': s1, s2 = string2symbols(name) atoms = bulk(s1, 'fcc', a) + bulk(s2, 'fcc', a) atoms.positions[1] += a / 4 elif x == 'rocksalt': s1, s2 = string2symbols(name) atoms = bulk(s1, 'fcc', a) + bulk(s2, 'fcc', a) atoms.positions[1, 0] += a / 2 else: raise ValueError('Unknown crystal structure: ' + crystalstructure) return atoms
def nanotube(n, m, length=1, bond=1.42, symbol='C', verbose=False): if n < m: m, n = n, m 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], 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 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 read_dftb(filename='dftb_in.hsd'): """Method to read coordinates form DFTB+ input file dftb_in.hsd additionally read information about fixed atoms and periodic boundary condition """ from ase_ext import Atoms, Atom from ase_ext.constraints import FixAtoms import sys, string if isinstance(filename, str): f = open(filename) lines = f.readlines() atoms_pos = [] atom_symbols = [] type_names = [] my_pbc = False myconstraints = [] moved_atoms_found = False range_found = False moved_atoms = [] for line in lines: if (line.strip().startswith('#')): pass else: if ('TypeNames' in line): col = line.split() for i in range(3, len(col) - 1): type_names.append(col[i].strip("\"")) elif ('Periodic' in line): if ('Yes' in line): my_pbc = True else: pass start_reading_coords = False stop_reading_coords = False for line in lines: if (line.strip().startswith('#')): pass else: if ('TypesAndCoordinates' in line): start_reading_coords = True if start_reading_coords: if ('}' in line): stop_reading_coords = True if (start_reading_coords and not (stop_reading_coords) and not 'TypesAndCoordinates' in line): typeindexstr, x, y, z = line.split()[:4] typeindex = int(typeindexstr) symbol = type_names[typeindex - 1] atom_symbols.append(symbol) atoms_pos.append([float(x), float(y), float(z)]) if type(filename) == str: f.close() atoms = Atoms(positions=atoms_pos, symbols=atom_symbols, pbc=my_pbc) return atoms
def read(filename, index=-1, format=None): """Read Atoms object(s) from file. filename: str Name of the file to read from. index: int or slice If the file contains several configurations, the last configuration will be returned by default. Use index=n to get configuration number n (counting from zero). format: str Used to specify the file-format. If not given, the file-format will be guessed by the *filetype* function. Known formats: ========================= =========== format short name ========================= =========== GPAW restart-file gpw Dacapo netCDF output file dacapo Old ASE netCDF trajectory nc Virtual Nano Lab file vnl ASE pickle trajectory traj GPAW text output gpaw-text CUBE file cube XCrySDen Structure File xsf Dacapo text output dacapo-text XYZ-file xyz VASP POSCAR/CONTCAR file vasp VASP OUTCAR file vasp_out Protein Data Bank pdb FHI-aims geometry file aims FHI-aims output file aims_out VTK XML Image Data vti VTK XML Structured Grid vts VTK XML Unstructured Grid vtu TURBOMOLE coord file tmol exciting input exi AtomEye configuration cfg WIEN2k structure file struct DftbPlus input file dftb SYBYL mol file mol2 ========================= =========== """ if isinstance(filename, str): p = filename.rfind('@') if p != -1: try: index = string2index(filename[p + 1:]) except ValueError: pass else: filename = filename[:p] if isinstance(index, str): index = string2index(index) if format is None: format = filetype(filename) if format.startswith('gpw'): import gpaw r = gpaw.io.open(filename, 'r') positions = r.get('CartesianPositions') * Bohr numbers = r.get('AtomicNumbers') cell = r.get('UnitCell') * Bohr pbc = r.get('BoundaryConditions') tags = r.get('Tags') magmoms = r.get('MagneticMoments') atoms = Atoms(positions=positions, numbers=numbers, cell=cell, pbc=pbc) if tags.any(): atoms.set_tags(tags) if magmoms.any(): atoms.set_initial_magnetic_moments(magmoms) return atoms if format == 'exi': from ase_ext.io.exciting import read_exciting return read_exciting(filename, index) if format == 'mol2': from ase_ext.io.mol2 import read_mol2 return read_mol2(filename, index) if format == 'xyz': from ase_ext.io.xyz import read_xyz return read_xyz(filename, index) if format == 'quipxyz': from ase_ext.io.quipxyz import read_xyz return read_xyz(filename, index) if format == 'traj': from ase_ext.io.trajectory import read_trajectory return read_trajectory(filename, index) if format == 'cube': from ase_ext.io.cube import read_cube return read_cube(filename, index) if format == 'nc': from ase_ext.io.netcdf import read_netcdf return read_netcdf(filename, index) if format == 'gpaw-text': from ase_ext.io.gpawtext import read_gpaw_text return read_gpaw_text(filename, index) if format == 'dacapo-text': from ase_ext.io.dacapo import read_dacapo_text return read_dacapo_text(filename) if format == 'dacapo': from ase_ext.io.dacapo import read_dacapo return read_dacapo(filename) if format == 'xsf': from ase_ext.io.xsf import read_xsf return read_xsf(filename, index) if format == 'vasp': from ase_ext.io.vasp import read_vasp return read_vasp(filename) if format == 'vasp_out': from ase_ext.io.vasp import read_vasp_out return read_vasp_out(filename, index) if format == 'mol': from ase_ext.io.mol import read_mol return read_mol(filename) if format == 'pdb': from ase_ext.io.pdb import read_pdb return read_pdb(filename) if format == 'cif': from ase_ext.io.cif import read_cif return read_cif(filename) if format == 'struct': from ase_ext.io.wien2k import read_struct return read_struct(filename) if format == 'vti': from ase_ext.io.vtkxml import read_vti return read_vti(filename) if format == 'vts': from ase_ext.io.vtkxml import read_vts return read_vts(filename) if format == 'vtu': from ase_ext.io.vtkxml import read_vtu return read_vtu(filename) if format == 'aims': from ase_ext.io.aims import read_aims return read_aims(filename) if format == 'aims_out': from ase_ext.io.aims import read_aims_output return read_aims_output(filename, index) if format == 'iwm': from ase_ext.io.iwm import read_iwm return read_iwm(filename) if format == 'Cmdft': from ase_ext.io.cmdft import read_I_info return read_I_info(filename) if format == 'tmol': from ase_ext.io.turbomole import read_turbomole return read_turbomole(filename) if format == 'cfg': from ase_ext.io.cfg import read_cfg return read_cfg(filename) if format == 'dftb': from ase_ext.io.dftb import read_dftb return read_dftb(filename) if format == 'sdf': from ase_ext.io.sdf import read_sdf return read_sdf(filename) raise RuntimeError('File format descriptor ' + format + ' not recognized!')
def read_netcdf(filename, index=-1): nc = NetCDFFile(filename) dims = nc.dimensions vars = nc.variables positions = vars['CartesianPositions'] numbers = vars['AtomicNumbers'][:] pbc = vars['BoundaryConditions'][:] cell = vars['UnitCell'] tags = vars['Tags'][:] if not tags.any(): tags = None magmoms = vars['MagneticMoments'][:] if not magmoms.any(): magmoms = None nimages = positions.shape[0] attach_calculator = False if 'PotentialEnergy' in vars: energy = vars['PotentialEnergy'] attach_calculator = True else: energy = nimages * [None] if 'CartesianForces' in vars: forces = vars['CartesianForces'] attach_calculator = True else: forces = nimages * [None] if 'Stress' in vars: stress = vars['Stress'] attach_calculator = True else: stress = nimages * [None] if isinstance(index, int): indices = [index] else: indices = list(range(nimages))[index] images = [] for i in indices: atoms = Atoms(positions=positions[i], numbers=numbers, cell=cell[i], pbc=pbc, tags=tags, magmoms=magmoms) if attach_calculator: calc = SinglePointCalculator(energy[i], forces[i], stress[i], None, atoms) ### Fixme magmoms atoms.set_calculator(calc) images.append(atoms) if isinstance(index, int): return images[0] else: return images
def graphene_nanoribbon(n, m, side='zigzag', saturated="no", C_H=1.09, C_C=1.42, vacc=5., magnetic=None, initial_mag=1.12, sheet=False, main_element='C', satur_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: The width of the nanoribbon m: The length of the nanoribbon. side ('zigzag'): The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated (no/yes/side): If yes, hydrogen atoms are placed along the edges. If side, then only 2 sides are saturated. C_H: Carbon-hydrogen bond length. Default: 1.09 Angstrom C_C: Carbon-carbon bond length. Default: 1.42 Angstrom. vacc: Amount of vacuum. Default 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 b = sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + '4', pbc=(1, 0, 1), cell=[4 * b, vacc, 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., vacc, b * 4]) zz_unit.positions = [[0, 0, 0], [C_C / 2., 0, b * 2]] atoms = Atoms() tol = 1e-4 if sheet: vacc2 = 0.0 else: vacc2 = vacc if side == 'zigzag': edge_index0 = np.arange(m) * 2 + 1 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 edge_index2 = [] edge_index3 = [] for i in range(0, n, 2): edge_index2.append(i * m * 2) edge_index3.append((i + 1) * m * 2 - 1) if i > 1: edge_index2.append(i * m * 2 - 1) edge_index3.append(i * m * 2 - 2) edge_index2 = np.array(edge_index2) edge_index3 = np.array(edge_index3) 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 != "no": H_atoms0 = Atoms(satur_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 0] += C_H H_atoms1 = Atoms(satur_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 0] -= C_H H_atoms2 = Atoms(satur_element + str(n)) H_atoms2.positions = atoms[edge_index2].positions H_atoms2.positions[:, 2] -= C_H H_atoms3 = Atoms(satur_element + str(n)) H_atoms3.positions = atoms[edge_index3].positions H_atoms3.positions[:, 2] += C_H if saturated == "yes": atoms += H_atoms0 + H_atoms1 + H_atoms2 + H_atoms3 if saturated == "side": atoms += H_atoms0 + H_atoms1 atoms.cell = [n * 3 * C_C / 2 + vacc2, vacc + 5.0, m * 4 * b] elif side == '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 + vacc2, vacc, 3 * C_C * m] atoms.center() atoms.set_pbc([sheet, False, True]) return atoms
def add_adsorbate(slab, adsorbate, height, position=(0, 0), offset=None, mol_index=0): """Add an adsorbate to a surface. This function adds an adsorbate to a slab. If the slab is produced by one of the utility functions in ase_ext.lattice.surface, it is possible to specify the position of the adsorbate by a keyword (the supported keywords depend on which function was used to create the slab). If the adsorbate is a molecule, the atom indexed by the mol_index optional argument is positioned on top of the adsorption position on the surface, and it is the responsibility of the user to orient the adsorbate in a sensible way. This function can be called multiple times to add more than one adsorbate. Parameters: slab: The surface onto which the adsorbate should be added. adsorbate: The adsorbate. Must be one of the following three types: A string containing the chemical symbol for a single atom. An atom object. An atoms object (for a molecular adsorbate). height: Height above the surface. position: The x-y position of the adsorbate, either as a tuple of two numbers or as a keyword (if the surface is produced by one of the functions in ase_ext.lattice.surfaces). offset (default: None): Offsets the adsorbate by a number of unit cells. Mostly useful when adding more than one adsorbate. mol_index (default: 0): If the adsorbate is a molecule, index of the atom to be positioned above the location specified by the position argument. Note *position* is given in absolute xy coordinates (or as a keyword), whereas offset is specified in unit cells. This can be used to give the positions in units of the unit cell by using *offset* instead. """ info = slab.adsorbate_info if 'cell' not in info: info['cell'] = slab.get_cell()[:2,:2] pos = np.array([0.0, 0.0]) # (x, y) part spos = np.array([0.0, 0.0]) # part relative to unit cell if offset is not None: spos += np.asarray(offset, float) if isinstance(position, str): # A site-name: if 'sites' not in info: raise TypeError('If the atoms are not made by an ' + 'ase.lattice.surface function, ' + 'position cannot be a name.') if position not in info['sites']: raise TypeError('Adsorption site %s not supported.' % position) spos += info['sites'][position] else: pos += position pos += np.dot(spos, info['cell']) # Convert the adsorbate to an Atoms object if isinstance(adsorbate, Atoms): ads = adsorbate elif isinstance(adsorbate, Atom): ads = Atoms([adsorbate]) else: # Hope it is a useful string or something like that ads = Atoms(adsorbate) # Get the z-coordinate: try: a = info['top layer atom index'] except KeyError: a = slab.positions[:, 2].argmax() info['top layer atom index']= a z = slab.positions[a, 2] + height # Move adsorbate into position ads.translate([pos[0], pos[1], z] - ads.positions[mol_index]) # Attach the adsorbate slab.extend(ads)