def GetDihedralHs(atom): sp3carbonFound = False #find the proton neigbour, check that it is sp3 carbon for NbrAtom in OBAtomAtomIter(atom): if NbrAtom.GetAtomicNum() == 6 and NbrAtom.GetHyb() == 3: carbon = NbrAtom sp3carbonFound = True break if not sp3carbonFound: return 0 #find the carbon neibours, check that they are sp3 hybridized ncarbons = [] for NbrAtom in OBAtomAtomIter(carbon): if NbrAtom.GetAtomicNum() == 6 and NbrAtom.GetHyb() == 3: ncarbons.append(NbrAtom) #check that the carbon neighbours have protons and return them nHs = [] for ncarbon in ncarbons: for NbrAtom in OBAtomAtomIter(ncarbon): if NbrAtom.GetAtomicNum() == 1: nHs.append(NbrAtom.GetIdx()) if len(nHs) == 0: return 0 else: return nHs
def methyl_protons(file): obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, file) methyl_protons = [] for atom in OBMolAtomIter(obmol): count = 0 nbrprotons = [] for NbrAtom in OBAtomAtomIter(atom): if (atom.GetAtomicNum() == 6) & (NbrAtom.GetAtomicNum() == 1): l = NbrAtom.GetIndex() count += 1 nbrprotons.append('H' + str(l + 1)) if count == 3: methyl_protons.append(nbrprotons) return methyl_protons
def remove_labile_protons(sdffile, lbls, shifts): f = sdffile.split('.sdf')[0] + '.sdf' obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, f) CI = [] for atom in OBMolAtomIter(obmol): if atom.GetAtomicNum() == 1: for NbrAtom in OBAtomAtomIter(atom): if (NbrAtom.GetAtomicNum() == 8): CI.append('H' + str(atom.GetIndex() + 1)) #remove these carbons for C in CI: ind = lbls.index(C) lbls.remove(C) for l in shifts: l.pop(ind) return lbls, shifts
def FindSubstAtoms(atom, outAtom, al): indexes = [a.GetIdx() for a in al] for NbrAtom in OBAtomAtomIter(atom): if (NbrAtom.GetIdx() not in indexes) and\ (NbrAtom.GetIdx() != outAtom.GetIdx()): al.append(NbrAtom) FindSubstAtoms(NbrAtom, outAtom, al)
def RestoreNumsSDF(f, fold, AuxInfo): #Read molecule from file obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, f) #Get the atoms Hs are connected to oldHcons = GetHcons(fold) #translate the H connected atoms to the new numbering system amap = GetInchiRenumMap(AuxInfo) for i in range(0, len(oldHcons)): oldHcons[i][1] = amap.index(oldHcons[i][1]) + 1 newHcons = [] temp = [] i = 0 for atom in OBMolAtomIter(obmol): idx = atom.GetIdx() anum = atom.GetAtomicNum() #If atom is hydrogen, check what it is connected to if anum == 1: for NbrAtom in OBAtomAtomIter(atom): newHcons.append([idx, NbrAtom.GetIdx()]) #Pick the temporary atom temp.append(atom) for i in range(0, len(newHcons)): conatom = newHcons[i][1] for b in range(0, len(oldHcons)): if conatom == oldHcons[b][1]: amap.append(oldHcons[b][0]) #remove the number, so that it doesn't get added twice oldHcons[b][1] = 0 newmol = OBMol() added = [] for i in range(1, len(amap) + 1): newn = amap.index(i) newmol.AddAtom(temp[newn]) added.append(newn) #Final runthrough to check that all atoms have been added, #tautomeric protons can be missed. If tautomeric proton tracking #is implemented this can be removed for i in range(0, len(temp)): if not i in added: newmol.AddAtom(temp[i]) #Restore the bonds newmol.ConnectTheDots() newmol.PerceiveBondOrders() #Write renumbered molecule to file obconversion.SetOutFormat("sdf") obconversion.WriteFile(newmol, f)
def GetENCorrection(atom, satom): Anum = atom.GetAtomicNum() if Anum != 6: return ENs[Anum - 1] - ENs[0], 0.0 else: ENcorr = 0.0 for NbrAtom in OBAtomAtomIter(atom): if NbrAtom.GetIdx() != satom.GetIdx(): neighbAnum = NbrAtom.GetAtomicNum() ENcorr += ENs[neighbAnum - 1] - ENs[0] return ENs[Anum - 1] - ENs[0], ENcorr
def GetHcons(f): obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, f) Hcons = [] for atom in OBMolAtomIter(obmol): idx = atom.GetIdx() anum = atom.GetAtomicNum() if anum == 1: for NbrAtom in OBAtomAtomIter(atom): Hcons.append([idx, NbrAtom.GetIdx()]) return Hcons
def labile_protons(file): obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, file) count = 0 for atom in OBMolAtomIter(obmol): for NbrAtom in OBAtomAtomIter(atom): if (atom.GetAtomicNum() == 8) & (NbrAtom.GetAtomicNum() == 1): count += 1 return count
def pication(rings, pos_charged, protcharged): """Return all pi-Cation interaction between aromatic rings and positively charged groups. For tertiary and quaternary amines, check also the angle between the ring and the nitrogen. """ data = namedtuple( 'pication', 'ring charge distance offset type restype resnr reschain restype_l resnr_l reschain_l protcharged') pairings = [] if len(rings) == 0 or len(pos_charged) == 0: return pairings for ring in rings: c = ring.center for p in pos_charged: d = euclidean3d(c, p.center) # Project the center of charge into the ring and measure distance to ring center proj = projection(ring.normal, ring.center, p.center) offset = euclidean3d(proj, ring.center) if not config.MIN_DIST < d < config.PICATION_DIST_MAX or not offset < config.PISTACK_OFFSET_MAX: continue if type(p).__name__ == 'lcharge' and p.fgroup == 'tertamine': # Special case here if the ligand has a tertiary amine, check an additional angle # Otherwise, we might have have a pi-cation interaction 'through' the ligand n_atoms = [a_neighbor for a_neighbor in OBAtomAtomIter(p.atoms[0].OBAtom)] n_atoms_coords = [(a.x(), a.y(), a.z()) for a in n_atoms] amine_normal = np.cross(vector(n_atoms_coords[0], n_atoms_coords[1]), vector(n_atoms_coords[2], n_atoms_coords[0])) b = vecangle(ring.normal, amine_normal) # Smallest of two angles, depending on direction of normal a = min(b, 180 - b if not 180 - b < 0 else b) if not a > 30.0: resnr, restype = whichresnumber(ring.atoms[0]), whichrestype(ring.atoms[0]) reschain = whichchain(ring.atoms[0]) resnr_l, restype_l = whichresnumber(p.orig_atoms[0]), whichrestype(p.orig_atoms[0]) reschain_l = whichchain(p.orig_atoms[0]) contact = data(ring=ring, charge=p, distance=d, offset=offset, type='regular', restype=restype, resnr=resnr, reschain=reschain, restype_l=restype_l, resnr_l=resnr_l, reschain_l=reschain_l, protcharged=protcharged) pairings.append(contact) break resnr = whichresnumber(p.atoms[0]) if protcharged else whichresnumber(ring.atoms[0]) resnr_l = whichresnumber(ring.orig_atoms[0]) if protcharged else whichresnumber(p.orig_atoms[0]) restype = whichrestype(p.atoms[0]) if protcharged else whichrestype(ring.atoms[0]) restype_l = whichrestype(ring.orig_atoms[0]) if protcharged else whichrestype(p.orig_atoms[0]) reschain = whichchain(p.atoms[0]) if protcharged else whichchain(ring.atoms[0]) reschain_l = whichchain(ring.orig_atoms[0]) if protcharged else whichchain(p.orig_atoms[0]) contact = data(ring=ring, charge=p, distance=d, offset=offset, type='regular', restype=restype, resnr=resnr, reschain=reschain, restype_l=restype_l, resnr_l=resnr_l, reschain_l=reschain_l, protcharged=protcharged) pairings.append(contact) return filter_contacts(pairings)
def FixTautProtons(f, inchi, AuxInfo): #Get tautomeric protons and atoms they are connected to from Inchi TautProts = GetTautProtons(inchi) amap = GetInchiRenumMap(AuxInfo) #get the correspondence of the Inchi numbers to the source numbers hmap = [] for taut in TautProts: for heavyatom in range(1, len(taut)): hmap.append([int(taut[heavyatom]), amap[int(taut[heavyatom]) - 1]]) #Read molecule from file obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, f) Fixprotpos = [] for heavyatom in hmap: atom = obmol.GetAtom(heavyatom[1]) for nbratom in OBAtomAtomIter(atom): if nbratom.GetAtomicNum() == 1: Fixprotpos.append(heavyatom[0]) draftFH = [] for i in range(0, len(Fixprotpos)): if Fixprotpos[i] not in [a[0] for a in draftFH]: draftFH.append([Fixprotpos[i], Fixprotpos.count(Fixprotpos[i])]) fixedlayer = '/f/h' for h in draftFH: if h[1] == 1: fixedlayer = fixedlayer + str(h[0]) + 'H,' else: fixedlayer = fixedlayer + str(h[0]) + 'H' + str(h[1]) + ',' resinchi = inchi + fixedlayer[:-1] return resinchi
def neighbors(self): return [Atom(a) for a in OBAtomAtomIter(self.OBAtom)]
def CalcJ(atom1, atom2): #Get the 2 carbon atoms joining the protons for NbrAtom in OBAtomAtomIter(atom1): if NbrAtom.GetAtomicNum() == 6 and NbrAtom.GetHyb() == 3: carbon1 = NbrAtom break for NbrAtom in OBAtomAtomIter(atom2): if NbrAtom.GetAtomicNum() == 6 and NbrAtom.GetHyb() == 3: carbon2 = NbrAtom break #Get the 2 planes formed by the carbons and each of the protons normal1, d = FindPlane(carbon1, atom1, carbon2) normal2, d = FindPlane(carbon2, atom2, carbon1) sign = VectAngleSign(BondVect(carbon1, atom1), BondVect(carbon2, atom2), BondVect(carbon1, carbon2)) angle = VectorAngle(normal1, normal2) if dotproduct(BondVect(carbon1, atom1), BondVect(carbon2, atom2)) > 0 and \ angle < 0.5*pi: dihedral = angle * sign else: dihedral = (pi - angle) * sign #Count the substituents, get their electronegativities nSubst = 0 relENs = [] ENcorrs = [] signs = [] for NbrAtom in OBAtomAtomIter(carbon1): ANum = NbrAtom.GetAtomicNum() if NbrAtom.GetIdx() != carbon2.GetIdx() and ANum != 1: nSubst += 1 relEN, ENcorr = GetENCorrection(NbrAtom, carbon1) relENs.append(relEN) ENcorrs.append(ENcorr) signs.append( VectAngleSign(BondVect(carbon1, atom1), BondVect(carbon1, NbrAtom), BondVect(carbon1, carbon2))) for NbrAtom in OBAtomAtomIter(carbon2): ANum = NbrAtom.GetAtomicNum() if NbrAtom.GetIdx() != carbon1.GetIdx() and ANum != 1: nSubst += 1 relEN, ENcorr = GetENCorrection(NbrAtom, carbon2) relENs.append(relEN) ENcorrs.append(ENcorr) signs.append( VectAngleSign(BondVect(carbon2, atom2), BondVect(carbon2, NbrAtom), BondVect(carbon2, carbon1))) SubstEffects = 0 if nSubst < 2: for relEN, ENcorr, sign in zip(relENs, ENcorrs, signs): corrRelEN = relEN - (Params[0][6]) * ENcorr SubstEffects += SubstEffect(dihedral, corrRelEN, sign, 0) J = Params[0][0] * cos(dihedral)**2 + Params[0][1] * cos(dihedral) else: for relEN, sign in zip(relENs, signs): corrRelEN = relEN - (Params[nSubst - 1][6]) * ENcorr SubstEffects += SubstEffect(dihedral, corrRelEN, sign, nSubst - 1) J = Params[nSubst - 1][0] * cos(dihedral)**2 + Params[ nSubst - 1][1] * cos(dihedral) return J + SubstEffects
def mol_fragments(mole,outfile): obconv = OBConversion() obconv.SetOutFormat("xyz") c = 1 for atom, exp,dft,diff in zip(OBMolAtomIter(mole)): # if this is a carbon atom start a breadth first search for other carbon atoms with depth specified # create a new mol instance new_mol = OBMol() # add this atom # new_mol.AddAtom(atom) fragment_ind = [] l = atom.GetIndex() fragment_ind.append(l) # for iteration depth radius old_queue = [atom] for iteration in range(0, 3): new_queue = [] for a in old_queue: for atom2 in OBAtomAtomIter(a): i = atom2.GetIndex() # if the atom has not been seen before add it to the fragment ind list and to the new molecule if i not in fragment_ind: new_queue.append(atom2) fragment_ind.append(i) # new_mol.AddAtom(atom2) old_queue = copy.copy(new_queue) fragment_ind = [fragment_ind[0]] + sorted(fragment_ind[1:]) for i in fragment_ind: for a in OBMolAtomIter(mole): if a.GetIndex() == i: new_mol.AddAtom(a) f = open(outfile + "frag" + str(l).zfill(3) + ".xyz", "w+") f.write(str(new_mol.NumAtoms()) + "\n\n") i = 0 for atom in OBMolAtomIter(new_mol): f.write(atom.GetType()[0] + " " + str(atom.GetX()) + " " + str(atom.GetY()) + " " + str( atom.GetZ()) + "\n") i+=1 f.close() c += 1
def main(f, settings): """ Find the axis atoms Find all the atoms to be rotated Rotate it and the substituents to the other side of the plane """ obconversion = OBConversion() obconversion.SetInFormat("sdf") obmol = OBMol() obconversion.ReadFile(obmol, f) obmol.ConnectTheDots() #Find the atoms composing furan ring Rings = obmol.GetSSSR() furan = [] for ring in Rings: if len(settings.RingAtoms) == 5: if all(x in ring._path for x in settings.RingAtoms): furan = ring break else: if ring.Size() == 5 and not ring.IsAromatic(): furan = ring break if furan == []: "No five membered rings to rotate. Quitting..." quit() #Find the plane of the 5-membered ring and the outlying atom norm, d, outAtom = FindFuranPlane(obmol, furan) #Find the atoms connected to the outlying atom and sort them #as either part of the ring(axis atoms) or as atoms to be rotated AxisAtoms = [] RotAtoms = [] for NbrAtom in OBAtomAtomIter(outAtom): #if NbrAtom.IsInRingSize(5): if furan.IsInRing(NbrAtom.GetIdx()): AxisAtoms.append(NbrAtom) else: RotAtoms.append(NbrAtom) FindSubstAtoms(NbrAtom, outAtom, RotAtoms) #Simple switch to help detect if the atoms are rotated the right way WasAbove90 = False angle = FindRotAngle(AxisAtoms[0], AxisAtoms[1], outAtom, norm) if angle > 0.5 * pi: WasAbove90 = True rotangle = 2 * (angle - 0.5 * pi) else: WasAbove90 = False rotangle = 2 * (0.5 * pi - angle) OldAtomCoords = outAtom.GetVector() print("Atom " + str(outAtom.GetAtomicNum()) + " will be rotated by " +\ str(rotangle*57.3) + ' degrees') RotateAtom(outAtom, AxisAtoms[0], AxisAtoms[1], rotangle) angle2 = FindRotAngle(AxisAtoms[0], AxisAtoms[1], outAtom, norm) #if the atom is on the same side of the plane as it was, # it has been rotated in the wrong direction if ((angle2 > 0.5 * pi) and WasAbove90) or ((angle2 < 0.5 * pi) and not WasAbove90): #Flip the sign of the rotation angle, restore the coords #and rotate the atom in the opposite direction print("Atom was rotated the wrong way, switching the direction") rotangle = -rotangle outAtom.SetVector(OldAtomCoords) RotateAtom(outAtom, AxisAtoms[0], AxisAtoms[1], rotangle) RotatedAtoms = [] # Index to make sure that atoms are not rotated twice for atom in RotAtoms: if atom not in RotatedAtoms: RotateAtom(atom, AxisAtoms[0], AxisAtoms[1], rotangle) RotatedAtoms.append(atom) else: print("Atom already rotated, skipping") obconversion.SetOutFormat("sdf") obconversion.WriteFile(obmol, f[:-4] + 'rot.sdf')