def _load_verify_openeye(self, oechemlicensepath=None): """Loads required OpenEye libraries and checks licenses Parameters ---------- oechemlicensepath : str, optional, default=None OpenEye license path to use, or None if environment variables are to be used. Raises ------ RuntimeError If OE_LICENSE is not found as an environment variable If A valid license is missing Notes ----- Needs to be run before any of the other functions to assure OpenEye libraries are accessible. """ # Don't do anything if we've already imported OpenEye toolkit. if self.oechem: return try: # Import the OpenEye toolkit components. from openeye import oechem # For chemical objects from openeye import oeiupac # For IUPAC conversion from openeye import oeomega # For conformer generation from openeye import oequacpac # For pKa estimations except Exception as e: raise Exception("Could not import `openeye` library. Make sure OpenEye Python Toolkit is installed and on PYTHONPATH.") import os if oechemlicensepath is not None: os.environ['OE_LICENSE'] = oechemlicensepath try: os.environ['OE_LICENSE'] # See if license path is set. except KeyError: raise RuntimeError("Environment variable OE_LICENSE needs to be set.") if not oechem.OEChemIsLicensed(): # Check for OEchem TK license. raise RuntimeError("No valid license available for OEChem TK.") if not oeiupac.OEIUPACIsLicensed(): # Check for Lexichem TK license. raise RuntimeError("No valid license available for Lexichem TK.") if not oeomega.OEOmegaIsLicensed(): # Check for Omega TK license. raise RuntimeError("No valid license for Omega TK.") if not oequacpac.OEQuacPacIsLicensed(): # Check for Quacpac TK license. raise RuntimeError("No valid license for Quacpac TK.") #Attach libraries to the instance to only load and check them once at initialization. self.oechem = oechem self.oeiupac = oeiupac self.oeomega = oeomega self.oequacpac = oequacpac return
def is_openeye_installed(): try: from openeye import oechem from openeye import oequacpac from openeye import oeiupac from openeye import oeomega if not (oechem.OEChemIsLicensed() and oequacpac.OEQuacPacIsLicensed() and oeiupac.OEIUPACIsLicensed() and oeomega.OEOmegaIsLicensed()): raise ImportError except ImportError: return False return True
def get_unique_protomer(molecule): """ Generate unique protomer for all tuatomers and charge states of the moelcule. **Requires openeye license** Parameters ---------- molecule: oechem.OEMol Will convert `rdkit.Chem.Mol` to `oechem.OEMol` if openeye is installed and license is valid Returns ------- str unique protomer """ molecule = deepcopy(molecule) # This only works for OpenEye # Todo There might be a way to use different layers of InChI for this purpose. # Not all tautomers are recognized as the same by InChI so it won't capture all tautomers. # But if we use only the formula and connectivity level we might be able to capture a larger subset. # if has_openeye: from openeye import oequacpac, oechem else: raise RuntimeError("Must have OpenEye for unique protomer feature") if not oechem.OEChemIsLicensed(): raise ImportError("Must have OEChem license!") if not oequacpac.OEQuacPacIsLicensed(): raise ImportError("Must have OEQuacPac license!") if has_rdkit: if isinstance(molecule, rd.Chem.rdchem.Mol): # convert to openeye molecule # Maybe we shouldn't do this. smiles = rd.Chem.MolToSmiles(molecule) molecule = oechem.OEMol() oechem.OESmilesToMol(molecule, smiles) molecule_copy = deepcopy(molecule) oequacpac.OEGetUniqueProtomer(molecule_copy, molecule) return oechem.OEMolToSmiles(molecule_copy)
try: openmm.Platform.getPlatformByName("CUDA") hasCUDA = True except Exception: logging.info("CUDA unavailable on this system.") hasCUDA = False try: from openeye import oechem if not oechem.OEChemIsLicensed(): raise (ImportError("Need License for OEChem!")) from openeye import oequacpac if not oequacpac.OEQuacPacIsLicensed(): raise (ImportError("Need License for oequacpac!")) from openeye import oeiupac if not oeiupac.OEIUPACIsLicensed(): raise (ImportError("Need License for OEOmega!")) from openeye import oeomega if not oeomega.OEOmegaIsLicensed(): raise (ImportError("Need License for OEOmega!")) hasOpenEye = True openeye_exception_message = str() except Exception as e: hasOpenEye = False openeye_exception_message = str(e)
def get_charges(molecule, max_confs=800, strict_stereo=True, normalize=True, keep_confs=None, legacy=True): """Generate charges for an OpenEye OEMol molecule. Parameters ---------- molecule : OEMol Molecule for which to generate conformers. Omega will be used to generate max_confs conformations. max_confs : int, optional, default=800 Max number of conformers to generate strictStereo : bool, optional, default=True If False, permits smiles strings with unspecified stereochemistry. See https://docs.eyesopen.com/omega/usage.html normalize : bool, optional, default=True If True, normalize the molecule by checking aromaticity, adding explicit hydrogens, and renaming by IUPAC name. keep_confs : int, optional, default=None If None, apply the charges to the provided conformation and return this conformation, unless no conformation is present. Otherwise, return some or all of the generated conformations. If -1, all generated conformations are returned. Otherwise, keep_confs = N will return an OEMol with up to N generated conformations. Multiple conformations are still used to *determine* the charges. legacy : bool, default=True If False, uses the new OpenEye charging engine. See https://docs.eyesopen.com/toolkits/python/quacpactk/OEProtonFunctions/OEAssignCharges.html# Returns ------- charged_copy : OEMol A molecule with OpenEye's recommended AM1BCC charge selection scheme. Notes ----- Roughly follows http://docs.eyesopen.com/toolkits/cookbook/python/modeling/am1-bcc.html """ # If there is no geometry, return at least one conformation. if molecule.GetConfs() == 0: keep_confs = 1 if not oechem.OEChemIsLicensed(): raise (ImportError("Need License for OEChem!")) if not oequacpac.OEQuacPacIsLicensed(): raise (ImportError("Need License for oequacpac!")) if normalize: molecule = normalize_molecule(molecule) else: molecule = oechem.OEMol(molecule) charged_copy = generate_conformers( molecule, max_confs=max_confs, strict_stereo=strict_stereo) # Generate up to max_confs conformers if not legacy: # 2017.2.1 OEToolkits new charging function status = oequacpac.OEAssignCharges(charged_copy, oequacpac.OEAM1BCCCharges()) if not status: raise (RuntimeError("OEAssignCharges failed.")) else: # AM1BCCSym recommended by Chris Bayly to KAB+JDC, Oct. 20 2014. status = oequacpac.OEAssignPartialCharges( charged_copy, oequacpac.OECharges_AM1BCCSym) if not status: raise (RuntimeError( "OEAssignPartialCharges returned error code %d" % status)) #Determine conformations to return if keep_confs == None: #If returning original conformation original = molecule.GetCoords() #Delete conformers over 1 for k, conf in enumerate(charged_copy.GetConfs()): if k > 0: charged_copy.DeleteConf(conf) #Copy coordinates to single conformer charged_copy.SetCoords(original) elif keep_confs > 0: logger().debug( "keep_confs was set to %s. Molecule positions will be reset." % keep_confs) #Otherwise if a number is provided, return this many confs if available for k, conf in enumerate(charged_copy.GetConfs()): if k > keep_confs - 1: charged_copy.DeleteConf(conf) elif keep_confs == -1: #If we want all conformations, continue pass else: #Not a valid option to keep_confs raise (ValueError('Not a valid option to keep_confs in get_charges.')) return charged_copy