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 _expand_states(molecules, enumerate='protonation', max_states=200, suppress_hydrogen=True, reasonable=True, carbon_hybridization=True, level=0, verbose=True): """ Expand the state specified by enumerate variable Parameters ---------- molecules: OEMol or list of OEMol molecule to expand states enumerate: str, optional, default='protonation' Kind of state to enumerate. Choice of protonation, tautomers, stereoiserms suppress_hydrogen: bool, optional, default=True If True, will suppress explicit hydrogen reasonable: bool, optional, default=True If True, will rank tautomers by the most reasonable energetically carbon_hybridization: bool, optional, default=True If True, will allow carbon to change hybridization max_states: int, optional, default=200 verbose: Bool, optional, deault=TRue Returns ------- states: list of OEMol enumerated states """ if type(molecules) != type(list()): molecules = [molecules] states = list() for molecule in molecules: ostream = oechem.oemolostream() ostream.openstring() ostream.SetFormat(oechem.OEFormat_SDF) states_enumerated = 0 if suppress_hydrogen: oechem.OESuppressHydrogens(molecule) if enumerate == 'protonation': formal_charge_options = oequacpac.OEFormalChargeOptions() formal_charge_options.SetMaxCount(max_states) formal_charge_options.SetVerbose(verbose) if verbose: logger().debug("Enumerating protonation states...") for protonation_state in oequacpac.OEEnumerateFormalCharges(molecule, formal_charge_options): states_enumerated += 1 oechem.OEWriteMolecule(ostream, protonation_state) states.append(protonation_state) if enumerate == 'tautomers': #max_zone_size = molecule.GetMaxAtomIdx() tautomer_options = oequacpac.OETautomerOptions() tautomer_options.SetMaxTautomersGenerated(max_states) tautomer_options.SetLevel(level) tautomer_options.SetRankTautomers(reasonable) tautomer_options.SetCarbonHybridization(carbon_hybridization) #tautomer_options.SetMaxZoneSize(max_zone_size) tautomer_options.SetApplyWarts(True) if verbose: logger().debug("Enumerating tautomers...") for tautomer in oequacpac.OEEnumerateTautomers(molecule, tautomer_options): states_enumerated += 1 states.append(tautomer) if enumerate == 'stereoisomers': if verbose: logger().debug("Enumerating stereoisomers...") for enantiomer in oeomega.OEFlipper(molecule, max_states, True): states_enumerated += 1 enantiomer = oechem.OEMol(enantiomer) oechem.OEWriteMolecule(ostream, enantiomer) states.append(enantiomer) return states
def mk_conformers(options, molecule, maxconf=99, verbose=True): """ Enumerate the list of conformers and associated properties for each protonation and tautomeric state. Parameters ---------- options molecule : openeye.oechem The molecule read from the PDB whose protomer and tautomer states are to be enumerated. maxconf : int, optional, default=128 Maximum number of protomers/tautomers to generate. Returns ------- conformers : list of Conformer The list of protomers/tautomers generated. """ conformers = list() formalChargeOptions = oequacpac.OEFormalChargeOptions(maxconf) tautomerOptions = oequacpac.OETautomerOptions(maxconf) # enumerate pka states index = 0 for pkaState in oequacpac.OEEnumerateFormalCharges(molecule, formalChargeOptions): if (index > maxconf): break # enumerate tautomers of pka states for tautomer in oequacpac.OEEnumerateTautomers(pkaState, tautomerOptions): if (index > maxconf): break # Assign conformer name. name = options.ligand+'%02d' % index tautomer.SetTitle(name) # DEBUG: Write molecule before charging. ofs = oechem.oemolostream() ofs.open(name + '-before.mol2') outmol = oechem.OEMol(tautomer) oechem.OEWriteMolecule(ofs, outmol) ofs.close() # Compute formal charge. oechem.OEAssignFormalCharges(tautomer) formal_charge = 0.0 for atom in tautomer.GetAtoms(): formal_charge += atom.GetFormalCharge() if verbose: print "formal charge: %d" % formal_charge # Assign canonical AM1BCC charges. assign_canonical_am1bcc_charges(tautomer) # DEBUG: Write molecule after charging. ofs = oechem.oemolostream() outmol = oechem.OEMol(tautomer) ofs.open(name + '-after.mol2') oechem.OEWriteMolecule(ofs, outmol) ofs.close() # Create conformer. conformer = Conformer(name, formal_charge, tautomer) # Append to protomer/tautomer list. conformers.append(conformer) # Keep count of protomers/tautomers. index += 1 # Show output if requested. if verbose: print "%12s %+5d %8d atoms" % (name, conformer.charge, conformer.natoms) if verbose: print "%d protomer/tautomer states were enumerated" % len(conformers) return conformers
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