def get_geometry(mol): """ extract atomlist from block with title 'molecule' """ atoms = mol.get("geometry") atomlist = [] for atom in atoms: atname = atom.get("atom") atnumber = AtomicData.atomic_number(str(atname)) coords = atom.get("xyz") if mol.get("units", "Angstrom") == "Angstrom": coords = [xyz/AtomicData.bohr_to_angs for xyz in coords] atomlist.append( (atnumber, coords) ) return atomlist
def load_hotbit_pseudoatom(elmfile): """ load description of pseudo atom from a hotbit element (.elm) file Parameters: =========== elmfile: path to element description Returns: ======== atom module with data stored as members """ Data = parseHotbitParameters(elmfile) class Atom: pass atom = Atom() atom.Z = AtomicData.atomic_number(Data["atom_name"]) atom.energies = [] atom.valence_orbitals = [] atom.nshell = [] atom.angular_momenta = [] atom.orbital_occupation = [] atom.r = None atom.radial_wavefunctions = [] spectr2l = {"s": 0, "p": 1, "d": 2, "f": 3, "g": 4, "h": 5, "i": 6} for k in Data.keys(): if "orbital_energy" in k: atom.energies.append(float(Data[k])) dummy, spectr = k.rsplit("_", 1) n = int(spectr[0]) l = int(spectr2l[spectr[1]]) occnr = AtomicData.valence_occ_numbers[Data["atom_name"]] if occnr.has_key(spectr): atom.orbital_occupation.append(occnr[spectr]) else: atom.orbital_occupation.append(0) atom.valence_orbitals.append(len(atom.valence_orbitals)) atom.nshell.append(n) atom.angular_momenta.append(l) if Data.has_key("radial_wavefunction_%s" % spectr): atom.r = Data["radial_wavefunction_%s" % spectr][:, 0] atom.radial_wavefunctions.append( Data["radial_wavefunction_%s" % spectr][:, 1]) atom.hubbard_U = Data["hubbard_U"] return atom
def __init__(self, symbols, coordinates, tstep, nstates, charge, sc_threshold=0.001): # build list of atoms atomlist = [] for s, xyz in zip(symbols, coordinates): Z = AtomicData.atomic_number(s) atomlist.append((Z, xyz)) self.dt_nuc = tstep # nuclear time step in a.u. self.nstates = nstates # number of electronic states including the ground state self.sc_threshold = sc_threshold # threshold for coefficients that are included in the # computation of the scalar coupling self.Nat = len(atomlist) self.masses = AtomicData.atomlist2masses(atomlist) self.pes = PotentialEnergySurfaces(atomlist, nstates, charge=charge) # save results from last step self.last_step = None
def process(self, l): # Which kind of information should be read? l = l.strip() if self.read == None: if l == "coordinates": self.read = "C" return elif self.read == "C": if l == "velocities": self.read = "V" return # Read coordinates or velocities line by line if self.read == "C": atom, X, Y, Z = l.split() Zi = AtomicData.atomic_number(atom) # positions in bohr pos = float(X), float(Y), float(Z) self.atomlist.append((Zi, pos)) elif self.read == "V": vx, vy, vz = l.split() vel = float(vx), float(vy), float(vz) self.velocities.append(vel)
def read_slakoformat_par(parfile, atom_order="AB"): """ read table for S and H in the format used by hotbit (https://trac.cc.jyu.fi/projects/hotbit) Paramters: ========== parfile: path to <atom1>_<atom2>.par Returns: ======== sk The Slater Koster data is stored in attributes of sk: sk.Z1, sk.Z2, sk.d, sk.S, sk.H """ from os.path import basename at1, at2 = basename(parfile).replace(".par", "").split("_") if atom_order == "BA": tmp = at1 at1 = at2 at2 = tmp data_blocks = parseHotbitParameters(parfile) data_AB = data_blocks["slako_integrals_%s_%s" % (at1, at2)] data_BA = data_blocks["slako_integrals_%s_%s" % (at2, at1)] m, n = data_AB.shape assert data_AB.shape == data_BA.shape d = data_AB[:, 0] assert np.all(data_AB[:, 0] == data_BA[:, 0]) sk = SlakoModule() sk.Z1 = AtomicData.atomic_number(at1) sk.Z2 = AtomicData.atomic_number(at2) sk.d = d sk.S = {} sk.H = {} S = sk.S H = sk.H for pos, (tausym_AB, tausym_BA) in enumerate( zip(T.tausymbols_AB[-n:], T.tausymbols_BA[-n:])): try: tau_AB = T.symbol2tau[tausym_AB] tau_BA = T.symbol2tau[tausym_BA] except KeyError: continue # AB l1, l2 = tau_AB[0], tau_AB[2] H[(l1, l2, T.tau2index[tau_AB])] = data_AB[:, pos + 1] S[(l1, l2, T.tau2index[tau_AB])] = data_AB[:, len(T.tausymbols_AB) + pos + 1] # BA l1, l2 = tau_BA[0], tau_BA[2] ## if sk.Z1 == sk.Z2: # I think this is the right condition if sk.Z1 > 1 and sk.Z2 > 1: # but with this illogical condition I can reproduce Roland's results for HCNO compounds orbital_parity = pow(-1, l1 + l2) else: orbital_parity = 1 H[(l1, l2, T.tau2index[tau_BA])] = orbital_parity * data_BA[:, pos + 1] S[(l1, l2, T.tau2index[tau_BA] )] = orbital_parity * data_BA[:, len(T.tausymbols_BA) + pos + 1] return sk
def read_slakoformat_skf(skfile, sk=None, atom_order="AB"): """ read table for S and H in the format used by DFTB+ see http://www.dftb.org/fileadmin/DFTB/public/misc/slakoformat.pdf Parameters: =========== skfile: path to <atom 1>-<atom 2>.skf sk: slako_module loaded from a different file, to which the data from current table is appended. atom_order: Which of the atoms in the SK table is to be treated as the first atom? "AB": The first orbital belongs to the first atom "BA": The first orbital belongs to the second atom Returns: ======== sk The Slater Koster data is stored in attributes of sk: sk.Z1, sk.Z2, sk.d, sk.S, sk.H """ from os.path import basename at1, at2 = basename(skfile).replace(".skf", "").split("-") fh = open(skfile, "r") # line 1 parts = process_slako_line(fh.readline()) gridDist, nGridPoints = float(parts[0]), int(parts[1]) if at1 == at2: # line 2 # homonuclear case Ed, Ep, Es, SPE, Ud, Up, Us, fd, fp, fs = map( float, process_slako_line(fh.readline())) # line 2 or 3 mass, c2, c3, c4, c5, c6, c7, c8, c9, rcut, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10 = \ map(float, process_slako_line(fh.readline())) d = linspace(0.0, gridDist * (nGridPoints - 1), nGridPoints) if sk == None: sk = SlakoModule() sk.Z1 = AtomicData.atomic_number(at1) sk.Z2 = AtomicData.atomic_number(at2) sk.d = d sk.S = {} sk.H = {} S = sk.S H = sk.H if atom_order == "BA": tausymbols = T.tausymbols_BA else: tausymbols = T.tausymbols_AB lines = fh.readlines() parts = process_slako_line(lines[0]) n = len(parts) / 2 assert n == 10 # for orbitals up to d functions there are 10 Slater Koster integrals for tausym in tausymbols[-n:]: try: tau = T.symbol2tau[tausym] except KeyError: continue # print "found %s integrals" % (T.tau2symbol[tau]) H[(tau[0], tau[2], T.tau2index[tau])] = array( [0.0 for i in range(0, int(nGridPoints))]) S[(tau[0], tau[2], T.tau2index[tau])] = array( [0.0 for i in range(0, int(nGridPoints))]) # line 4 to (4 + nGridPoints -1) for i in range(0, nGridPoints): parts = process_slako_line(lines[i]) #Hdd0 Hdd1 Hdd2 Hpd0 Hpd1 Hpp0 Hpp1 Hsd0 Hsp0 Hss0 Sdd0 Sdd1 Sdd2 Spd0 Spd1 Spp0 Spp1 Ssd0 Ssp0 Sss0 for pos, tausym in enumerate(tausymbols[-n:]): try: tau = T.symbol2tau[tausym] except KeyError: continue l1, l2 = tau[0], tau[2] if atom_order == "BA": orbital_parity = pow(-1, l1 + l2) else: orbital_parity = 1 H[(l1, l2, T.tau2index[tau])][i] = orbital_parity * float(parts[pos]) S[(l1, l2, T.tau2index[tau])][i] = orbital_parity * float( parts[len(tausymbols) + pos]) return sk
def read_repulsive_potential(filename): """ read repulsive potential in the format used by Hotbit, DFTBaby or DFTB+ """ from os.path import exists, basename, dirname, join if ".par" in filename: # Hotbit's format at1, at2 = basename(filename).replace(".par", "").split("_") if not exists(filename): # file file A_B.par does not exist, look for file B_A.par filename_BA = join(dirname(filename), "%s_%s.par" % (at2, at1)) print "parameter file %s does not exist -> try to load %s" % ( filename, filename_BA) filename = filename_BA data_blocks = hotbit_format.parseHotbitParameters(filename) mod = ReppotModule() mod.d = data_blocks["repulsive_potential"][:, 0] mod.Vrep = data_blocks["repulsive_potential"][:, 1] mod.Z1 = AtomicData.atomic_number(at1) mod.Z2 = AtomicData.atomic_number(at2) return mod elif ".py" in filename: # DFTBaby format # access dictionary by .-notation mod = utils.dotdic() execfile(filename, mod) return mod elif ".skf" in filename: # DFTB+ format, only the Splines part is read at1, at2 = basename(filename).replace(".skf", "").split("-") if not exists(filename): # file file A-B.skf does not exist, look for file B-A.skf filename_BA = join(dirname(filename), "%s-%s.skf" % (at2, at1)) print "parameter file %s does not exist -> try to load %s" % ( filename, filename_BA) filename = filename_BA fh = open(filename) lines = fh.readlines() fh.close() # find section with repulsive potential for i, l in enumerate(lines): if l.strip() == "Spline": break else: raise Exception("No 'Spline' section found in parameter file %s" % filename) # Line 2: nInt, cutoff = lines[i + 1].strip().split() nInt, cutoff = int(nInt), float(cutoff) # Line 3: V(r < r0) = exp(-a1*r+a2) + a3 is r too small to be covered by the spline a1, a2, a3 = map(float, lines[i + 2].strip().split()) # Line 4 to 4+nInt-2 rs = np.zeros(nInt) cs = np.zeros((4, nInt)) for j in range(0, nInt): # spline for the range [rj=start,r_(j+1)=end] # V(r_j <= r < r_(j+1)) = c0 + c1*(r-r0) + c2*(r-r0)^2 + c3*(r-r0)^3 start, end, c0, c1, c2, c3 = map( float, lines[i + 3 + j].strip().split()[:6]) rs[j] = start cs[:, j] = np.array([c0, c1, c2, c3]) # V(r_nInt < r) = 0.0 assert end == cutoff # Now we evaluate the spline on a equidistant grid Npts = 100 d = np.linspace(0.0, cutoff, Npts) Vrep = np.zeros(Npts) j = 0 for i, di in enumerate(d): if (di < rs[0]): Vrep[i] = np.exp(-a1 * di + a2) + a3 else: # find interval such that r[j] <= di < r[j+1] while (di >= rs[j + 1]) and j < nInt - 2: j += 1 if j < nInt - 2: assert rs[j] <= di < rs[j + 1] c0, c1, c2, c3 = cs[:, j] Vrep[i] = c0 + c1 * (di - rs[j]) + c2 * ( di - rs[j])**2 + c3 * (di - rs[j])**3 else: Vrep[i] = 0.0 # create python module mod = ReppotModule() mod.d = d mod.Vrep = Vrep mod.Z1 = AtomicData.atomic_number(at1) mod.Z2 = AtomicData.atomic_number(at2) return mod else: raise Exception("Format of %s not understood" % filename)
def _create_visualization(self, atomlist): mlab = self.scene.mlab # draw atoms as balls vec = XYZ.atomlist2vector(atomlist) x, y, z = vec[::3], vec[1::3], vec[2::3] Zs = np.array([Z for (Z,pos) in atomlist]) atom_names = [AtomicData.atom_names[Z-1] for (Z,pos) in atomlist] rads = np.array([AtomicData.covalent_radii.get(atname) for atname in atom_names]) atom_radii = np.sqrt(rads)*1.8 s = atom_radii if self.show_flags["atoms"] == False: # make atoms so small that one does not see them scale_factor = 0.01 self.shown_atoms = False else: scale_factor = 0.45 self.shown_atoms = True atoms = mlab.quiver3d(x,y,z, s,s,s, scalars=Zs.astype(float), mode="sphere", scale_factor=scale_factor, resolution=20, figure=self.scene.mayavi_scene) # atoms are coloured by their atomic number atoms.glyph.color_mode = "color_by_scalar" atoms.glyph.glyph_source.glyph_source.center = [0,0,0] self.lut = atoms.module_manager.scalar_lut_manager.lut.table.to_array() for atname in set(atom_names): Z = AtomicData.atomic_number(atname) self.lut[Z,0:3] = ( np.array( atom_colours_rgb.get(atname, (0.0, 0.75, 0.75)) )*255.0 ).astype('uint8') atoms.module_manager.scalar_lut_manager.lut.table = self.lut atoms.module_manager.scalar_lut_manager.data_range = (0.0, 255.0) # draw bonds C = XYZ.connectivity_matrix(atomlist) Nat = len(atomlist) connections = [] bonds = mlab.points3d(x,y,z, scale_factor=0.15, resolution=20, figure=self.scene.mayavi_scene) for i in range(0, Nat): Zi, posi = atomlist[i] for j in range(i+1,Nat): if C[i,j] == 1: Zj, posj = atomlist[j] connections.append( (i,j) ) bonds.mlab_source.dataset.lines = np.array(connections) bonds.mlab_source.dataset.modified() tube = mlab.pipeline.tube(bonds, tube_radius=0.15, #tube_radius=0.05, figure=self.scene.mayavi_scene) tube.filter.radius_factor = 1.0 surface = mlab.pipeline.surface(tube, color=(0.8,0.8,0.0), opacity=0.7, figure=self.scene.mayavi_scene) self.atoms = atoms self.bonds = bonds # self.tube = tube # self.surface = surface self.atom_radii = s self.Zs = Zs.astype(float) self.primitives.append(atoms) self.primitives.append(bonds) self.primitives.append(tube) self.primitives.append(surface) # Lewis structure if self.show_flags["Lewis structure"] == True: bondsTuples, bond_orders, lone_pairs, formal_charges = BondOrders.assign_bond_orders(atomlist, C, charge=0) # plot DOUBLE bonds double_bonds = mlab.points3d(x,y,z, scale_factor=0.15, resolution=20, figure=self.scene.mayavi_scene) connections_double = [] for i,bond in enumerate(bondsTuples): if bond_orders[i] == 2: # double bond between atoms I and J connections_double.append( bond ) double_bonds.mlab_source.dataset.lines = np.array(connections_double) double_bonds.mlab_source.dataset.modified() tube = mlab.pipeline.tube(double_bonds, tube_radius=0.35, figure=self.scene.mayavi_scene) tube.filter.radius_factor = 1.0 surface = mlab.pipeline.surface(tube, color=(0.8,0.8,0.0), figure=self.scene.mayavi_scene) # self.double_bonds = double_bonds self.primitives.append(double_bonds) self.primitives.append(tube) self.primitives.append(surface) # # plot TRIPLE bonds triple_bonds = mlab.points3d(x,y,z, scale_factor=0.15, resolution=20, figure=self.scene.mayavi_scene) connections_triple = [] for i,bond in enumerate(bondsTuples): if bond_orders[i] == 3: # triple bond between atoms I and J connections_triple.append( bond ) triple_bonds.mlab_source.dataset.lines = np.array(connections_triple) triple_bonds.mlab_source.dataset.modified() tube = mlab.pipeline.tube(triple_bonds, tube_radius=0.35, figure=self.scene.mayavi_scene) tube.filter.radius_factor = 1.0 surface = mlab.pipeline.surface(tube, color=(0.8,0.8,0.0), figure=self.scene.mayavi_scene) # self.triple_bonds = triple_bonds self.primitives.append(triple_bonds) self.primitives.append(tube) self.primitives.append(surface) self.shown_lewis_structure = True