def read_new_type(self): """ Routine for reading a file type not contained in open babel. """ infile = open(self.file_path, 'r') line = infile.readline() if self.file_type == 'txyz2': # Tinker format preserving all information self.tinker_symbs = [] self.tinker_extra = [] num_at_chk = int(line.split()[0]) line = infile.readline() while (line != ''): words = line.split() if len(words) == 0: break obatom = openbabel.OBAtom() self.tinker_symbs.append(words[1]) lett1 = words[1][0] if words[1] in symbol_Z_dict: at_num = symbol_Z_dict[words[1]] elif words[1][0] in symbol_Z_dict: at_num = symbol_Z_dict[words[1][0]] else: at_num = 99 obatom.SetAtomicNum(at_num) coords = [float(word) for word in words[2:5]] obatom.SetVector(*coords) self.tinker_extra.append(words[5:]) # maybe one could use SetSymbol here self.mol.AddAtom(obatom) line = infile.readline() #print self.mol.NumAtoms() assert (num_at_chk == self.mol.NumAtoms()) elif self.file_type == 'col' or self.file_type == 'nx': while (line != ''): words = line.split() obatom = openbabel.OBAtom() obatom.SetAtomicNum(int(float(words[1]))) coords = [ float(word) * units.length['A'] for word in words[2:5] ] obatom.SetVector(*coords) self.mol.AddAtom(obatom) line = infile.readline() else: print('type %s not supported for input' % self.file_type) exit(1) infile.close()
def exchangeAtom(C, H, molTS, molFG, outfile, bondLength): # read write xyz file convTS, convFG = [ob.OBConversion() for i in range(2)] convTS.SetInAndOutFormats("xyz", "xyz") convFG.SetInAndOutFormats("xyz", "xyz") # builder builder = ob.OBBuilder() # define molecules, atoms and bond classes TS, FG = [ob.OBMol() for i in range(2)] atomH = ob.OBAtom() atomC = ob.OBAtom() bond = ob.OBBond() # read in xyz files convTS.ReadFile(TS, molTS) convFG.ReadFile(FG, molFG) # number of atoms in TS molecule numAtoms = TS.NumAtoms() # get hydrogen atom and its vector atomH = TS.GetAtom(H) atomC = TS.GetAtom(C) vec = ob.vector3(float(atomH.GetX()), float(atomH.GetY()), float(atomH.GetZ())) # delete hydrogen atom TS.DeleteAtom(atomH) # put both molecules together (same coord system) TS += FG # making the bond builder.Connect(TS, C, numAtoms, vec, 1) bond = TS.GetBond(C, numAtoms) bond.SetLength(atomC, bondLength) # call opimizer #opt_mmff_FG(TS, numAtoms, outfile) convTS.WriteFile(TS, "single/" + outfile) # clear TS and FG molecule classes TS.Clear() FG.Clear()
def get_zmatrix_template(parser): """Make a zmatrix from the original geometry. Parameters ---------- parser : object Parser object from vetee. Returns ------- zmatrix : str The zmatrix (gzmat format) for the parser molecule. Will be used to combine with dihedral angles. """ # from vetee obmol = openbabel.OBMol() # add coordinates for each atom for atom in parser.coords: obatom = openbabel.OBAtom() atomicnum = vetee.gaussian_options.periodic_table(atom[0]) obatom.SetAtomicNum(atomicnum) obatom.SetVector(atom[1], atom[2], atom[3]) obmol.AddAtom(obatom) # set charge, multiplicity, and comments (title) obmol.SetTotalCharge(parser.charge) obmol.SetTotalSpinMultiplicity(parser.multip) if parser.comments is not None: obmol.SetTitle(parser.comments) # convert the obmol to a pybel Molecule pybelmol = pybel.Molecule(obmol) # generate a zmatrix string using the obmol input zmatrix = pybelmol.write("gzmat") return zmatrix
def __init__(self, mol): """ Initializes with pymatgen Molecule or OpenBabel"s OBMol. Args: mol: pymatgen"s Molecule or OpenBabel OBMol """ if isinstance(mol, Molecule): if not mol.is_ordered: raise ValueError("OpenBabel Molecule only supports ordered " "molecules.") # For some reason, manually adding atoms does not seem to create # the correct OBMol representation to do things like force field # optimization. So we go through the indirect route of creating # an XYZ file and reading in that file. obmol = ob.OBMol() obmol = ob.OBMol() for site in mol: coords = [c for c in site.coords] atomno = site.specie.Z obatom = ob.OBAtom() obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) obmol.ConnectTheDots() obmol.PerceiveBondOrders() obmol.SetTotalSpinMultiplicity(mol.spin_multiplicity) obmol.SetTotalCharge(mol.charge) self._obmol = obmol elif isinstance(mol, ob.OBMol): self._obmol = mol
def makeopenbabel(atomcoords, atomnos, charge=0, mult=1): """Create an Open Babel molecule. >>> import numpy, openbabel >>> atomnos = numpy.array([1, 8, 1], "i") >>> coords = numpy.array([[-1., 1., 0.], [0., 0., 0.], [1., 1., 0.]]) >>> obmol = makeopenbabel(coords, atomnos) >>> obconversion = openbabel.OBConversion() >>> formatok = obconversion.SetOutFormat("inchi") >>> print obconversion.WriteString(obmol).strip() InChI=1/H2O/h1H2 """ obmol = ob.OBMol() for i in range(len(atomnos)): # Note that list(atomcoords[i]) is not equivalent!!! # For now, only take the last geometry. # TODO: option to export last geometry or all geometries? coords = atomcoords[-1][i].tolist() atomno = int(atomnos[i]) obatom = ob.OBAtom() obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) obmol.ConnectTheDots() obmol.PerceiveBondOrders() obmol.SetTotalSpinMultiplicity(mult) obmol.SetTotalCharge(charge) return obmol
def get_pdb_ccd_open_babel_mol(pdb_mol): """ Generate an Open Babel representation of a PDB CCD entry Args: pdb_mol (:obj:`dict`): structure of a entry Returns: :obj:`openbabel.OBMol`: structure of a entry """ if not pdb_mol['complete']: return None mol = openbabel.OBMol() for pdb_atom in pdb_mol['atoms']: atom = openbabel.OBAtom() atom.SetAtomicNum(pdb_atom['atomic_num']) atom.SetFormalCharge(pdb_atom['charge']) mol.AddAtom(atom) for pdb_bond in pdb_mol['bonds']: bond = openbabel.OBBond() bond.SetBegin(mol.GetAtom(pdb_bond['begin'])) bond.SetEnd(mol.GetAtom(pdb_bond['end'])) bond.SetBondOrder(pdb_bond['order']) assert mol.AddBond(bond) return mol
def EFP2atom(s): at=openbabel.OBAtom() st=s.split() at.SetAtomicNum(int(float(st[-1]))) at.SetVector(float(st[1])*Bohr, float(st[2])*Bohr, float(st[3])*Bohr) at.SetTitle(st[0][3:len(st[0])]) return at
def hash2smiles(hash): import openbabel result_list = [] obconvert = openbabel.OBConversion() obconvert.SetOutFormat('smiles') for (atoms, bonds) in parse_hash(hash): mol = openbabel.OBMol() for n in xrange(len(atoms)): (node, valence, hydrogens, charge, chirality) = parse_atom(atoms[n]) if node == 'PO3': node = 'P' atom = openbabel.OBAtom() atom.SetAtomicNum(atomicnum_table[node]) mol.AddAtom(atom) for n in range(len(atoms)): for m in range(n): order = bonds.pop(0) if order: mol.AddBond(n + 1, m + 1, order) smiles = obconvert.WriteString(mol).strip() result_list.append(smiles) return result_list
def __init__(self, OBAtom=None, index=None): if not OBAtom: OBAtom = ob.OBAtom() self.OBAtom = OBAtom # For the moment, I will remember the index of the atom in the molecule... # I'm not sure if this is useful, though. self.index = index
def GetConf(mol, args, catoms=[]): # Create a mol3D copy with a dummy metal metal Conf3D = mol3D() Conf3D.copymol3D(mol) Conf3D.addAtom(atom3D('Fe', [0, 0, 0])) #Add dummy metal to the mol3D dummy_metal = openbabel.OBAtom() #And add the dummy metal to the OBmol dummy_metal.SetAtomicNum(26) Conf3D.OBMol.AddAtom(dummy_metal) for i in catoms: Conf3D.OBMol.AddBond(i + 1, Conf3D.OBMol.NumAtoms(), 1) natoms = Conf3D.natoms Conf3D.createMolecularGraph() shape = findshape(args, mol) LB, UB = GetBoundsMatrices(Conf3D, natoms, catoms, shape) status = False while not status: D = Metrize(LB, UB, natoms) D0, status = GetCMDists(D, natoms) G = GetMetricMatrix(D, D0, natoms) L, V = Get3Eigs(G, natoms) X = np.dot(V, L) # get projection x = np.reshape(X, 3 * natoms) res1 = optimize.fmin_cg(DistErr, x, fprime=DistErrGrad, gtol=0.1, args=(LB, UB, natoms), disp=0) X = np.reshape(res1, (natoms, 3)) Conf3D = SaveConf(X, Conf3D, True, catoms) return Conf3D
def _removeMetalAtoms(self): _metalAtoms = [] removing = True while removing: added = 0 if self.mol.NumAtoms() == 0: break for i in range(1, self.mol.NumAtoms() + 1): atom = self.mol.GetAtom(i) if atom.GetAtomicNum() in [1, 6, 7, 8, 12, 15, 16]: if atom not in self._atoms: self._atoms.append(atom) added += 1 else: print( "Info: FragIt [FRAGMENTATION] Temporarily removing atom with Z={}" .format(atom.GetAtomicNum())) # the atoms are most-likely counter ions, so we give them an # appropriate formal charge (of +/- 1) atomic_charge = 0 # default if atom.GetAtomicNum() in [11, 19]: # Na+ and K+: atomic_charge = 1 elif atom.GetAtomicNum() in [9, 17]: # F- and Cl- atomic_charge = -1 new_atom = openbabel.OBAtom() new_atom.Duplicate(atom) new_atom.SetFormalCharge(atomic_charge) _metalAtoms.append(new_atom) self.mol.DeleteAtom(atom) break if added == self.mol.NumAtoms(): removing = False break if len(self.getExplicitlyBreakAtomPairs()) > 0: print( "\n WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" ) print( " You have requested to manually fragment atom indices. However," ) print( " because you _also_ have metal atoms in your input file, atom" ) print( " indices might have shifted around and you will likely see an" ) print( " error below about atoms not being connected with a bond.\n" ) print( " A possible fix is to move metal atoms to the end of your file.\n" ) #print(" WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING") return _metalAtoms
def oasa_to_ob_atom(self, oatom): num = PT[oatom.symbol]['ord'] obatom = openbabel.OBAtom() obatom.SetAtomicNum(num) obatom.SetVector(oatom.x, oatom.y, oatom.z) obatom.SetFormalCharge(oatom.charge) #patom = pybel.Atom() #patom.atomicnum = num return obatom
def _to_normal_coordinates(self, atom, index): """Returns: The `atom`'s normal coordinates for normal mode at `index`. """ def ar(vec): """Returns a numpy array with the coordinates of the vector.""" return np.array((vec.GetX(), vec.GetY(), vec.GetZ())) atomnc = ob.OBAtom() nc = ar(atom) + self.lx[index][atom.GetIdx() - 1] atomnc.SetVector(*nc) return atomnc
def to_openbabel_Mol(mol, CalcBondmap = False): obmol = ob.OBMol() if not mol.coords == None: for atom, coord in zip(mol.atoms, mol.coords): obatom = ob.OBAtom() obatom.SetAtomicNum(ob.OBElementTable().GetAtomicNum(atom)) coord_vec = ob.vector3(coord[0], coord[1], coord[2]) obatom.SetVector(coord_vec) obmol.InsertAtom(obatom) else: for atom in mol.atoms: obatom = ob.OBAtom() obatom.SetAtomicNum(ob.OBElementTable().GetAtomicNum(atom)) obmol.InsertAtom(obatom) if CalcBondmap == True: obmol.ConnectTheDots() obmol.PerceiveBondOrders() else: for bond in mol.bondmap: obmol.AddBond(bond[0] + 1, bond[1] + 1, bond[2]) return obmol
def __init__(self, Id, Type, Val, Cor, Q, Bonds, Mol): self.id = Id self.type = Type self.val = Val self.cor = Cor self.q = Q self.bonds = Bonds self.mol = Mol self.atom = openbabel.OBAtom() self.atom.SetId(Id) self.atom.SetAtomicNum(Type)
def read_cclib(self, data, ind=-1, lvprt=1): if lvprt >= 1: print(("Reading cclib structure with %i atoms." % data.natom)) self.mol = openbabel.OBMol() for iat in range(data.natom): obatom = openbabel.OBAtom() obatom.SetAtomicNum(int(data.atomnos[iat])) coords = data.atomcoords[ind][iat] obatom.SetVector(*coords) self.mol.AddAtom(obatom)
def GetConf(mol, args, catoms=[]): """Uses distance geometry to get a random conformer. Parameters ---------- mol : mol3D mol3D class instance for molecule of interest. args : Namespace Namespace argument from inparse. catoms : list, optional List of connection atoms used to generate additional constraints if specified (see GetBoundsMatrices()). Default is empty. Returns ------- Conf3D : mol3D mol3D class instance of new conformer. """ # Create a mol3D copy with a dummy metal metal Conf3D = mol3D() Conf3D.copymol3D(mol) Conf3D.addAtom(atom3D('Fe', [0, 0, 0])) #Add dummy metal to the mol3D dummy_metal = openbabel.OBAtom() #And add the dummy metal to the OBmol dummy_metal.SetAtomicNum(26) Conf3D.OBMol.AddAtom(dummy_metal) for i in catoms: Conf3D.OBMol.AddBond(i + 1, Conf3D.OBMol.NumAtoms(), 1) natoms = Conf3D.natoms Conf3D.createMolecularGraph() shape = findshape(args, mol) LB, UB = GetBoundsMatrices(Conf3D, natoms, catoms, shape) status = False while not status: D = Metrize(LB, UB, natoms) D0, status = GetCMDists(D, natoms) G = GetMetricMatrix(D, D0, natoms) L, V = Get3Eigs(G, natoms) X = np.dot(V, L) # get projection x = np.reshape(X, 3 * natoms) res1 = optimize.fmin_cg(DistErr, x, fprime=DistErrGrad, gtol=0.1, args=(LB, UB, natoms), disp=0) X = np.reshape(res1, (natoms, 3)) Conf3D = SaveConf(X, Conf3D, True, catoms) return Conf3D
def read_at_dicts(self, at_dicts): """ Create a mol from information specified in a list of dictionaries. [{'Z':, 'x':, 'y':, 'z':}, ...] """ self.mol = openbabel.OBMol() for iat in range(len(at_dicts)): obatom = openbabel.OBAtom() obatom.SetAtomicNum(at_dicts[iat]['Z']) coords = (at_dicts[iat]['x'], at_dicts[iat]['y'], at_dicts[iat]['z']) obatom.SetVector(*coords) self.mol.AddAtom(obatom)
def makeopenbabel(atomcoords, atomnos, charge=0, mult=1): """Create an Open Babel molecule.""" obmol = ob.OBMol() for i in range(len(atomnos)): # Note that list(atomcoords[i]) is not equivalent!!! # For now, only take the last geometry. # TODO: option to export last geometry or all geometries? coords = atomcoords[-1][i].tolist() atomno = int(atomnos[i]) obatom = ob.OBAtom() obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) obmol.ConnectTheDots() obmol.PerceiveBondOrders() obmol.SetTotalSpinMultiplicity(mult) obmol.SetTotalCharge(int(charge)) return obmol
def _single_protonation_orca_strings(self, pymol): orca_strings = [] self.stored_data['protonated_children'] = [] for atom in pymol.atoms: if atom.atomicnum in [7, 8, 15, 16]: print 'Atom #{} is {} atom with\n coords {}'.format( atom.idx, element(atom.atomicnum), atom.coords) child = {} child['atom_index'] = atom.idx child['element'] = element(atom.atomicnum).symbol if atom.hyb > 2: child['likely_to_break'] = True else: child['likely_to_break'] = False obmol = pymol.OBMol h = openbabel.OBAtom() h.SetAtomicNum(1) h.SetVector(*atom.coords) h.SetVector(h.GetVector().GetX() + 0.4, h.GetVector().GetY() + 0.4, h.GetVector().GetZ() + 0.4) print 'New Proton is #{} with info {} and\n coords ({}, {}. {})'.format( h.GetIdx(), element(h.GetAtomicNum()), h.GetVector().GetX(), h.GetVector().GetY(), h.GetVector().GetZ()) obmol.InsertAtom(h) obmol.AddBond(atom.idx, h.GetIdx(), 1) obmol.SetTotalCharge(pymol.charge + 1) tmp_pymol = pybel.Molecule(obmol) tmp_pymol.localopt() orca_string, _ = create_orca_input_string(tmp_pymol) child['orca_string'] = orca_string orca_strings.append(orca_string) self.stored_data['protonated_children'].append(child) return orca_strings
def test_building_a_molecule(self): mol = ob.OBMol() C = add_atom(mol, 6) N = add_atom(mol, 7) # XXX Why can't I do mol.AddBond(C, N, 3)? mol.AddBond(C.GetIdx(), N.GetIdx(), 3) self.assertEqual(C.ImplicitHydrogenCount(), 1) C.IncrementImplicitValence() # Is this how to increment the implicit hcount? self.assertEqual(C.ImplicitHydrogenCount(), 2) conv = ob.OBConversion() conv.SetOutFormat("can") s = conv.WriteString(mol).strip() # XXX How does this work when the ImplicitHydrogenCount is 2?? XXX self.assertEqual(s, "C#N") # I can even add an atom this way. (Why are there 2 ways?) O = ob.OBAtom() O.SetAtomicNum(8) mol.AddAtom(O) O.SetImplicitValence(2) s = conv.WriteString(mol).strip() self.assertEqual(s, "C#N.O")
def construct(self, db, mol): cores = [] support = [] nfrags = 0 for e in db.entries: fr = pybel.Smarts(e.smarts) found = fr.findall(mol) if len(found)>0: cores.append([e.name, found]) for f in found: support.append([e.name, f]) nfrags += 1 print "\nTotal number of database matches: ", nfrags, "\n" # constructing overlap matrix of the fragments print "Constructing overlap matrix" overlap = [] for i in xrange(len(support)): overlap.append([]) for j in xrange(len(support)): overlap[-1].append(ListOverlap(support[i][1], support[j][1])) # subdivide molecule into non-overlapping fragments without any atoms left print "Creating a set of unique fragments" numat = mol.OBMol.NumHvyAtoms() complete = False result = None nums = [] for i in xrange(len(support)): nums.append([i]) n0 = 0 n = len(nums) ntry = 0 for i in xrange(len(support)-1): for nn in nums[n0:n]: for j in xrange(len(support)): if j not in nn: good = 1 for k in nn: if overlap[j][k]: good = 0 break if good: newl = nn[:] newl.append(j) sstop = 0 for nn2 in nums[n:]: if IsIncluded(nn2,newl): sstop = 1 break if (sstop == 0): ntry += 1 nat = 0 for k in newl: nat += len(support[k][1]) if (nat == numat): complete = True result = newl break nums.append(newl) # print i, j, newl if (complete): break if (complete): break n0 = n n = len(nums) if (result == None): for nn in nums: nat = 0 for k in nn: nat += len(support[k][1]) if (nat == numat): result = nn break # result = [0] # convert data to the appropriate format coredict = {} nfrag = 0 for ss in result: if support[ss][0] not in coredict: coredict[support[ss][0]] = [support[ss][1]] nfrag += 1 else: coredict[support[ss][0]].append(support[ss][1]) nfrag += 1 cores = [] print "The molecule was subdivided into ", nfrag, " non-overlapping fragments after ", ntry+1, " attempts\n" for c in coredict: cores.append([c, coredict[c]]) for c in cores: # print c for cc in c[1]: self.frags.append(frag()) self.frags[-1].ename = c[0] self.frags[-1].refndx = list(cc[:]) WithBonds0 = list(cc[:]) for i in cc: for at in openbabel.OBAtomAtomIter(mol.OBMol.GetAtom(i)): if (at.GetIndex()+1 not in cc): if (at.GetAtomicNum() > 1): WithBonds0.append(at.GetIndex()+1) else: self.frags[-1].refndx.append(at.GetIndex()+1) # Creating submolecule from the fragment # subMol = openbabel.OBMol() for at in openbabel.OBMolAtomIter(mol.OBMol): if (at.GetIndex()+1) in WithBonds0: at1 = openbabel.OBAtom() at1.Duplicate(at) self.frags[-1].subMol.AddAtom(at1) self.frags[-1].subMol.ConnectTheDots() self.frags[-1].subMol.PerceiveBondOrders() self.frags[-1].subMol.AddHydrogens() # creating new lists for submolecule frB = pybel.Smarts(pybel.Molecule(self.frags[-1].subMol).write("smi")) # print "======================== fragment", self.frags[-1].ename, " ===========================" # print self.frags[-1].ename, pybel.Molecule(self.frags[-1].subMol).write("smi") fr = pybel.Smarts(db.Smarts(c[0])) self.frags[-1].moltotal = frB.findall(pybel.Molecule(self.frags[-1].subMol))[0] newcore = fr.findall(pybel.Molecule(self.frags[-1].subMol))[0] # indices in the submolecule self.frags[-1].molcore = [] for f in self.frags[-1].moltotal: if f in newcore: self.frags[-1].molcore.append(f) # creating new lists for EFP fragment nbd = len(self.frags[-1].moltotal) - len(self.frags[-1].molcore) # number of connections bpat = db.Bondpatterns(c[0], nbd) found = 0 for fn in bpat: efpmol = pyEFP.EFP2mol("./"+db.dirname+"/"+str(c[0])+"/"+fn+".efp") # print self.frags[-1].fname, pybel.Molecule(efpmol).write("smi") newlB = frB.findall(pybel.Molecule(efpmol)) # print c[0], fn, efpmol.NumAtoms(), len(self.frags[-1].moltotal) - len(self.frags[-1].molcore), newlB # print pybel.Molecule(efpmol).write("smi") # print "frB = ", pybel.Molecule(self.frags[-1].subMol).write("smi") # print frB.findall(mol) if len(newlB) > 0: self.frags[-1].efptotal = newlB[0] found = 1 break if (found==0): print "Cannot find bond pattern for fragment ", self.frags[-1].ename, " corresponding to the structure ", pybel.Molecule(self.frags[-1].subMol).write("smi").strip(), "( ", nbd, " connections )" return 1 self.frags[-1].fname = fn newl = fr.findall(pybel.Molecule(efpmol))[0] self.frags[-1].efpcore = [] for f in self.frags[-1].efptotal: if f in newl: self.frags[-1].efpcore.append(f) # calculating links # first loop to identify index in local reference for f in self.frags: for i in xrange(len(f.efptotal)): if (f.efptotal[i] not in f.efpcore): f.links.append([f.efptotal[i], f.moltotal[i]]) # second loop to identify linked residue and index in the corresponding reference ifr0 = 0 for f in self.frags: for xx in xrange(len(f.links)): i = f.links[xx][1] x0 = f.subMol.GetAtom(i).x() y0 = f.subMol.GetAtom(i).y() z0 = f.subMol.GetAtom(i).z() found = 0 ifr = 0 for f2 in self.frags: # if (f2.molcore[0] != f.molcore[0]): if (ifr0 != ifr): for j in f2.molcore: x1 = f2.subMol.GetAtom(j).x() y1 = f2.subMol.GetAtom(j).y() z1 = f2.subMol.GetAtom(j).z() dx = x1-x0 dy = y1-y0 dz = z1-z0 dr2 = dx*dx + dy*dy + dz*dz if dr2 < 0.0001: found = 1 f.links[xx].append(ifr) # print xx, len(f.links), f2.moltotal.index(j), len(f2.efptotal), f2.fname, f2.ename # sys.stdout.flush() f.links[xx].append(f2.efptotal[f2.moltotal.index(j)]) f.links[xx].append(j) break if (found == 1): break ifr += 1 ifr0 += 1 return 0
def harvestGaussian(self, Filename): molinfo = { # . crucial info 'smi': '', # SMILES representation of the molecule 'M': 0.0, # molecular mass 'cSPE': 0.0, # zero-point corrected single-point energy 'Tr': [0,0,0], # rotational temperatures 'v0': [], # harmonic frequencies 'eff': 0.0, # ReaxFF reference energy 'Ip': [], # ReaxFF reference inertia 'Htherm': 0.0, # thermal enthalpy at 298.15K 'spin': 0.0, # spin multiplicity # . Hindered Rotor info 'rotor': {}, # internal rotation data # . additional info 'sym': 1, # rotational symmetry number 'geo': {}, # charge-centered coordinates {id:[type,[x,y,z]]} 'cmd': [], # g09 command line parameters used for all calculations 'confirmed': True, # IRC TS confirmation 'normalTerm': False, # normal termination flag 'errorLink': 0 # g09 part with error } rotor = {} geo = {} ivib = [] # subdata: harmonic frequency iper = [] # subdata: periodicity isym = [] # subdata: symmetry number imom = [] # subdata: reduced moment of inertia bond = [] # subdata: connection between frequency and rotor bond2 = {} # subdata: connection between frequency and rotor ax = [] # subdata: rotor axes irot = 0 # subdata: number of internal rot deg of freedom irc = [[], []] # . parse Gaussian log file print('file:', Filename) done = False reaxFFdone = False reader = open(Filename, 'r') line = reader.readline() try: while not done: if 'Gaussian 09:' in line: line = reader.readline(); line = reader.readline() # . harvest g09 command line while not line.startswith(' # ') and line != '': line = reader.readline() tmp = line[3:-1] line = reader.readline() while '----------' not in line and line != '': tmp += line[1:-1] line = reader.readline() cmd = tmp.split() cmd = ' '.join([c for c in tmp.split() if '=' not in c and 'opt' not in c and 'freq' not in c and 'int' not in c and 'scf' not in c and 'maxdisk' not in c.lower() and 'symmetry' not in c]) molinfo['cmd'].append(cmd) # . harvest ReaxFF information # stands at start of every job # if no 'normal termination' follows, the job was aborted elif line.startswith(' REAXFF:'): if not reaxFFdone: words = line.strip().split() molinfo['smi'] = words[1] molinfo['eff'] = float(words[2]) molinfo['Ip'] = [float(w) for w in words[3:]] reaxFFdone = True molinfo['normalTerm'] = False # . harvest spin multiplicity elif 'Symbolic Z-matrix:' in line: line = reader.readline() words = line.strip().split() molinfo['spin'] = float(words[5]) # . harvest internal rotation data (anharmonicity) elif 'Hindered Internal Rotation Analysis' in line and not ivib: while '- Thermochemistry For Hindered Internal Rotation -' not in line and 'No hindered rotor corrections are necessary' not in line and 'This molecule contains only rings' not in line and line != '': line = reader.readline() words = line.strip().split() if line.startswith(' Number of internal rotation degrees of freedom'): irot = int(words[-1]) #elif line.startswith(' Normal Mode Analysis for Internal Rotation'): # or line.startswith(' Redo normal mode analysis with added constraints') # ivib = [] elif 'Frequencies ---' in line and len(ivib) < irot: for v in [float(w) for w in words[2:]]: ivib.append(v) elif len(words) == 6 and words[0][-1] == ')': iper.append(int(words[3])) # periodicity isym.append(int(words[4])) # symmetry number elif 'Reduced Moments ---' in line: for m in [float(w) for w in words[3:]]: if m not in imom: imom.append(m) elif line.strip() == 'Bond': line = reader.readline() words = line.strip().split() bidx = 0 while len(words) > 3 and words[1] == '-': ax.append(sorted([int(words[0]), int(words[2])])) # bond partners of axis if bidx+1 > len(bond): bond.append([]) bond[bidx] += [float(w) for w in words[3:]] # axis share bidx += 1 line = reader.readline() words = line.strip().split() # . harvest harmonic frequencies (vibration) elif 'Harmonic frequencies (cm**-1)' in line: if molinfo['v0']: molinfo['v0'] = [] while '- Thermochemistry -' not in line and line != '': line = reader.readline() if 'Frequencies --' in line: words = line.strip().split() molinfo['v0'] += [float(w) for w in words[2:]] # . harvest molecular mass (translation) elif 'Molecular mass:' in line: words = line.strip().split() molinfo['M'] = float(words[2]) # . harvest rotational temperatures (rotation) elif 'Rotational symmetry number' in line: words = line.strip().split() molinfo['sym'] = int(words[3][:-1]) elif 'Rotational temperatures (Kelvin)' in line or 'Rotational temperature (Kelvin)' in line: words = line.strip().split() molinfo['Tr'] = [float(w) for w in words[3:] if '***' not in w] # . harvest energetics elif 'Sum of electronic and zero-point Energies=' in line: words = line.strip().split() molinfo['cSPE'] = float(words[6]) elif 'Sum of electronic and thermal Enthalpies=' in line: words = line.strip().split() molinfo['Htherm'] = float(words[6]) elif 'CBS-QB3 (0 K)=' in line: words = line.strip().split() molinfo['cSPE'] = float(words[3]) elif 'CBS-QB3 Enthalpy=' in line: words = line.strip().split() molinfo['Htherm'] = float(words[2]) elif 'G3MP2(0 K)=' in line: words = line.strip().split() molinfo['cSPE'] = float(words[2]) elif 'G3MP2 Enthalpy=' in line: words = line.strip().split() molinfo['Htherm'] = float(words[2]) # . harvest geometry elif 'Standard orientation' in line: for i in range(5): line = reader.readline() while '-----------------------------------' not in line and line != '': words = line.strip().split() geo[int(words[0])] = [int(words[1]),[float(words[3]),float(words[4]),float(words[5])]] line = reader.readline() molinfo['geo'] = geo # . harvest IRC information elif 'Input orientation:' in line: tmp = [] line = reader.readline() line = reader.readline() line = reader.readline() line = reader.readline() line = reader.readline() while '---' not in line: words = line.split() tmp.append([int(words[1]), [float(words[3]), float(words[4]), float(words[5])]]) line = reader.readline() elif 'Calculation of FORWARD path complete.' in line: irc[0] = tmp elif 'Calculation of REVERSE path complete.' in line: irc[1] = tmp # . normal termination? elif 'Normal termination of Gaussian' in line: molinfo['normalTerm'] = True elif 'Error termination ' in line: molinfo['normalTerm'] = False words = line.strip().split() if len(words) > 7: molinfo['errorLink'] = words[5].split('/')[-1] line = reader.readline() if line == '': done = True reader.close() except: # . return here if exception self.log.printIssue(Text='Exception while executing\n'+traceback.format_exc(), Fatal=False) molinfo['normalTerm'] = False molinfo['M'] = 0.0 return molinfo # . return here if crucial data misses # eff=0 and Tr=[0,0,0] allowed ([H]) if molinfo['cSPE'] == 0.0 or molinfo['M'] == 0.0 or molinfo['smi'] == '' or molinfo['Ip'] == [] or molinfo['Htherm'] == 0.0: molinfo['M'] = 0.0 molinfo['normalTerm'] = False return molinfo # . delete frequencies too close to each other keep = [not any(abs(ivib[i]-ivib[j])<1 for i in range(j+1,irot)) for j in range(irot)] if not all(keep): ivib = [ivib[i] for i in range(irot) if keep[i]] iper = [iper[i] for i in range(irot) if keep[i]] isym = [isym[i] for i in range(irot) if keep[i]] imom = [imom[i] for i in range(irot) if keep[i]] bond = [bond[i] for i in range(irot) if keep[i]] ax = [ax[i] for i in range(irot) if keep[i]] nfreqs = len(ivib) # . merge internal rotation data (4.649783E-48 (kg/amu)*(m/bohr)**2 # don't use a frequency twice unused = [True]*nfreqs for i in range(nfreqs): idx = bond[i].index(max([bond[i][k] for k in range(nfreqs) if unused[k]])) unused[idx] = False if imom[idx] != 0.0: rotor[ivib[idx]] = isym[i]**2 *self.h**2 /(8 *numpy.math.pi**2 *self.kB *imom[idx] *4.649783E-48 *iper[i]**2) # . remove internal rotation axes which are part of ring # atom.thisown=False should solve instabilities mol = openbabel.OBMol() for a in geo: atom = openbabel.OBAtom() atom.thisown = False atom.SetAtomicNum(geo[a][0]) atom.SetVector(geo[a][1][0], geo[a][1][1], geo[a][1][2]) mol.AddAtom(atom) mol.ConnectTheDots() mol.PerceiveBondOrders() tmp_rotor = self.findInternalRotors(Mol=mol) # . delete false rotors, which are part of a ring # ax: axes found by g09 # tmp_rotor: axes found by local method, no rings # rotor: mapping of rot. freq. <-> rot. temp. (g09 data) for idx in range(nfreqs): if ax[idx] not in tmp_rotor and ivib[idx] in rotor: del rotor[ivib[idx]] molinfo['rotor'] = rotor # . check number of molecules (==1) # if species, but nmol > 1, dont use qm-data # return information for species if molinfo['smi'] == '[H]' or molinfo['smi'] == '[H][H]': nmol = 1 else: nmol = len(self.conv.WriteString(mol).strip().split('.')) if ':' not in molinfo['smi']: molinfo['confirmed'] = (nmol == 1) return molinfo # . IRC check, only for TS # build reactants mol = openbabel.OBMol() for a in irc[0]: atom = openbabel.OBAtom() atom.thisown = False if a[0] == 1: atom.SetAtomicNum(9); atom.SetType('H') else: atom.SetAtomicNum(a[0]) atom.SetVector(a[1][0], a[1][1], a[1][2]) mol.AddAtom(atom) mol.ConnectTheDots() for atom in openbabel.OBMolAtomIter(mol): if atom.GetType() == 'H': atom.SetAtomicNum(1) mol.AssignSpinMultiplicity(True) reactants = [] for frag in mol.Separate(): if frag.NumHvyAtoms() == 0: if frag.NumAtoms() == 1: reactants.append('[H]') elif frag.NumAtoms() == 2: reactants.append('[H][H]') continue self.conv.SetInAndOutFormats('mdl','inchi') inchi = self.conv.WriteString(frag) self.conv.SetInAndOutFormats('inchi','mdl') self.conv.ReadString(frag, inchi) self.conv.SetInAndOutFormats('mdl','can') reactants.append(self.conv.WriteString(frag).strip()) # . build products mol = openbabel.OBMol() for a in irc[1]: atom = openbabel.OBAtom() atom.thisown = False if a[0] == 1: atom.SetAtomicNum(9); atom.SetType('H') else: atom.SetAtomicNum(a[0]) atom.SetVector(a[1][0], a[1][1], a[1][2]) mol.AddAtom(atom) mol.ConnectTheDots() for atom in openbabel.OBMolAtomIter(mol): if atom.GetType() == 'H': atom.SetAtomicNum(1) mol.AssignSpinMultiplicity(True) products = [] for frag in mol.Separate(): if frag.NumHvyAtoms() == 0: if frag.NumAtoms() == 1: products.append('[H]') elif frag.NumAtoms() == 2: products.append('[H][H]') continue self.conv.SetInAndOutFormats('mdl','inchi') inchi = self.conv.WriteString(frag) self.conv.SetInAndOutFormats('inchi','mdl') self.conv.ReadString(frag, inchi) self.conv.SetInAndOutFormats('mdl','can') products.append(self.conv.WriteString(frag).strip()) # . check reacIRC = sorted( [sorted(reactants), sorted(products)] ) reacFF = sorted( [sorted(molinfo['smi'].split(':')[0].split(',')), sorted(molinfo['smi'].split(':')[1].split(','))] ) molinfo['confirmed'] = (reacIRC == reacFF) # . return information (for TS) return molinfo
def amol2mol(amol): mol = openbabel.OBMol() atoms = list() bonds = list() atoms, bonds = pickle.loads(amol) natoms = len(atoms) mol.ReserveAtoms(natoms) atomidx = 0 chiatoms = dict() a = openbabel.OBAtom() for atom in atoms: hybridization, atnum, fcharge, isotope, stereo, mult, aromatic = atom a.Clear() atomidx += 1 a.SetIdx(atomidx) a.SetHyb(hybridization) a.SetAtomicNum(atnum) a.SetIsotope(isotope) a.SetFormalCharge(fcharge) if stereo == 1: a.SetClockwiseStereo() elif stereo == 2: a.SetAntiClockwiseStereo() elif stereo == 3: a.SetChiral() a.SetSpinMultiplicity(mult) if aromatic: a.SetAromatic() if not mol.AddAtom(a): return None if stereo: cd = openbabel.OBChiralData() catom = mol.GetAtom(atomidx) catom.CloneData(cd) chiatoms[catom] = cd pass for bond in bonds: flags = 0 #b = openbabel.OBBond() start, end, order, stereo, aromatic, updown = bond if start == 0 or end == 0 or order == 0 or start > natoms or end > natoms: return None if order == 4: order = 5 if stereo == 1: flags |= openbabel.OB_WEDGE_BOND elif stereo == 6: flags |= openbabel.OB_HASH_BOND if aromatic: flags |= openbabel.OB_AROMATIC_BOND if updown == 1: flags |= openbabel.OB_TORUP_BOND print flags elif updown == 2: flags |= openbabel.OB_TORDOWN_BOND print flags if not mol.AddBond(start, end, order, flags): return None chidata = chiatoms.get(mol.GetAtom(start)) if chidata: chidata.AddAtomRef(end, openbabel.input) chidata = chiatoms.get(mol.GetAtom(end)) if chidata: chidata.AddAtomRef(start, openbabel.input) mol.SetAromaticPerceived() mol.SetKekulePerceived() return mol
def test_FragmentationGetOBAtom(self): test_atom = self.fragmentation.getOBAtom(1) self.assertEqual(type(test_atom), type(openbabel.OBAtom()))
def pic(self, filename, picformat='svg'): """ Generates a graphical file with 2D-representation of the resonance structure """ try: import openbabel as ob except: print "Cannot import openbabel" return #ValEl = {'H':1, 'B':3,'C':4,'N':5,'O':6,'F':7,'S':6} #ValEl = {'1':1, '5':3,'6':4,'7':5,'8':6,'9':7,'16':6} # Import Element Numbers ati = [] Sym2Num = ob.OBElementTable() for a in self.symbols: ElNum = Sym2Num.GetAtomicNum(a) ati.append(ElNum) # Import connections conn = self.data mol = ob.OBMol() # Create atoms for a in ati: at = ob.OBAtom() at.SetAtomicNum(a) mol.AddAtom(at) # Create connections val = [] total_LP = 0 for i in range(len(conn)): total_LP += conn[i][i] for i in range(len(conn)): val.append(conn[i][i] * 2) for j in range(i): if conn[i][j] == 0: continue val[i] += conn[i][j] val[j] += conn[i][j] atA = mol.GetAtomById(i) atB = mol.GetAtomById(j) b = ob.OBBond() b.SetBegin(atA) b.SetEnd(atB) b.SetBO(int(conn[i][j])) mol.AddBond(b) for i in range(len(conn)): atA = mol.GetAtomById(i) atAN = atA.GetAtomicNum() FormValEl = CountValenceEl(atAN) #if total_LP == 0: # if atAN == 1: # FullShell = 2 # else: # FullShell = 8 # FormCharge = FormValEl + int(val[i]) - FullShell #else: FormCharge = int(FormValEl - val[i]) #print "atAN, FormValEl, val[i], FullShell" #print atAN, FormValEl, val[i], FullShell #FormCharge = FormCharge % 2 atA.SetFormalCharge(FormCharge) # Export file mol.DeleteNonPolarHydrogens() conv = ob.OBConversion() conv.SetOutFormat(picformat) conv.AddOption('C') conv.WriteFile(mol, filename)