def enumerate_from_smiles(smiles, oe_options=None): oe_options = oe_options or OEOptions() omegaOpts = oeomega.OEOmegaOptions(oeomega.OEOmegaSampling_Pose) omegaOpts.SetMaxSearchTime(60) omega = oeomega.OEOmega(omegaOpts) if oe_options.use_tautomer: tautomer_options = oequacpac.OETautomerOptions() pKa_norm = True taut_iter = lambda x: oequacpac.OEGetReasonableTautomers(x, tautomer_options, pKa_norm) else: taut_iter = lambda x: [x] if oe_options.use_flipper: flipper = lambda x: oeomega.OEFlipper(x.GetActive(), oe_options.num_sterocenters, oe_options.force_flipper) else: flipper = lambda x: [x] # get molecule try: molecule = mol_from_smiles(smiles) except ValueError: return [None] results = [] for enantiomer in flipper(molecule): for tautomer in taut_iter(enantiomer): tautomer = oechem.OEMol(tautomer) omega.Build(tautomer) tautomer2 = oechem.OEMol(tautomer) results.append(tautomer2) return results
def generate_tautomers(molecule: oechem.OEGraphMol) -> List[oechem.OEGraphMol]: """ Generate reasonable tautomers of a given molecule. Parameters ---------- molecule: oechem.OEGraphMol An OpenEye molecule. Returns ------- tautomers: list of oechem.OEGraphMol A list of OpenEye molecules holding the tautomers. """ from openeye import oechem, oequacpac tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetMaxTautomersGenerated(4096) tautomer_options.SetMaxTautomersToReturn(16) tautomer_options.SetCarbonHybridization(True) tautomer_options.SetMaxZoneSize(50) tautomer_options.SetApplyWarts(True) pKa_norm = True tautomers = [ oechem.OEGraphMol(tautomer) for tautomer in oequacpac.OEGetReasonableTautomers( molecule, tautomer_options, pKa_norm) ] return tautomers
def main(argv=[__name__]): if len(argv) != 3: oechem.OEThrow.Usage("%s <mol-infile> <mol-outfile>" % argv[0]) ifs = oechem.oemolistream() if not ifs.open(argv[1]): oechem.OEThrow.Fatal("Unable to open %s for reading" % argv[1]) ofs = oechem.oemolostream() if not ofs.open(argv[2]): oechem.OEThrow.Fatal("Unable to open %s for writing" % argv[2]) # @ <SNIPPET-EnumerateTautomersWithOptions> tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetMaxTautomersGenerated(4096) tautomer_options.SetMaxTautomersToReturn(16) tautomer_options.SetCarbonHybridization(True) tautomer_options.SetMaxZoneSize(50) tautomer_options.SetApplyWarts(True) pKa_norm = True for mol in ifs.GetOEGraphMols(): for tautomer in oequacpac.OEGetReasonableTautomers( mol, tautomer_options, pKa_norm): # work with tautomer # @ </SNIPPET-EnumerateTautomersWithOptions> oechem.OEWriteMolecule(ofs, tautomer) return 0
def _enumerate_tautomers(molecule, max_states=200, pka_norm=True, warts=True): """ Expand reasonable tautomer states. This function generates tautomers (which might be different ionization states than parent) that are normalized to the predominant state at pH ~7.4 Parameters ---------- molecule : OEMol to expand states max_states : int max number of states pka_norm: bool, optional, default True warts: bool, optional default True Returns ------- tautomers: list of oemols """ from openeye import oequacpac tautomers = [] tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetApplyWarts(warts) tautomer_options.SetMaxTautomersGenerated(max_states) for tautomer in oequacpac.OEGetReasonableTautomers(molecule, tautomer_options, pka_norm): tautomers.append(tautomer) return tautomers
def from_oemol(self, from_oemol): with self.logger("from_oemol") as logger: tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetMaxTautomersGenerated(4096) tautomer_options.SetMaxTautomersToReturn(16) tautomer_options.SetCarbonHybridization(True) tautomer_options.SetMaxZoneSize(50) tautomer_options.SetApplyWarts(True) pKa_norm = True omegaOpts = oeomega.OEOmegaOptions(oeomega.OEOmegaSampling_Pose) omegaOpts.SetStrictAtomTypes(False) omegaOpts.SetSampleHydrogens(True) omegaOpts.SetMaxSearchTime(30) omegaOpts.SetFixDeleteH(True) omega = oeomega.OEOmega(omegaOpts) options = oeshape.OEROCSOptions() overlayoptions = oeshape.OEOverlayOptions() overlayoptions.SetOverlapFunc( oeshape.OEOverlapFunc(oeshape.OEAnalyticShapeFunc())) options.SetOverlayOptions(overlayoptions) # options.SetNumBestHits(10) options.SetConfsPerHit(200) # options.SetMaxHits(10000) rocs = oeshape.OEROCS(options) for tautomer in oequacpac.OEGetReasonableTautomers( from_oemol, tautomer_options, pKa_norm): logger.log("got enantiomer") for enantiomer in oeomega.OEFlipper(tautomer, 4, False): logger.log("got tautomer ") enantiomer_ = oechem.OEMol(enantiomer) ret_code = omega.Build(enantiomer_) if ret_code != oeomega.OEOmegaReturnCode_Success: logger.error("got oemeg_failed", oeomega.OEGetOmegaError(ret_code)) else: rocs.AddMolecule(oechem.OEMol(enantiomer_)) for res in rocs.Overlay(self.refmol): outmol = oechem.OEMol(res.GetOverlayConfs()) good_mol = oechem.OEMol(outmol) oechem.OEAddExplicitHydrogens(good_mol) oechem.OEClearSDData(good_mol) oeshape.OEDeleteCompressedColorAtoms(good_mol) oeshape.OEClearCachedSelfColor(good_mol) oeshape.OEClearCachedSelfShape(good_mol) oeshape.OERemoveColorAtoms(good_mol) return good_mol logger.error("Returning None.") return None
def dock_molecule_to_receptor(molecule, receptor_filename, covalent=False): """ Dock the specified molecules, writing out to specified file Parameters ---------- molecule : oechem.OEMol The molecule to dock receptor_filename : str Receptor to dock to covalent : bool, optional, default=False If True, try to place covalent warheads in proximity to CYS145 Returns ------- docked_molecule : openeye.oechem.OEMol Returns the best tautomer/protomer in docked geometry, annotated with docking score None is returned if no viable docked pose found """ import os # Extract the fragment name for the receptor fragment = extract_fragment_from_filename(receptor_filename) # Read the receptor from openeye import oechem, oedocking receptor = oechem.OEGraphMol() if not oedocking.OEReadReceptorFile(receptor, receptor_filename): oechem.OEThrow.Fatal("Unable to read receptor") #print(f'Receptor has {receptor.NumAtoms()} atoms') if not oedocking.OEReceptorHasBoundLigand(receptor): raise Exception("Receptor does not have bound ligand") #print('Initializing receptor...') dockMethod = oedocking.OEDockMethod_Hybrid2 dockResolution = oedocking.OESearchResolution_High dock = oedocking.OEDock(dockMethod, dockResolution) success = dock.Initialize(receptor) # Add covalent restraint if specified warheads_found = find_warheads(molecule) if covalent and len(warheads_found) > 0: warheads_found = set(warheads_found.keys()) # Initialize covalent constraints customConstraints = oedocking.OEReceptorGetCustomConstraints(receptor) # Find CYS145 SG atom hv = oechem.OEHierView(receptor) hres = hv.GetResidue("A", "CYS", 145) proteinHeavyAtom = None for atom in hres.GetAtoms(): if atom.GetName().strip() == 'SG': proteinHeavyAtom = atom break if proteinHeavyAtom is None: raise Exception('Could not find CYS145 SG') # Add the constraint feature = customConstraints.AddFeature() feature.SetFeatureName("CYS145 proximity") for warhead_type in warheads_found: smarts = covalent_warhead_smarts[warhead_type] print(f'Adding constraint for SMARTS pattern {smarts}') feature.AddSmarts(smarts) sphereRadius = 4.0 # Angstroms sphereCenter = oechem.OEFloatArray(3) receptor.GetCoords(proteinHeavyAtom, sphereCenter) sphere = feature.AddSphere() sphere.SetRad(sphereRadius) sphere.SetCenter(sphereCenter[0], sphereCenter[1], sphereCenter[2]) oedocking.OEReceptorSetCustomConstraints(receptor, customConstraints) # Enumerate tautomers from openeye import oequacpac tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetMaxTautomersGenerated(4096) tautomer_options.SetMaxTautomersToReturn(16) tautomer_options.SetCarbonHybridization(True) tautomer_options.SetMaxZoneSize(50) tautomer_options.SetApplyWarts(True) pKa_norm = True tautomers = [ oechem.OEMol(tautomer) for tautomer in oequacpac.OEGetReasonableTautomers(molecule, tautomer_options, pKa_norm) ] # Set up Omega #print('Expanding conformers...') from openeye import oeomega #omegaOpts = oeomega.OEOmegaOptions(oeomega.OEOmegaSampling_Dense) omegaOpts = oeomega.OEOmegaOptions() #omegaOpts.SetMaxConfs(5000) omegaOpts.SetMaxSearchTime(60.0) # time out omega = oeomega.OEOmega(omegaOpts) omega.SetStrictStereo(False) # enumerate sterochemistry if uncertain # Dock tautomers docked_molecules = list() from tqdm import tqdm for mol in tautomers: dockedMol = oechem.OEGraphMol() # Expand conformers omega.Build(mol) # Dock molecule retCode = dock.DockMultiConformerMolecule(dockedMol, mol) if (retCode != oedocking.OEDockingReturnCode_Success): #print("Docking Failed with error code " + oedocking.OEDockingReturnCodeGetName(retCode)) continue # Store docking data sdtag = oedocking.OEDockMethodGetName(dockMethod) oedocking.OESetSDScore(dockedMol, dock, sdtag) oechem.OESetSDData(dockedMol, "docked_fragment", fragment) dock.AnnotatePose(dockedMol) docked_molecules.append( dockedMol.CreateCopy() ) if len(docked_molecules) == 0: return None # Select the best-ranked molecule and pose # Note that this ignores protonation state and tautomer penalties docked_molecules.sort(key=score) best_molecule = docked_molecules[0] return best_molecule
def run_docking(receptor, molecules, dock_method, num_poses=1, docking_poses_save_path=None): """ Dock molecules into a prepared receptor. Parameters ---------- receptor: oechem.OEGraphMol An oechem.OEGraphMol object holding the prepared receptor. molecules: list of oechem.OEGraphMol A list of oechem.OEGraphMol objects holding prepared molecules for docking. dock_method: int Constant defining the docking method. num_poses: int Number of docking poses to generate per molecule. docking_poses_save_path: str File path for saving docking poses. If docking_poses_save_path is not provided, docking poses will not be saved. Returns ------- docked_molecules: list of oechem.OEGraphMol A list of oechem.OEGraphMol objects holding the docked molecules. """ # Standard libraries import pathlib # External libraries from openeye import oechem, oedocking, oequacpac, oeomega # initialize receptor dock_resolution = oedocking.OESearchResolution_High dock = oedocking.OEDock(dock_method, dock_resolution) dock.Initialize(receptor) def score(molecule, dock=dock): """Return the docking score.""" value = oechem.OEGetSDData(molecule, dock.GetName()) return float(value) docked_molecules = list() # dock molecules for molecule in molecules: # enumerate tautomers tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetMaxTautomersGenerated(4096) tautomer_options.SetMaxTautomersToReturn(16) tautomer_options.SetCarbonHybridization(True) tautomer_options.SetMaxZoneSize(50) tautomer_options.SetApplyWarts(True) pKa_norm = True tautomers = [ oechem.OEMol(tautomer) for tautomer in oequacpac.OEGetReasonableTautomers( molecule, tautomer_options, pKa_norm) ] # set up omega omega_options = oeomega.OEOmegaOptions() omega_options.SetMaxSearchTime(60.0) # time out omega = oeomega.OEOmega(omega_options) omega.SetStrictStereo(False) # enumerate stereochemistry if uncertain docked_tautomers = list() # dock tautomers for mol in tautomers: docked_mol = oechem.OEMol() # expand conformers omega.Build(mol) # dock molecule return_code = dock.DockMultiConformerMolecule( docked_mol, mol, num_poses) if return_code != oedocking.OEDockingReturnCode_Success: print( f'Docking failed for molecule with title {mol.GetTitle()} with error code ' f'{oedocking.OEDockingReturnCodeGetName(return_code)}.') continue # store docking data oedocking.OESetSDScore(docked_mol, dock, dock.GetName()) # expand conformations for conformation in docked_mol.GetConfs(): docked_tautomers.append(oechem.OEGraphMol(conformation)) # sort all conformations of all tautomers by score docked_tautomers.sort(key=score) # keep number of conformations as specified by num_poses docked_molecules += docked_tautomers[:num_poses] if len(docked_molecules) == 0: return None # save docking poses if docking_poses_save_path is not None: write_mols(docked_molecules, str(pathlib.Path(docking_poses_save_path).absolute())) return docked_molecules