Source code for molsystem.openeye

# -*- coding: utf-8 -*-

"""Interface to OpenEye OEChem."""

import logging

try:
    from openeye import oechem
except ModuleNotFoundError:
    oechem_available = False
    oechem_licensed = False
else:
    oechem_available = True
    oechem_licensed = oechem.OEChemIsLicensed()

logger = logging.getLogger(__name__)


[docs] def check_openeye_license(): if not oechem_available: raise RuntimeError( "OpenEye OEChem is not installed! See " "https://docs.eyesopen.com/toolkits/python/index.html for detail" ) if not oechem_licensed: raise RuntimeError( "Cannot find a license for OpenEye OEChem! See " "https://docs.eyesopen.com/toolkits/python/index.html for detail" )
[docs] def openeye_version(): """The version of the OpenEye OEChem toolkit.""" if not oechem_available: return None return oechem.OEChemGetVersion()
[docs] class OpenEyeMixin: """A mixin for handling OpenEye's software via its Python interface."""
[docs] def to_OEGraphMol(self, properties=None): """Return an OEGraphMol object for the configuration, template, or subset.""" check_openeye_license() oe_mol = oechem.OEGraphMol() if self.__class__.__name__ == "_Configuration": oe_mol.SetIntData("net charge", self.charge) oe_mol.SetIntData("spin multiplicity", self.spin_multiplicity) # Create the atoms oe_atoms = [] if "charge" in self.atoms: charges = self.atoms.get_column_data("charge") for atno, xyz, q in zip( self.atoms.atomic_numbers, self.atoms.coordinates, charges ): oe_atom = oe_mol.NewAtom(atno) oe_mol.SetCoords(oe_atom, xyz) oe_atom.SetPartialCharge(q) oe_atoms.append(oe_atom) else: for atno, xyz in zip(self.atoms.atomic_numbers, self.atoms.coordinates): oe_atom = oe_mol.NewAtom(atno) oe_mol.SetCoords(oe_atom, xyz) oe_atoms.append(oe_atom) # and bonds index = {j: i for i, j in enumerate(self.atoms.ids)} for row in self.bonds.bonds(): oe_mol.NewBond( oe_atoms[index[row["i"]]], oe_atoms[index[row["j"]]], row["bondorder"] ) if properties == "all": data = self.properties.get("all", include_system_properties=True) for key, value in data.items(): _type = self.properties.type(key) if _type == "int": oe_mol.SetIntData(key, value) elif _type == "float": oe_mol.SetDoubleData(key, value) elif _type == "str": oe_mol.SetStringData(key, value) else: raise ValueError(f"Can't handle property of type '{_type}'") # Units, if any units = self.properties.units(key) if units is not None and units != "": tmp = key.split("#", maxsplit=1) if len(tmp) > 1: oe_mol.SetStringData(tmp[0] + ",units" + "#" + tmp[1], units) else: oe_mol.SetStringData(key + ",units", units) return oe_mol
[docs] def from_OEMol( self, oe_mol, properties="all", atoms=True, coordinates=True, bonds=True ): """Transform an OpenEye molecule into the current object.""" check_openeye_license() atnos = [] Xs = [] Ys = [] Zs = [] qs = [] for oe_atom in oe_mol.GetAtoms(): atno = oe_atom.GetAtomicNum() atnos.append(atno) x, y, z = oe_mol.GetCoords(oe_atom) Xs.append(x) Ys.append(y) Zs.append(z) qs.append(oe_atom.GetPartialCharge()) index = {at: i for i, at in enumerate(oe_mol.GetAtoms())} Is = [] Js = [] BondOrders = [] for oe_bond in oe_mol.GetBonds(): oe_i = oe_bond.GetBgn() oe_j = oe_bond.GetEnd() i = index[oe_i] j = index[oe_j] bondorder = oe_bond.GetOrder() Is.append(i) Js.append(j) BondOrders.append(bondorder) logger.debug(f"bond {i} - {j} {bondorder}") if atoms: self.clear() # Get the property data, cast to correct type data = {} for tmp in oe_mol.GetDataIter(): tag = tmp.GetTag() attribute = oechem.OEGetTag(tag) value = oe_mol.GetData(tag) data[attribute] = value # Check for property items for charge and multiplicity if self.__class__.__name__ == "_Configuration": if "net charge" in data: self.charge = int(data["net charge"]) if "spin multiplicity" in data: self.spin_multiplicity = int(data["spin multiplicity"]) if atoms: if any([i != 0.0 for i in qs]): if "formal_charge" not in self.atoms: self.atoms.add_attribute("charge", coltype="float", default=0) ids = self.atoms.append(x=Xs, y=Ys, z=Zs, atno=atnos, charge=qs) else: ids = self.atoms.append(x=Xs, y=Ys, z=Zs, atno=atnos) else: ids = self.atoms.ids if coordinates: xyz = [[x, y, z] for x, y, z in zip(Xs, Ys, Zs)] self.atoms.coordinates = xyz if atoms or bonds: i = [ids[x] for x in Is] j = [ids[x] for x in Js] self.bonds.append(i=i, j=j, bondorder=BondOrders) # Record any properties in the database if desired if properties == "all": for key, value in data.items(): if ",units" not in key and key not in [ "", "net charge", "spin multiplicity", ]: if not self.properties.exists(key): tmp = key.split("#", maxsplit=1) if len(tmp) > 1: units_key = tmp[0] + ",units" + "#" + tmp[1] else: units_key = key + ",units" _type = value.__class__.__name__ if units_key in data: units = data[units_key] self.properties.add(key, _type, units=units) else: self.properties.add(key, _type) self.properties.put(key, value) return self