def GetMoreTerminalPoints(shape, pts, winRad, maxGridVal, targetNumber=5): """ adds a set of new terminal points using a max-min algorithm """ shapeGrid = shape.grid shapeVect = shapeGrid.GetOccupancyVect() nGridPts = len(shapeVect) # loop, taking the grid point with the maximum minimum distance, until # we have enough points while len(pts) < targetNumber: maxMin = -1 for i in range(nGridPts): if shapeVect[i] < maxGridVal: continue minVal = 1e8 posI = shapeGrid.GetGridPointLoc(i) for currPt in pts: dst = posI.Distance(currPt.location) if dst < minVal: minVal = dst if minVal > maxMin: maxMin = minVal bestPt = posI count, centroid = Geometry.ComputeGridCentroid(shapeGrid, bestPt, winRad) pts.append(SubshapeObjects.SkeletonPoint(location=centroid))
def to_rdmol(plams_mol, sanitize=True): """ Translate a PLAMS molecule into an RDKit molecule type. :parameter plams_mol: PLAMS molecule :type plams_mol: plams.Molecule :return: an RDKit molecule :rtype: rdkit.Chem.Mol """ if isinstance(plams_mol, Chem.Mol): return plams_mol # Create rdkit molecule e = Chem.EditableMol(Chem.Mol()) for atom in plams_mol.atoms: a = Chem.Atom(atom.atnum) if 'charge' in atom.properties: a.SetFormalCharge(atom.properties.charge) if 'pdb_info' in atom.properties: set_PDBresidueInfo(a, atom.properties.pdb_info) e.AddAtom(a) for bond in plams_mol.bonds: a1 = plams_mol.atoms.index(bond.atom1) a2 = plams_mol.atoms.index(bond.atom2) e.AddBond(a1, a2, Chem.BondType(bond.order)) rdmol = e.GetMol() if sanitize: Chem.SanitizeMol(rdmol) conf = Chem.Conformer() for a in range(len(plams_mol.atoms)): atom = plams_mol.atoms[a] p = Geometry.Point3D(atom._getx(), atom._gety(), atom._getz()) conf.SetAtomPosition(a, p) rdmol.AddConformer(conf) return rdmol
def initFromLines(self, lines): from rdkit.Chem import ChemicalFeatures import re spaces = re.compile('[\ \t]+') feats = [] rads = [] for lineNum, line in enumerate(lines): txt = line.split('#')[0].strip() if txt: splitL = spaces.split(txt) if len(splitL) < 5: logger.error( 'Input line %d only contains %d fields, 5 are required. Read failed.' % (lineNum, len(splitL))) return fName = splitL[0] try: xP = float(splitL[1]) yP = float(splitL[2]) zP = float(splitL[3]) rad = float(splitL[4]) except ValueError: logger.error( 'Error parsing a number of line %d. Read failed.' % (lineNum)) return feats.append( ChemicalFeatures.FreeChemicalFeature( fName, fName, Geometry.Point3D(xP, yP, zP))) rads.append(rad) self._initializeFeats(feats, rads)
def to_rdmol(plams_mol, sanitize=True): """ Translate a PLAMS molecule into an RDKit molecule type """ # Create rdkit molecule e = Chem.EditableMol(Chem.Mol()) for atom in plams_mol.atoms: a = Chem.Atom(atom.atnum) ch = atom.properties.charge if isinstance(ch, int): a.SetFormalCharge(ch) e.AddAtom(a) for bond in plams_mol.bonds: a1 = plams_mol.atoms.index(bond.atom1) a2 = plams_mol.atoms.index(bond.atom2) e.AddBond(a1, a2, Chem.BondType(bond.order)) rdmol = e.GetMol() if sanitize: Chem.SanitizeMol(rdmol) conf = Chem.Conformer() for a in range(len(plams_mol.atoms)): atom = plams_mol.atoms[a] p = Geometry.Point3D(atom._getx(), atom._gety(), atom._getz()) conf.SetAtomPosition(a, p) rdmol.AddConformer(conf) return rdmol
def hasMetalAcceptor(self, ligand, residue): """Get the presence or absence of a metal complexation where the residue is a metal""" metal = Chem.MolFromSmarts(self.prm["metallic"]["metal"]) lig = Chem.MolFromSmarts(self.prm["metallic"]["ligand"]) lig_matches = ligand.mol.GetSubstructMatches(lig) res_matches = residue.mol.GetSubstructMatches(metal) if lig_matches and res_matches: for lig_match in lig_matches: lig_atom = rdGeometry.Point3D( *ligand.coordinates[lig_match[0]]) for res_match in res_matches: res_atom = rdGeometry.Point3D( *residue.coordinates[res_match[0]]) dist = lig_atom.Distance(res_atom) if dist <= self.prm["metallic"]["distance"]: return 1 return 0
def test5errorHandling(self): refPts = ( Geometry.Point3D(0.0, 0.0, 0.0), Geometry.Point3D(1.0, 0.0, 0.0), Geometry.Point3D(0.0, 1.0, 0.0), Geometry.Point3D(0.0, 0.0, 1.0), ) prbPts = ( 1, 2, 3, 4, ) self.assertRaises(ValueError, lambda: rdAlg.GetAlignmentTransform(refPts, prbPts)) prbPts = () self.assertRaises(ValueError, lambda: rdAlg.GetAlignmentTransform(refPts, prbPts)) prbPts = 1 self.assertRaises(ValueError, lambda: rdAlg.GetAlignmentTransform(refPts, prbPts)) prbPts = ( Geometry.Point3D(2.0, 2.0, 3.0), Geometry.Point3D(3.0, 2.0, 3.0), Geometry.Point3D(2.0, 3.0, 3.0), (2.0, 2.0, 5.0), ) self.assertRaises(ValueError, lambda: rdAlg.GetAlignmentTransform(refPts, prbPts))
def CalculateTorsionAngles(mol, tors_list, tors_list_rings, confId=-1): """ Calculate the torsion angles for a list of non-ring and a list of ring torsions. Arguments: - mol: the molecule of interest - tors_list: list of non-ring torsions - tors_list_rings: list of ring torsions - confId: index of the conformation (default: first conformer) Return: list of torsion angles """ torsions = [] conf = mol.GetConformer(confId) for t, maxdev in tors_list: if len(t) == 1: t = t[0] p1, p2, p3, p4 = _getTorsionAtomPositions(t, conf) tors = (Geometry.ComputeSignedDihedralAngle(p1, p2, p3, p4) / math.pi) * 180.0 if tors < 0: tors += 360.0 # angle between 0 and 360 else: # loop over torsions and take minimum tors = 360.0 for t2 in t: p1, p2, p3, p4 = _getTorsionAtomPositions(t2, conf) tmp = (Geometry.ComputeSignedDihedralAngle(p1, p2, p3, p4) / math.pi) * 180.0 if tmp < 0: tmp += 360.0 # angle between 0 and 360 if tmp < tors: tors = tmp torsions.append((tors, maxdev)) # rings for t, maxdev in tors_list_rings: num = len(t) # loop over torsions and sum them up tors = 0 for t2 in t: p1, p2, p3, p4 = _getTorsionAtomPositions(t2, conf) tmp = abs( (Geometry.ComputeSignedDihedralAngle(p1, p2, p3, p4) / math.pi) * 180.0) tors += tmp tors /= num torsions.append((tors, maxdev)) return torsions
def GenerateSubshapeShape(self, cmpd, confId=-1, addSkeleton=True, **kwargs): shape = SubshapeObjects.ShapeWithSkeleton() shape.grid = Geometry.UniformGrid3D(self.gridDims[0], self.gridDims[1], self.gridDims[2], self.gridSpacing) AllChem.EncodeShape(cmpd, shape.grid, ignoreHs=False, confId=confId) if addSkeleton: conf = cmpd.GetConformer(confId) self.GenerateSubshapeSkeleton(shape, conf, **kwargs) return shape
def FindGridPointBetweenPoints(pt1,pt2,shapeGrid,winRad): center = pt1+pt2 center /= 2.0 d=1e8 while d>shapeGrid.GetSpacing(): count,centroid=Geometry.ComputeGridCentroid(shapeGrid,center,winRad) d = center.Distance(centroid) center = centroid return center
def detect(self, acceptor, donor): acceptor_matches = acceptor.GetSubstructMatches(self.acceptor) donor_matches = donor.GetSubstructMatches(self.donor) if acceptor_matches and donor_matches: for donor_match, acceptor_match in product(donor_matches, acceptor_matches): # D-H ... A d = Geometry.Point3D(*donor.xyz[donor_match[0]]) h = Geometry.Point3D(*donor.xyz[donor_match[1]]) a = Geometry.Point3D(*acceptor.xyz[acceptor_match[0]]) if d.Distance(a) <= self.distance: hd = h.DirectionVector(d) ha = h.DirectionVector(a) # get DHA angle angle = hd.AngleTo(ha) if angle_between_limits(angle, *self.angles): return True, acceptor_match[0], donor_match[1] return False, None, None
def test2Coords(self): m1 = Chem.MolFromSmiles('C1CCC1CC') coordMap = {0: Geometry.Point2D(0, 0), 1: Geometry.Point2D(1.5, 0), 2: Geometry.Point2D(1.5, 1.5), 3: Geometry.Point2D(0, 1.5)} rdDepictor.Compute2DCoords(m1, coordMap=coordMap) conf = m1.GetConformer(0) for i in range(4): self.assertTrue( ptEq(conf.GetAtomPosition(i), Geometry.Point3D(coordMap[i].x, coordMap[i].y, 0.0))) m1 = Chem.MolFromSmiles('CCC') try: rdDepictor.Compute2DCoords(m1, coordMap=coordMap) ok = 0 except ValueError: ok = 1 self.assertTrue(ok)
def _initializeFeats(self, feats): self._feats = [] for feat in feats: if isinstance(feat, ChemicalFeatures.MolChemicalFeature): pos = feat.GetPos() newFeat = ChemicalFeatures.FreeChemicalFeature(feat.GetFamily(), feat.GetType(), Geometry.Point3D(pos[0], pos[1], pos[2])) self._feats.append(newFeat) else: self._feats.append(feat)
def show_shape(viewer, mol, cid, shape): """Show the encoded shape for a conformer (cid) of a molecule in viewer. """ viewer.server.deleteAll() # write shape to file tmpFile = tempfile.mktemp('.grd') Geometry.WriteGridToFile(shape, tmpFile) viewer.ShowMol(mol, name='testMol', showOnly=True, confId=cid) viewer.server.loadSurface(tmpFile, 'testGrid', '', 2.5)
def SampleSubshape(self, subshape1, newSpacing): ogrid = subshape1.grid rgrid = Geometry.UniformGrid3D(self.gridDims[0], self.gridDims[1], self.gridDims[2], newSpacing) for idx in range(rgrid.GetSize()): l = rgrid.GetGridPointLoc(idx) v = ogrid.GetValPoint(l) rgrid.SetVal(idx, v) res = SubshapeObjects.ShapeWithSkeleton() res.grid = rgrid return res
def hasHydrophobic(self, ligand, residue): """Get the presence or absence of an hydrophobic interaction between a residue and a ligand""" # define SMARTS query as hydrophobic hydrophobic = Chem.MolFromSmarts(self.prm["hydrophobic"]["smarts"]) # get atom tuples matching query lig_matches = ligand.mol.GetSubstructMatches(hydrophobic) res_matches = residue.mol.GetSubstructMatches(hydrophobic) if lig_matches and res_matches: for lig_match in lig_matches: # define ligand atom matching query as 3d point lig_atom = rdGeometry.Point3D(*ligand.coordinates[lig_match[0]]) for res_match in res_matches: # define residue atom matching query as 3d point res_atom = rdGeometry.Point3D(*residue.coordinates[res_match[0]]) # compute distance between points dist = lig_atom.Distance(res_atom) if dist <= self.prm["hydrophobic"]["distance"]: return 1 return 0
def test3IssueSF1526844(self): t = Chem.MolFromSmiles('c1nc(N)ccc1') rdDepictor.Compute2DCoords(t, canonOrient=False) m2 = Chem.MolFromSmiles('c1nc(NC=O)ccc1') AlignDepict.AlignDepict(m2, t) expected = [Geometry.Point3D(1.5, 0.0, 0.0), Geometry.Point3D(0.75, -1.299, 0.0), Geometry.Point3D(-0.75, -1.299, 0.0), Geometry.Point3D(-1.5, -2.5981, 0.0), Geometry.Point3D(-3.0, -2.5981, 0.0), Geometry.Point3D(-3.75, -3.8971, 0.0), Geometry.Point3D(-1.5, 0.0, 0.0), Geometry.Point3D(-0.75, 1.2990, 0.0), Geometry.Point3D(0.75, 1.2990, 0.0)] nat = m2.GetNumAtoms() conf = m2.GetConformer() for i in range(nat): pos = conf.GetAtomPosition(i) self.assertTrue(ptEq(pos, expected[i], 0.001))
def check(mol): if not mol.GetNumAtoms() or mol.GetNumAtoms() == 1: return False if mol.GetNumConformers(): origin = Geometry.Point3D(0, 0, 0) conf = mol.GetConformer() for i in range(mol.GetNumAtoms()): p = conf.GetAtomPosition(i) d = p - origin if d.Length() > 0.0001: return False return True
def hasEdgeToFace(self, ligand, residue): """Get the presence or absence of an aromatic face to edge interaction between a residue and a ligand""" for pi_res in self.AROMATIC_PATTERNS: for pi_lig in self.AROMATIC_PATTERNS: res_matches = residue.mol.GetSubstructMatches(pi_res) lig_matches = ligand.mol.GetSubstructMatches(pi_lig) for lig_match in lig_matches: lig_pi_coords = ligand.coordinates[list(lig_match)] lig_centroid = rdGeometry.Point3D(*getCentroid(lig_pi_coords)) for res_match in res_matches: res_pi_coords = residue.coordinates[list(res_match)] res_centroid = rdGeometry.Point3D(*getCentroid(res_pi_coords)) dist = lig_centroid.Distance(res_centroid) if dist <= self.prm["aromatic"]["distance"]: # ligand lig_plane = rdGeometry.Point3D(*lig_pi_coords[0]) lig_centroid_plane = lig_centroid.DirectionVector(lig_plane) lig_normal = rdGeometry.Point3D(*getNormalVector(lig_centroid_plane)) # residue res_plane = rdGeometry.Point3D(*res_pi_coords[0]) res_centroid_plane = res_centroid.DirectionVector(res_plane) res_normal = rdGeometry.Point3D(*getNormalVector(res_centroid_plane)) # angle angle = degrees(res_normal.AngleTo(lig_normal)) if isinAngleLimits(angle, *self.prm["aromatic"]["EdgeToFace"]): return 1 return 0
def ob_mol_to_rd_mol(ob_mol): ''' Convert an OBMol to an RWMol, copying over the elements, coordinates, formal charges, bonds and aromaticity. ''' n_atoms = ob_mol.NumAtoms() rd_mol = Chem.RWMol() rd_conf = Chem.Conformer(n_atoms) for ob_atom in ob.OBMolAtomIter(ob_mol): rd_atom = Chem.Atom(ob_atom.GetAtomicNum()) rd_atom.SetFormalCharge(ob_atom.GetFormalCharge()) rd_atom.SetIsAromatic(ob_atom.IsAromatic()) rd_atom.SetNumExplicitHs(ob_atom.GetImplicitHCount()) rd_atom.SetNoImplicit(True) # don't use rdkit valence model rd_atom.SetHybridization(ob_hyb_to_rd_hyb(ob_atom)) idx = rd_mol.AddAtom(rd_atom) rd_coords = Geometry.Point3D( ob_atom.GetX(), ob_atom.GetY(), ob_atom.GetZ() ) rd_conf.SetAtomPosition(idx, rd_coords) rd_mol.AddConformer(rd_conf) for ob_bond in ob.OBMolBondIter(ob_mol): # OB uses 1-indexing, rdkit uses 0 i = ob_bond.GetBeginAtomIdx() - 1 j = ob_bond.GetEndAtomIdx() - 1 bond_order = ob_bond.GetBondOrder() if bond_order == 1: bond_type = Chem.BondType.SINGLE elif bond_order == 2: bond_type = Chem.BondType.DOUBLE elif bond_order == 3: bond_type = Chem.BondType.TRIPLE else: raise Exception('unknown bond order {}'.format(bond_order)) rd_mol.AddBond(i, j, bond_type) rd_bond = rd_mol.GetBondBetweenAtoms(i, j) rd_bond.SetIsAromatic(ob_bond.IsAromatic()) Chem.GetSSSR(rd_mol) # initialize ring info rd_mol.UpdatePropertyCache(strict=False) # compute valence return rd_mol
def _embed(mol, xyz): map_idx = atom_map(mol) assert map_idx is not None coordMap = {i: RDGeom.Point3D(*xyz[map_idx[i] - 1]) for i in map_idx} n = mol.GetNumAtoms() conf = Conformer(n) conf.Set3D(True) for i in range(n): conf.SetAtomPosition(i, coordMap[i]) ret = mol.AddConformer(conf, assignId=True) # not sure if this can fail, so just accept anything return ret
def testGetDrawCoords(self): m = Chem.MolFromSmiles('c1ccc(C)c(C)c1C') AllChem.Compute2DCoords(m) d = Draw.MolDraw2DSVG(300, 300) d.DrawMolecule(m) conf = m.GetConformer() for idx in range(m.GetNumAtoms()): pos = conf.GetAtomPosition(idx) pos = Geometry.Point2D(pos.x, pos.y) dpos1 = d.GetDrawCoords(idx) dpos2 = d.GetDrawCoords(pos) self.assertAlmostEqual(dpos1.x, dpos2.x, 6) self.assertAlmostEqual(dpos1.y, dpos2.y, 6)
def testCreateSGroup(self): mol = Chem.MolFromMolBlock(''' Mrv1810 10061910532D 0 0 0 0 0 999 V3000 M V30 BEGIN CTAB M V30 COUNTS 4 3 0 0 0 M V30 BEGIN ATOM M V30 1 O -14.8632 3.7053 0 0 M V30 2 C -13.3232 3.7053 0 0 M V30 3 O -11.7832 3.7053 0 0 M V30 4 * -10.2453 3.6247 0 0 M V30 END ATOM M V30 BEGIN BOND M V30 1 1 1 2 M V30 2 1 2 3 M V30 3 1 3 4 M V30 END BOND M V30 END CTAB M END''') self.assertTrue(mol is not None) mcpy = Chem.Mol(mol) sg = Chem.CreateMolSubstanceGroup(mcpy, "SRU") self.assertEqual(sg.GetProp("TYPE"), "SRU") sg = Chem.GetMolSubstanceGroupWithIdx(mcpy, 0) sg.AddBracket((Geometry.Point3D(-11.1, 4.6, 0), Geometry.Point3D(-11.1, 2.7, 0))) sg.AddBracket((Geometry.Point3D(-13.9, 2.7, 0), Geometry.Point3D(-13.9, 4.6, 0))) sg.AddAtomWithIdx(1) sg.AddAtomWithIdx(2) sg.AddBondWithIdx(0) sg.AddBondWithIdx(2) sg.SetProp("CONNECT", "HT") sg.SetProp("LABEL", "n") mb = Chem.MolToMolBlock(mcpy, forceV3000=True) self.assertNotEqual(mb.find('V30 1 SRU'), -1) self.assertNotEqual(mb.find('BRKXYZ'), -1) self.assertNotEqual(mb.find('CONNECT=HT'), -1)
def CalculateTorsionAngles(mol, tors_list, tors_list_rings, confId=-1): """ Calculate the torsion angles for a list of non-ring and a list of ring torsions. Arguments: - mol: the molecule of interest - tors_list: list of non-ring torsions - tors_list_rings: list of ring torsions - confId: index of the conformation (default: first conformer) Return: list of torsion angles """ torsions = [] conf = mol.GetConformer(confId) for quartets, maxdev in tors_list: tors = [] # loop over torsions and calculate angle for atoms in quartets: p1, p2, p3, p4 = _getTorsionAtomPositions(atoms, conf) tmpTors = (Geometry.ComputeSignedDihedralAngle(p1, p2, p3, p4) / math.pi) * 180.0 if tmpTors < 0: tmpTors += 360.0 # angle between 0 and 360 tors.append(tmpTors) torsions.append((tors, maxdev)) # rings for quartets, maxdev in tors_list_rings: num = len(quartets) # loop over torsions and sum them up tors = 0 for atoms in quartets: p1, p2, p3, p4 = _getTorsionAtomPositions(atoms, conf) tmpTors = abs( (Geometry.ComputeSignedDihedralAngle(p1, p2, p3, p4) / math.pi) * 180.0) tors += tmpTors tors /= num torsions.append(([tors], maxdev)) return torsions
def hasPiCation(self, ligand, residue): """Get the presence or absence of an interaction between a residue as a cation and a ligand as a pi system""" # check for residues matching cation smarts query cation = Chem.MolFromSmarts(self.prm["ionic"]["cation"]) res_matches = residue.mol.GetSubstructMatches(cation) if res_matches: # check for ligand matching pi query for pi in self.AROMATIC_PATTERNS: lig_matches = ligand.mol.GetSubstructMatches(pi) for res_match in res_matches: # cation as 3d point cat = rdGeometry.Point3D( *residue.coordinates[res_match[0]]) for lig_match in lig_matches: # get coordinates of atoms matching pi-system pi_coords = ligand.coordinates[list(lig_match)] # centroid of pi-system as 3d point centroid = rdGeometry.Point3D(*getCentroid(pi_coords)) # distance between cation and centroid dist = cat.Distance(centroid) if dist <= self.prm["pi-cation"]["distance"]: # compute angle between centroid-normal and centroid-cation vectors # get vector in the ring plane atom_plane = rdGeometry.Point3D(*pi_coords[0]) centroid_plane = centroid.DirectionVector( atom_plane) # vector normal to the ring plane centroid_normal = rdGeometry.Point3D( *getNormalVector(centroid_plane)) # vector between the centroid and the charge centroid_charge = centroid.DirectionVector(cat) angle = degrees( centroid_normal.AngleTo(centroid_charge)) if isinAngleLimits( angle, *self.prm["pi-cation"]["angle"]): return 1 return 0
def setUp(self): self.fdefBlock = """ DefineFeature HAcceptor1 [N,O;H0] Family HBondAcceptor Weights 1.0 EndFeature DefineFeature HDonor1 [N,O;!H0] Family HBondDonor Weights 1.0 EndFeature DefineFeature Aromatic1 c1ccccc1 Family Aromatic Weights 1.0,1.0,1.0,1.0,1.0,1.0 EndFeature\n""" self.featFactory = ChemicalFeatures.BuildFeatureFactoryFromString(self.fdefBlock) self.feats = [ChemicalFeatures.FreeChemicalFeature('HBondAcceptor', 'HAcceptor1', Geometry.Point3D(0.0, 0.0, 0.0)), ChemicalFeatures.FreeChemicalFeature('HBondDonor', 'HDonor1', Geometry.Point3D(2.65, 0.0, 0.0)), ChemicalFeatures.FreeChemicalFeature('Aromatic', 'Aromatic1', Geometry.Point3D(5.12, 0.908, 0.0)), ] self.pcophore = Pharmacophore.Pharmacophore(self.feats)
def test4points(self): refPts = ( Geometry.Point3D(0.0, 0.0, 0.0), Geometry.Point3D(1.0, 0.0, 0.0), Geometry.Point3D(0.0, 1.0, 0.0), Geometry.Point3D(0.0, 0.0, 1.0), ) prbPts = ( Geometry.Point3D(2.0, 2.0, 3.0), Geometry.Point3D(3.0, 2.0, 3.0), Geometry.Point3D(2.0, 3.0, 3.0), Geometry.Point3D(2.0, 2.0, 4.0), ) res = rdAlg.GetAlignmentTransform(refPts, prbPts) self.assertTrue(feq(res[0], 0.0))
def _parsePoint(self, txt): txt = txt.strip() startP = 0 endP = len(txt) if txt[0] == '(': startP += 1 if txt[-1] == ')': endP -= 1 txt = txt[startP:endP] splitL = txt.split(',') if len(splitL) != 3: raise ValueError('Bad location string') return Geometry.Point3D(float(splitL[0]), float(splitL[1]), float(splitL[2]))
def _initializeFeats(self, feats, radii): if len(feats) != len(radii): raise ValueError('len(feats)!=len(radii)') self._feats = [] self._radii = [] for feat, rad in zip(feats, radii): if isinstance(feat, ChemicalFeatures.MolChemicalFeature): pos = feat.GetPos() newFeat = ChemicalFeatures.FreeChemicalFeature(feat.GetFamily(), feat.GetType(), Geometry.Point3D(pos[0], pos[1], pos[2])) else: newFeat = feat self._feats.append(newFeat) self._radii.append(rad)
def hasHBacceptor(self, ligand, residue): """Get the presence or absence of a H-bond interaction between a residue as a donor and a ligand as an acceptor""" donor = Chem.MolFromSmarts(self.prm["HBond"]["donor"]) acceptor = Chem.MolFromSmarts(self.prm["HBond"]["acceptor"]) lig_matches = ligand.mol.GetSubstructMatches(acceptor) res_matches = residue.mol.GetSubstructMatches(donor) if lig_matches and res_matches: for res_match in res_matches: # D-H ... A d = rdGeometry.Point3D(*residue.coordinates[res_match[0]]) h = rdGeometry.Point3D(*residue.coordinates[res_match[1]]) for lig_match in lig_matches: a = rdGeometry.Point3D(*ligand.coordinates[lig_match[0]]) dist = d.Distance(a) if dist <= self.prm["HBond"]["distance"]: hd = h.DirectionVector(d) ha = h.DirectionVector(a) # get angle between hd and ha in degrees angle = degrees(hd.AngleTo(ha)) if isinAngleLimits(angle, *self.prm["HBond"]["angle"]): return 1 return 0
def hasXBacceptor(self, ligand, residue): """Get the presence or absence of a Halogen Bond where the residue acts as a donor""" donor = Chem.MolFromSmarts(self.prm["XBond"]["donor"]) acceptor = Chem.MolFromSmarts(self.prm["XBond"]["acceptor"]) lig_matches = ligand.mol.GetSubstructMatches(acceptor) res_matches = residue.mol.GetSubstructMatches(donor) if lig_matches and res_matches: for res_match in res_matches: # D-X ... A d = rdGeometry.Point3D(*residue.coordinates[res_match[0]]) x = rdGeometry.Point3D(*residue.coordinates[res_match[1]]) for lig_match in lig_matches: a = rdGeometry.Point3D(*ligand.coordinates[lig_match[0]]) dist = d.Distance(a) if dist <= self.prm["XBond"]["distance"]: xd = x.DirectionVector(d) xa = x.DirectionVector(a) # get angle between hd and ha in degrees angle = degrees(xd.AngleTo(xa)) if isinAngleLimits(angle, *self.prm["XBond"]["angle"]): return 1 return 0