Source code for openpharmacophore.screening.screening

from collections import namedtuple
import os
from rdkit import RDConfig, RDLogger
from rdkit import Chem
from rdkit.Chem import ChemicalFeatures, rdDistGeom
from rdkit.Chem.Pharm3D import EmbedLib

from openpharmacophore import LigandBasedPharmacophore, \
    LigandReceptorPharmacophore, Pharmacophore, Ligand
from openpharmacophore.pharmacophore.rdkit_pharmacophore import pharmacophore_to_rdkit
from openpharmacophore.pharmacophore.align import align_ligand_to_pharmacophore


Match = namedtuple("Match", ["ligand", "rmsd"])
RDLogger.DisableLog('rdApp.*')  # Disable rdkit warnings


[docs]class VirtualScreening: """ Class to perform virtual screening with pharmacophores.""" feature_factory = ChemicalFeatures.BuildFeatureFactory( os.path.join(RDConfig.RDDataDir, 'BaseFeatures.fdef')) def __init__(self, pharmacophores): self._pharmacophores = self.add_pharmacophores(pharmacophores) self._matches = [[] for _ in range(len(pharmacophores))] self._fails = [0] * len(pharmacophores) @property def n_pharmacophores(self) -> int: return len(self._pharmacophores) @property def pharmacophores(self): return self._pharmacophores @property def fails(self): return self._fails @property def matches(self): return self._matches
[docs] @staticmethod def add_pharmacophores(pharmacophores): """ Add new pharmacophores. """ pharma_list = [] for pharma in pharmacophores: if isinstance(pharma, (LigandReceptorPharmacophore, LigandBasedPharmacophore)): for ph in pharma: pharma_list.append(ph) elif isinstance(pharma, Pharmacophore): pharma_list.append(pharma) else: raise TypeError(f"Unexpected type {type(pharma)}") return pharma_list
[docs] def screen(self, db): """ Screen a database of molecules with each of the pharmacophores. Parameters --------- db : InMemoryMolDB or MolDB The database with the molecules. """ # TODO: add progress bar for ii, pharma in enumerate(self._pharmacophores): pharma = pharmacophore_to_rdkit(pharma) for lig in db: lig = lig.to_rdkit() mappings = self._feature_mappings(lig, pharma) if len(mappings) > 0: atom_match = [list(x.GetAtomIds()) for x in mappings] lig = Chem.AddHs(lig) result = align_ligand_to_pharmacophore(lig, atom_match, pharma) if result is not None: aligned_mol, rmsd = result self._matches[ii].append(Match(Ligand(aligned_mol), rmsd)) else: self._fails[ii] += 1 else: self._fails[ii] += 1
@staticmethod def _feature_mappings(ligand, pharmacophore): """ Maps the chemical features in the given ligand to those of the pharmacophore. Parameters ---------- ligand : rdkit.Mol pharmacophore : rdkit.Chem.Pharm3D.Pharmacophore Returns ------- list [rdkit.MolChemicalFeature] """ can_match, all_matches = EmbedLib.MatchPharmacophoreToMol( ligand, VirtualScreening.feature_factory, pharmacophore) if can_match: bounds_matrix = rdDistGeom.GetMoleculeBoundsMatrix(ligand) failed, _, matched_features, _ = EmbedLib.MatchPharmacophore( all_matches, bounds_matrix, pharmacophore, useDownsampling=True) return matched_features return []