def get_smiles_similarity_indigo(smiles1, smiles2, fp_type="sub", metric="tanimoto"): """ Calculates the structural similarity between the SMILES of two compounds by means of the Indigo package. fp_type: sim | sub - "sim" = similarity fingerprints: shorter - "sub" = substructure fingerprints: more descriptive metric: tanimoto | tversky """ import indigo as indigo if len(smiles1) == 0 or len(smiles2) == 0: return None ind = indigo.Indigo() # Sometimes the SMILES are not correct, and they fail when loading. This is why I have introduced this exception #try: m = ind.loadMolecule(smiles1) m2 = ind.loadMolecule(smiles2) #except indigo.IndigoException: # return None m.aromatize() fp = m.fingerprint(fp_type) m2.aromatize() # Aromatize molecules in case they are not in aromatic form fp2 = m2.fingerprint( fp_type) # Calculate similarity between "similarity" fingerprints d = ind.similarity(fp, fp2, metric) return d
def amend_smiles(smi,ioks): """ in case Indigo cannot parse a SMILES, amend this by calling """ obj = indigo.Indigo() # some failure is due to stereo chem, now remove it if not ioks.parse_status: _pat = re.compile("\@") smi = re.sub("", s1) iok = T try: _m = obj.loadMolecule(smi) except: print(' ** reload mol failed after removing stereochemistry') iok = F ioks.parse_status = iok else: # failure largely due to aromization problem m = obj.loadMolecule(smi) _bom = get_bo_matrix(m) #_m.unfolderHydrogens() na = _m.countAtoms() _bom = get_bo_matrix(_m) chgs = np.array([_m.getAtom(i).charge() for i in range(na)],np.int) zs = np.array([m.getAtom(i).atomicNumber() for i in range(na)],np.int) tvsi = [] nrmax = 0 nbmax = 0 iok, bom = cf.update_bom(nrmax,nbmax,zs,tvsi,_bom,F) blk = (zs,chgs,bom,coords) rawm = rawmol_indigo(blk) return rawm.m
def get_mcs_indices_indigo(m_sdf, t_sdf, timeout=None, exact=False): import indigo indigo = indigo.Indigo() m_mol = indigo.loadMolecule(m_sdf) t_mol = indigo.loadMolecule(t_sdf) # find common substructure arr = indigo.createArray() arr.arrayAdd(m_mol) arr.arrayAdd(t_mol) mcs = indigo.extractCommonScaffold(arr, 'exact' if exact else 'approx') # match to scaffold query = indigo.loadQueryMolecule(mcs.smiles()) m_match = indigo.substructureMatcher(m_mol).match(query) t_match = indigo.substructureMatcher(t_mol).match(query) # atom indices of match m_atoms = [m_match.mapAtom(a) for a in query.iterateAtoms()] t_atoms = [t_match.mapAtom(a) for a in query.iterateAtoms()] m_indices = [a.index() for a in m_atoms if a is not None] t_indices = [a.index() for a in t_atoms if a is not None] return m_indices, t_indices
def rotatable_bonds(smiles): """ Find the number of rotatable bonds in a molecule. Rotatable bonds are defined as any single bond, not in a ring, bound to a nonterminal heavy (i.e., non-hydrogen) atom. Excluded from the count are amide C-N bonds because of their high rotational energy barrier. The SMARTS definition is that according to J. Med. Chem., 2002, 45 (12), pp 2615-2623 """ rotatable = 0 try: # Initialise the Indigo library indigo = indigo_module.Indigo() # Load the molecule into Indigo try: mol = indigo.loadMolecule(smiles) except IndigoException as e: # If loading the molecule fails, try turning off chirality error checking and try again. indigo.setOption("ignore-stereochemistry-errors", True) mol = indigo.loadMolecule(smiles) # Aromatize the molecule mol.aromatize() matcher = indigo.substructureMatcher(mol) q = indigo.loadSmarts('[!$([NH]!@C(=O))&!D1&!$(*#*)]-&!@[!$([NH]!@C(=O))&!D1&!$(*#*)]') rotatable = matcher.countMatches(q) except IndigoException as e: print("Indigo Exception: %s" % (e)) finally: return rotatable
def __init__(self, arg_ns: argparse.Namespace): self.arg_ns = arg_ns self.index = arg_ns.elastic_index self.session = indigo.Indigo() self.es = elasticsearch.Elasticsearch( [arg_ns.elastic_url], verify_certs=arg_ns.elastic_verify_certs, ssl_show_warn=arg_ns.elastic_verify_certs, )
def __init__(self, arg_ns: argparse.Namespace): self.arg_ns = arg_ns self.session = indigo.Indigo() if arg_ns.bingo_dir: self.bingo_dir = arg_ns.bingo_dir else: self.bingo_dir = Path(arg_ns.pubchem_dir) / 'bingo_dir' if self.bingo_dir.is_dir(): self.bingo_conn = Bingo.loadDatabaseFile(self.session, str(self.bingo_dir), '') else: self.bingo_conn = Bingo.createDatabaseFile(self.session, str(self.bingo_dir), 'molecule', '')
def __init__(self, _obj, addh=True, kekulize=False, amend=False): hadd_status = T parse_status = T kekulize_status = T if isinstance(_obj, indigo.IndigoObject): m = _obj elif isinstance(_obj, str): obj = indigo.Indigo() if os.path.exists(_obj): m = obj.loadMoleculeFromFile(_obj) else: self.smi = _obj try: m = obj.loadMolecule(_obj) except: print(' ** failed to parse SMILES') parse_status = F if parse_status: if addh: try: m.unfoldHydrogens() except: hadd_status = F print(' ** failed to add H') elif isinstance(_obj, (tuple,list)): # unfortunately, Indigo cannot load file formats other than sdf/mol # so we manually construct molecule here rawm = rawmol_indigo(_obj) m = rawm.m else: raise '#unknown instance' if parse_status and hadd_status: if kekulize: try: kekulize_status = m.dearomatize() except: kekulize_status = F if not kekulize_status: print(' ** failed to kekulize') ioks = states(parse_status, hadd_status, kekulize_status) self.ioks = ioks self.status = parse_status and hadd_status and kekulize_status if self.status: self.m = m else: print(' # parse_status,hadd_status,kekulize_status=',parse_status,hadd_status,kekulize_status) if amend: self.m = amend_smiles(self.smi, ioks)
def draw(smiles, fname): _indigo = indigo.Indigo() _renderer = indigo_renderer.IndigoRenderer(_indigo) _indigo.setOption('render-output-format', 'png') _indigo.setOption('render-image-size', 250, 200) _indigo.setOption('render-margins', 10, 10) _indigo.setOption('render-stereo-style', 'none') _indigo.setOption('render-implicit-hydrogens-visible', False) _indigo.setOption('render-coloring', True) _indigo.setOption('render-bond-length', 50.0) _indigo.setOption('render-label-mode', 'hetero') indigo_mol = _indigo.loadMolecule(smiles) indigo_mol.aromatize() indigo_mol.layout() _renderer.renderToFile(indigo_mol, fname)
def sp3carbon(smiles): """ Calculate the number of carbon atoms, sp3 hybridised carbon atoms and sp3 fraction of a SMILES string. """ return_value = False num_carbon = float(0) num_carbon_sp3 = float(0) sp3_fraction = float(0) try: indigo = indigo_module.Indigo() try: mol = indigo.loadMolecule(smiles) except IndigoException as e: # If loading the molecule fails, try turning off chirality error checking and try again. indigo.setOption("ignore-stereochemistry-errors", True) mol = indigo.loadMolecule(smiles) mol.aromatize() mol.unfoldHydrogens() # Must add hydrogens to get the correct answer for atom in mol.iterateAtoms(): if (atom.symbol() == 'C'): num_carbon = num_carbon + 1 if (atom.degree() == 4): num_carbon_sp3 = num_carbon_sp3 + 1 if num_carbon == 0: sp3_fraction = 0 else: sp3_fraction = num_carbon_sp3 / num_carbon return_value = (int(num_carbon), int(num_carbon_sp3), sp3_fraction) except IndigoException as e: logging.error("sp3carbon(): Indigo exception: %s" % (e)) except Exception as e: logging.error("sp3carbon(): Exception: %s" % (e)) finally: return return_value
def tpsa(smiles): """ Compute the topological polar surface area of a molecule specified as a SMILES string. """ return_value = False # Variables to store the pattern defintions Pattern = collections.namedtuple("Pattern", ["value", "subsearch"]) patterns = [] try: # Initialise the Indigo library indigo = indigo_module.Indigo() # Build the path to the tpsa data file, relative to this file. fn = os.path.join(os.path.dirname(__file__), 'data/tpsa.tab') # Get the patterns from the tpsa.tab file, ignoring the header line for line in open(fn).readlines()[1:]: # Extract the fields value, smarts, comment = line.split("\t") subsearch = indigo.loadSmarts(smarts) # Store for later use patterns.append(Pattern(float(value), subsearch)) # Load the molecule mol = indigo.loadMolecule(smiles) # Molecules MUST be dearomatized for this TPSA calculation to work correctly. mol.dearomatize() return_value = sum( tpsa_count_matches(indigo, pattern.subsearch, mol) * pattern.value for pattern in patterns) except IndigoException as e: logging.error("Indigo exception: %s" % (e)) except Exception as e: logging.error("Exception: %s" % (e)) finally: return return_value
def __init__(self, obj): assert isinstance(obj, (list, tuple)), "#ERROR: obj not a list/tuple?" assert len(obj) == 4, "#ERROR: `obj should .eq. (zs,chgs,bom,coords)" zs, coords, chgs, bom = obj # unfortunately, Indigo cannot load file formats other than sdf/mol # so we manually construct molecule here na = len(zs) ias = np.arange(na).astype(np.int) newobj = indigo.Indigo() m = newobj.createMolecule() ats = [] for ia in range(na): ai = m.addAtom(co.chemical_symbols[zs[ia]]) ai.setXYZ(coords[ia, 0], coords[ia, 1], coords[ia, 2]) ai.setCharge(chgs[ia]) ats.append(ai) for ia in range(na): ai = ats[ia] jas = ias[np.logical_and(bom[ia] > 0, ias > ia)] for ja in jas: bi = ai.addBond(ats[ja], bom[ia, ja]) self.m = m
def WriteStructureThumbnail(self, output_format='png'): if not indigo or not indigo_renderer or not openbabel: # the web server is not supposed to be running this function logging.error( 'Indigo/Openbabel are not installed, cannot draw structures.') if self.inchi is None: return _obConversion = openbabel.OBConversion() _obConversion.SetInFormat("inchi") _obConversion.SetOutFormat("smiles") obmol = openbabel.OBMol() _obConversion.ReadString(obmol, str(self.inchi)) smiles = _obConversion.WriteString(obmol) _indigo = indigo.Indigo() _renderer = indigo_renderer.IndigoRenderer(_indigo) _indigo.setOption('render-output-format', output_format) _indigo.setOption('render-image-size', 250, 200) _indigo.setOption('render-margins', 10, 10) _indigo.setOption('render-stereo-style', 'none') _indigo.setOption('render-implicit-hydrogens-visible', False) _indigo.setOption('render-coloring', True) _indigo.setOption('render-bond-length', 50.0) _indigo.setOption('render-label-mode', 'hetero') try: indigo_mol = _indigo.loadMolecule(smiles) indigo_mol.aromatize() indigo_mol.layout() data = _renderer.renderToBuffer(indigo_mol).tostring() self.thumbnail = base64.encodestring(data) except indigo.IndigoException as e: logging.warning("Cannot draw structure of %s: %s" % (self.kegg_id, str(e)))
def test_murcko_alpha(self): indigo = indigo_module.Indigo() icb = "N#CC1C=CC=C(C=1)N=C=O" # 3-isocyanatobenzonitrile mol = indigo.loadMolecule(icb) self.assertEqual( murcko_alpha(mol).canonicalSmiles(), 'CC1=CC(N)=CC=C1')
class Molecule(object): # for more rendering options visit: # http://www.ggasoftware.com/opensource/indigo/api/options#rendering _indigo = indigo.Indigo() _renderer = indigo_renderer.IndigoRenderer(_indigo) _indigo.setOption('render-output-format', 'svg') _indigo.setOption('render-margins', 10, 10) _indigo.setOption('render-stereo-style', 'none') _indigo.setOption('render-implicit-hydrogens-visible', False) _indigo.setOption('render-coloring', True) _indigo.setOption('render-bond-length', 20.0) _indigo.setOption('render-label-mode', 'hetero') _obElements = openbabel.OBElementTable() @staticmethod def GetNumberOfElements(): return Molecule._obElements.GetNumberOfElements() @staticmethod def GetAllElements(): return [ Molecule._obElements.GetSymbol(i) for i in xrange(Molecule.GetNumberOfElements()) ] @staticmethod def GetSymbol(atomic_num): return Molecule._obElements.GetSymbol(atomic_num) @staticmethod def GetAtomicNum(elem): if type(elem) == types.UnicodeType: elem = str(elem) return Molecule._obElements.GetAtomicNum(elem) @staticmethod def SetBondLength(l): Molecule._indigo.setOption('render-bond-length', l) @staticmethod def VerifySmarts(smarts): try: pybel.Smarts(smarts) return True except IOError: return False def __init__(self): self.title = None self.obmol = openbabel.OBMol() self.pybel_mol = None self.smiles = None self.inchi = None def __str__(self): return self.title or self.smiles or self.inchi or "" def __len__(self): return self.GetNumAtoms() def Clone(self): tmp = Molecule() tmp.title = self.title tmp.obmol = openbabel.OBMol(self.obmol) tmp.pybel_mol = pybel.Molecule(tmp.obmol) tmp.smiles = self.smiles tmp.inchi = self.inchi return tmp def SetTitle(self, title): self.title = title @staticmethod def FromSmiles(smiles): m = Molecule() m.smiles = smiles obConversion = openbabel.OBConversion() obConversion.SetInFormat("smiles") if not obConversion.ReadString(m.obmol, m.smiles): raise OpenBabelError("Cannot read the SMILES string: " + smiles) try: m.UpdateInChI() m.UpdatePybelMol() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from SMILES: " + smiles) m.SetTitle(smiles) return m @staticmethod def FromInChI(inchi): m = Molecule() m.inchi = inchi obConversion = openbabel.OBConversion() obConversion.SetInFormat("inchi") obConversion.ReadString(m.obmol, m.inchi) try: m.UpdateSmiles() m.UpdatePybelMol() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from InChI: " + inchi) m.SetTitle(inchi) return m @staticmethod def FromMol(mol): m = Molecule() obConversion = openbabel.OBConversion() obConversion.SetInFormat("mol") obConversion.ReadString(m.obmol, mol) try: m.UpdateInChI() m.UpdateSmiles() m.UpdatePybelMol() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from MOL file:\n" + mol) m.SetTitle("") return m @staticmethod def FromOBMol(obmol): m = Molecule() m.obmol = obmol try: m.UpdateInChI() m.UpdateSmiles() m.UpdatePybelMol() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from OBMol") m.SetTitle("") return m @staticmethod def _FromFormat(s, fmt='inchi'): if fmt == 'smiles' or fmt == 'smi': return Molecule.FromSmiles(s) if fmt == 'inchi': return Molecule.FromInChI(s) if fmt == 'mol': return Molecule.FromMol(s) if fmt == 'obmol': return Molecule.FromOBMol(s) @staticmethod def _ToFormat(obmol, fmt='inchi'): obConversion = openbabel.OBConversion() obConversion.SetOutFormat(fmt) res = obConversion.WriteString(obmol) if not res: raise OpenBabelError("Cannot convert OBMol to %s" % fmt) if fmt == 'smiles' or fmt == 'smi': res = res.split() if res == []: raise OpenBabelError("Cannot convert OBMol to %s" % fmt) else: return res[0] elif fmt == 'inchi': return res.strip() else: return res @staticmethod def Smiles2InChI(smiles): obConversion = openbabel.OBConversion() obConversion.SetInAndOutFormats("smiles", "inchi") obmol = openbabel.OBMol() if not obConversion.ReadString(obmol, smiles): raise OpenBabelError("Cannot read the SMILES string: " + smiles) return obConversion.WriteString(obmol).strip() @staticmethod def InChI2Smiles(inchi): obConversion = openbabel.OBConversion() obConversion.SetInAndOutFormats("inchi", "smiles") obmol = openbabel.OBMol() if not obConversion.ReadString(obmol, inchi): raise OpenBabelError("Cannot read the InChI string: " + inchi) return obConversion.WriteString(obmol).split()[0] def RemoveHydrogens(self): self.pybel_mol.removeh() def RemoveAtoms(self, indices): self.obmol.BeginModify() for i in sorted(indices, reverse=True): self.obmol.DeleteAtom(self.obmol.GetAtom(i + 1)) self.obmol.EndModify() self.smiles = None self.inchi = None def SetAtomicNum(self, index, new_atomic_num): self.obmol.GetAtom(index + 1).SetAtomicNum(new_atomic_num) self.smiles = None self.inchi = None def ToOBMol(self): return self.obmol def ToPybelMol(self): return self.pybel_mol def ToFormat(self, fmt='inchi'): return Molecule._ToFormat(self.obmol, fmt=fmt) def ToMolfile(self): return self.ToFormat('mol') def UpdateInChI(self): self.inchi = Molecule._ToFormat(self.obmol, 'inchi') def ToInChI(self): """ Lazy storage of the InChI identifier (calculate once only when asked for and store for later use). """ if not self.inchi: self.UpdateInChI() return self.inchi def UpdateSmiles(self): self.smiles = Molecule._ToFormat(self.obmol, 'smiles') def ToSmiles(self): """ Lazy storage of the SMILES identifier (calculate once only when asked for and store for later use). """ if not self.smiles: self.UpdateSmiles() return self.smiles def UpdatePybelMol(self): self.pybel_mol = pybel.Molecule(self.obmol) @staticmethod def _GetFormulaFromInChI(inchi): tokens = re.findall('/f([0-9A-Za-z\.]+/)', inchi) if len(tokens) == 0: tokens = re.findall('InChI=1S?/([0-9A-Za-z\.]+)', inchi) if len(tokens) == 1: return tokens[0] elif len(tokens) > 1: raise ValueError('Bad InChI: ' + inchi) else: return '' @staticmethod def _GetAtomBagAndChargeFromInChI(inchi): fixed_charge = 0 for q in re.findall('/q([0-9\+\-\;]+)', inchi): for s in q.split(';'): if s: fixed_charge += int(s) fixed_protons = 0 for p in re.findall('/p([0-9\+\-\;]+)', inchi): for s in p.split(';'): if s: fixed_protons += int(s) formula = Molecule._GetFormulaFromInChI(inchi) atom_bag = {} for mol_formula_times in formula.split('.'): for times, mol_formula in re.findall('^(\d+)?(\w+)', mol_formula_times): if not times: times = 1 else: times = int(times) for atom, count in re.findall("([A-Z][a-z]*)([0-9]*)", mol_formula): if count == '': count = 1 else: count = int(count) atom_bag[atom] = atom_bag.get(atom, 0) + count * times if fixed_protons: atom_bag['H'] = atom_bag.get('H', 0) + fixed_protons fixed_charge += fixed_protons return atom_bag, fixed_charge @staticmethod def _GetNumElectronsFromInChI(inchi): """Calculates the number of electrons in a given molecule.""" atom_bag, fixed_charge = Molecule._GetAtomBagAndChargeFromInChI(inchi) n_protons = 0 for elem, count in atom_bag.iteritems(): n_protons += count * Molecule._obElements.GetAtomicNum(elem) return n_protons - fixed_charge def GetFormula(self): return Molecule._GetFormulaFromInChI(self.ToInChI()) def GetExactMass(self): return self.obmol.GetExactMass() def GetAtomBagAndCharge(self): return Molecule._GetAtomBagAndChargeFromInChI(self.ToInChI()) def GetHydrogensAndCharge(self): atom_bag, charge = self.GetAtomBagAndCharge() return atom_bag.get('H', 0), charge def GetNumElectrons(self): return Molecule._GetNumElectronsFromInChI(self.ToInChI()) def GetNumAtoms(self): return self.obmol.NumAtoms() def GetAtoms(self): return self.pybel_mol.atoms def FindSmarts(self, smarts): """ Corrects the pyBel version of Smarts.findall() which returns results as tuples, with 1-based indices even though Molecule.atoms is 0-based. Args: mol: the molecule to search in. smarts_str: the SMARTS query to search for. Returns: The re-mapped list of SMARTS matches. """ if type(smarts) == types.StringType: smarts = pybel.Smarts(smarts) shift_left = lambda m: [(n - 1) for n in m] return map(shift_left, smarts.findall(self.pybel_mol)) def ToSVG(self, comment=None): if comment: Molecule._indigo.setOption('render-comment', comment) else: Molecule._indigo.setOption('render-comment', '') try: indigo_mol = Molecule._indigo.loadMolecule(self.ToSmiles()) indigo_mol.aromatize() indigo_mol.layout() svg_str = Molecule._renderer.renderToBuffer(indigo_mol).tostring() id = str(uuid.uuid4()) i = 0 while True: symbol = 'glyph0-%d' % i if svg_str.find('id="' + symbol + '"') != -1: svg_str = svg_str.replace('id="' + symbol + '"', 'id="' + id + "_" + symbol + '"') svg_str = svg_str.replace( 'href="#' + symbol + '"', 'href="#' + id + "_" + symbol + '"') else: break i += 1 return svg_str except indigo.IndigoException as e: return "<b>Indigo error</b>: %s</br>\n" % str(e) def Draw(self, show_title=False): def expose_cairo(win, event, svg): cr = win.window.cairo_create() svg.render_cairo(cr) return True try: if show_title: svg = rsvg.Handle(data=self.ToSVG(self.title)) else: svg = rsvg.Handle(data=self.ToSVG()) except glib.GError: #@UndefinedVariable return _x, _y, w, h = svg.get_dimension_data() win = gtk.Window() win.resize(int(w), int(h)) win.connect("delete-event", lambda w, e: gtk.main_quit()) win.connect("expose-event", expose_cairo, svg) win.show_all() win.connect("destroy", lambda w: gtk.main_quit()) gtk.main() def GetAtomCharges(self): """ Returns: A list of charges, according to the number of atoms in the molecule """ return [atom.formalcharge for atom in self.pybel_mol.atoms] @staticmethod def _GetDissociationTable(molstring, fmt='inchi', mid_pH=default_pH, min_pKa=0, max_pKa=14, T=default_T, transform_multiples=False): """ Returns the relative potentials of pseudoisomers, relative to the most abundant one at pH 7. """ from pygibbs.dissociation_constants import DissociationTable from toolbox import chemaxon diss_table = DissociationTable() try: pKa_table, major_ms = chemaxon.GetDissociationConstants( molstring, mid_pH=mid_pH, transform_multiples=transform_multiples) mol = Molecule.FromSmiles(major_ms) nH, z = mol.GetHydrogensAndCharge() diss_table.SetMolString(nH, nMg=0, s=major_ms) diss_table.SetCharge(nH, z, nMg=0) pKa_higher = [x for x in pKa_table if mid_pH < x[0] < max_pKa] pKa_lower = [x for x in pKa_table if mid_pH > x[0] > min_pKa] for i, (pKa, _, smiles_above) in enumerate(sorted(pKa_higher)): diss_table.AddpKa(pKa, nH_below=(nH - i), nH_above=(nH - i - 1), nMg=0, ref='ChemAxon', T=T) diss_table.SetMolString((nH - i - 1), nMg=0, s=smiles_above) for i, (pKa, smiles_below, _) in enumerate(sorted(pKa_lower, reverse=True)): diss_table.AddpKa(pKa, nH_below=(nH + i + 1), nH_above=(nH + i), nMg=0, ref='ChemAxon', T=T) diss_table.SetMolString((nH + i + 1), nMg=0, s=smiles_below) except chemaxon.ChemAxonError: mol = Molecule._FromFormat(molstring, fmt) diss_table.SetOnlyPseudoisomerMolecule(mol) return diss_table def GetDissociationTable(self, fmt='inchi', mid_pH=default_pH, min_pKa=0, max_pKa=14, T=default_T): """ Returns the relative potentials of pseudoisomers, relative to the most abundant one at pH 7. """ return Molecule._GetDissociationTable(self.ToInChI(), 'inchi', mid_pH, min_pKa, max_pKa, T)
def reaction(smarts_string, mol1, mol2=False): """ This is a convenience function that quickly runs a virtual reaction and return the products. """ products = [] try: # Setup the Indigo library. # Enable generation of multiple products from a reaction, but don't # allow product molecules to be fed back in to be reacted a second # time around. indigo = indigo_module.Indigo() indigo.setOption("rpe-multistep-reactions", "true") indigo.setOption("rpe-max-depth", "1") indigo.setOption("rpe-self-reaction", "false") indigo.setOption("rpe-mode", "grid") # Load the molecules into Indigo molecules = indigo.createArray() m1 = indigo.loadMolecule(mol1) molecules.arrayAdd(m1) if (mol2): m2 = indigo.loadMolecule(mol2) molecules.arrayAdd(m2) # Initialise a 2D array to hold the reactant table reactant_table = indigo.createArray() # Create the reaction Indigo variable rxn = indigo.loadReactionSmarts(smarts_string) # Keep mapped atoms rxn.automap("keep") # Build the Indigo array of reactants for i in range(0, rxn.countReactants()): array = indigo.createArray() if (i < molecules.count()): array.arrayAdd(molecules.at(i)) reactant_table.arrayAdd(array) # Enumerate the products output_reactions = indigo.reactionProductEnumerate(rxn, reactant_table) num_products = output_reactions.count() if (num_products > 0): # The reaction was successful. Add the products to products[] for i in range(num_products): product = output_reactions.at(i) for p in product.iterateProducts(): products.append(p.canonicalSmiles()) except IndigoException as e: print("Indigo Exception: %s" % (e)) except Exception as e: print("Exception: %s" % (e)) finally: return products
import os import indigo indigo = indigo.Indigo("/var/www/gga/ketcher/lib") from django.conf.urls.defaults import patterns, url from django.http import Http404, HttpResponse def handle_knock(request): return HttpResponse(content="You are welcome!", mimetype='text/plain') def handle_layout(request): if request.method == 'GET' and request.GET.has_key("smiles"): moldata = request.GET["smiles"] elif request.method == 'POST' and request.POST.has_key("moldata"): moldata = request.POST["moldata"] else: raise Http404 mol = indigo.loadQueryMolecule(moldata) mol.layout() return HttpResponse(content="Ok.\n" + mol.molfile(), mimetype='text/plain') def handle_save(request): filedata = request.POST['filedata'] lines = filedata.splitlines() first = lines[0] rest = "\n".join(lines[1:])
NEW_RENDER_ENGINE = False try: from rdkit.Chem.Draw import rdMolDraw2D if hasattr(rdMolDraw2D, 'MolDraw2DCairo') and hasattr( rdMolDraw2D, 'MolDraw2DSVG'): NEW_RENDER_ENGINE = True except: pass try: import indigo from indigo import IndigoException import indigo_renderer indigoObj = indigo.Indigo() except ImportError: indigo = None indigo_renderer = None try: import cairo cffi = False except ImportError: import cairocffi cairocffi.install_as_pycairo() cffi = True import io import cairo if not hasattr(cairo, 'HAS_PDF_SURFACE'): cairo.HAS_PDF_SURFACE = False
def murcko(indigo_obj): """ Generate the Bemis-Murcko scaffold for a molecule. """ indigo = indigo_module.Indigo() if not indigo: raise Exception('The Indigo library was not initialised.') mol = indigo_obj.clone() try: hanging_atoms = [] while True: # Exit the while loop if we've removed all of the atoms if mol == None: break natoms = mol.countAtoms() nei = False found = False present = False # Atoms with 0 or 1 connections are appended to the # hanging_atoms[] list for atom in mol.iterateAtoms(): if (atom.degree() <= 1): hanging_atoms.append(atom.index()) while (len(hanging_atoms) > 0): # Clear down the to_remove and hanging_next lists to_remove = [] hanging_next = [] for atom in hanging_atoms: if (mol.getAtom(atom).degree() == 0): to_remove.append(atom) else: nei = mol.getAtom(atom).iterateNeighbors().next() if (nei.degree() <= 2 or nei.bond().bondOrder() == 1): to_remove.append(atom) else: present = False for a in hanging_next: if (a == atom): present = True if (present): hanging_next.append(atom) for atom in to_remove: if (mol.getAtom(atom).degree() > 0): nei = mol.getAtom(atom).iterateNeighbors().next() if (nei.degree() == 2): found = False for a in to_remove: if (a == nei.index()): found = True break if not found: for a in hanging_next: if (mol.getAtom(a).index() == nei.index()): found = True break if not found: hanging_next.append(nei.index()) # If there are no atoms left in the to_remove list, break out # of the while (len(hanging_atoms) > 0) loop. if (len(to_remove) == 0): break # Remove the atoms whose indices are in the to_remove array mol.removeAtoms(to_remove) hanging_atoms = hanging_next if mol == None: break # If we haven't removed any atoms during the last cycle, we've finished. if (natoms == mol.countAtoms()): break # If the number of remaining atoms is less than 3, there can't be a ring, therefore there can't be a scaffold. # Return a 'None' result if (mol.countAtoms() < 3): mol = None except (Exception, TypeError, ValueError) as e: logging.error("Exception: %s" % (e)) mol = None except IndigoException as e: logging.error("IndigoException: %s" % (e)) mol = None finally: return mol
def murcko_alpha(indigo_obj, murcko_fwk=False): """ Generate the Bemis-Murcko scaffold for a molecule, but leave the alpha atoms attached. The general strategy is: 1) Obtain the molecule's Murcko framework, which is either passed as an argument or calculated if necessary. 2) Find the atom ID numbers of the Murcko framework ring atoms. 3) Subtract the ring atom IDs from all atom IDs in the Murcko scaffold to recover the remaining (linker) atoms. 4) Highlight the linker atoms. 5) Loop until the atom count hasn't changed between two cycles: a) If an atom has one or zero bonds, add it to the hanging_atoms list. For all hanging atoms: i) If the atom isn't connected to any others, flag it for deletion. ii) Check whether the neighbouring atom is part of a ring. If it is, we don't want to delete the current atom because it is a ring alpha atom. iii) If the neighbouring atom isn't in a ring, and (the neighbouring atom is bonded to 2 or fewer atoms and the bond order is 1) and the neighbouring atom isn't highlighted, flag the atom for deletion. b) Remove all atoms that have been flagged for deletion. 6) Un-highlight all atoms. """ try: indigo = indigo_module.Indigo() if not indigo: raise Exception( 'The Indigo library instance was passed uninitialised') mol = indigo_obj.clone() if (murcko_fwk == False): # Get the molecule's Murcko framework. murcko_fwk = murcko(mol) if (murcko_fwk is None): raise Exception( "This molecule doesn't have a Murcko framework. Stopping.") # Initialise a set to hold the atom indices of the Murcko framework. murcko_atoms = set() # Populate the murcko_atoms set with the atom indices. for atom in murcko_fwk.iterateAtoms(): murcko_atoms.add(atom.index()) # Initialise a set to hold the atom indices of the ring atoms in the Murcko framework. murcko_ring_atoms = set() for r in murcko_fwk.iterateRings(3, 1000): for atom in r.iterateAtoms(): #print "Atom index %s is in a ring." % (atom.index()) murcko_ring_atoms.add(atom.index()) # Subtract the set of Murcko ring atoms from the whole Murcko set to get the linker atom indices. linker_atom_indices = list(murcko_atoms - murcko_ring_atoms) # Highlight the linker atoms. for atom in mol.iterateAtoms(): if atom.index() in linker_atom_indices: atom.highlight() # Hanging atoms are those with one or fewer bonds to other atoms. hanging_atoms = [] # Loop until done while True: if mol == None: break # Record the number of atoms in the molecule. This will be # compared to the number of atoms at the end of this cycle. # If the numbers are the same, we'll have finished. natoms = mol.countAtoms() # Reset some variables nei = False found = False present = False # If an atom is connected to one or fewer other atoms, consider it for deletion. for atom in mol.iterateAtoms(): if (atom.degree() <= 1): hanging_atoms.append(atom.index()) while (len(hanging_atoms) > 0): # Clear down the to_remove and hanging_next lists to_remove = [] hanging_next = [] for atom in hanging_atoms: if (mol.getAtom(atom).degree() == 0): # The hanging atom is not connected to any other atoms. Add it to to_remove array. to_remove.append(atom) else: nei = mol.getAtom(atom).iterateNeighbors().next() # Check whether the neighbouring atom is part of a ring. If it is, we don't want to delete the current atom. nei_not_in_ring = True # Loop over all bonds in the molecule for bond in mol.iterateBonds(): # If the bond is somehow connected to the neighbouring atom, check whether it's a chain or a ring bond. if (bond.source().index() == nei.index()) or ( bond.destination().index() == nei.index()): # The Indigo.RING constant is 10 if bond.topology() == 10: # The neighbouring atom is in a ring. The atom will not be deleted. nei_not_in_ring = False # If the neighbouring atom isn't in a ring, # and (the neighbouring atom is bonded to 2 # or fewer atoms and the bond order is 1) and # the neighbouring atom isn't highlighted, # flag the atom for deletion. if nei_not_in_ring and (nei.degree() <= 2 \ or nei.bond().bondOrder() == 1) \ and (not(nei.isHighlighted())): # If the atom meets the deletion criteria, add it to the list of atoms to be deleted. to_remove.append(atom) else: present = False for a in hanging_next: if (a == atom): present = True if (present): hanging_next.append(atom) for atom in to_remove: if (mol.getAtom(atom).degree() > 0): nei = mol.getAtom(atom).iterateNeighbors().next() if (nei.degree() == 2): found = False # Is the neighbour's index() already in the to_remove array? for a in to_remove: if (a == nei.index()): # print "Atom is already in the to_remove array" found = True break if not found: for a in hanging_next: if (mol.getAtom(a).index() == nei.index()): found = True break if not found: hanging_next.append(nei.index()) if (len(to_remove) == 0): break # Remove the atoms whose indices are in the to_remove array mol.removeAtoms(to_remove) hanging_atoms = hanging_next if mol == None: break # If we haven't removed any atoms during the last cycle, we've finished. if (natoms == mol.countAtoms()): break # If the number of remaining atoms is less than 3, there can't be a ring, therefore there can't be a scaffold. # Return a 'None' result if (mol.countAtoms() < 3): mol = None # Remove any atom highlights to prevent them from appearing # in the canonical SMILES string when the molecule object is # passed back to the calling function. if mol is not None: for atom in mol.iterateAtoms(): if atom.index() in linker_atom_indices: atom.unhighlight() except (Exception, TypeError, ValueError) as e: logging.error("murcko_alpha(): Exception: %s" % (e)) mol = None except IndigoException as e: logging.error("murcko_alpha(): IndigoException: %s" % (e)) mol = None finally: return mol
def populate(self, target_model_name, target_database, source_model_name, source_database, size, limit, offset, inchi_conversion, idx, display_offset): from django.db import connections from django.db import transaction from django.db.models import get_model from django.db.utils import DatabaseError, IntegrityError source_model = get_model(self.app_name, source_model_name) target_model = get_model(self.app_name, target_model_name) target_conn = connections[target_database] source_pk = source_model._meta.pk.name writer = Writer(self.term, (idx, 0)) pbar = ProgressBar(widgets=[ '{0} ({1}) [{2}-{3}]: '.format(target_model_name, idx - display_offset + 1, offset, offset + limit), Percentage(), ' (', Counter(), ') ', Bar(marker=RotatingMarker()), ' ', ETA() ], fd=writer, maxval=limit).start() inchi_kwargs = {} if inchi_conversion == 'indigo': indigo_obj = indigo.Indigo() indigo_inchi_obj = indigo_inchi.IndigoInchi(indigo_obj) inchi_kwargs = {"inchiObj": indigo_inchi_obj} elif inchi_conversion == 'rdkit' and self.verbosity < 1: from rdkit import rdBase rdBase.DisableLog('rdApp.error') from rdkit import RDLogger lg = RDLogger.logger() lg.setLevel(RDLogger.CRITICAL) inchi_converter = inchi_converters.get(inchi_conversion) last_pk = None for i in range(offset, offset + limit, size): success = 0 failure = 0 empty = 0 ignored = 0 transaction.commit_unless_managed(using=target_database) transaction.enter_transaction_management(using=target_database) transaction.managed(True, using=target_database) with target_conn.constraint_checks_disabled(): try: chunk_size = min(size, limit + offset - i) original_data = None if not last_pk: if i: last_pk = source_model.objects.using( source_database).order_by(source_pk).only( source_pk).values_list(source_pk)[i][0] else: original_data = source_model.objects.using( source_database).order_by( source_pk).values_list( 'pk', 'standardinchi')[:chunk_size] if not original_data: original_data = source_model.objects.using( source_database).order_by(source_pk).values_list( 'pk', 'standardinchi').filter( pk__gt=last_pk)[:chunk_size] last_pk = original_data[chunk_size - 1][0] target_data = [] for pk, inchi in original_data: if not inchi: empty += 1 continue if int(pk) in self.ignores: ignored += 1 continue ctab = self.convert_inchi(inchi_converter, pk, inchi, inchi_kwargs) if not ctab: failure += 1 continue target_data.append( target_model(pk=int(pk), molfile=ctab)) success += 1 target_model.objects.using(target_database).bulk_create( target_data) except IntegrityError as e: if self.verbosity >= 1: self.stderr.write( "ERROR: integrity error ({0}) occurred when processing chunk {1}-{2}" .format(e.message, i, i + size)) transaction.rollback(using=target_database) transaction.leave_transaction_management( using=target_database) continue except DatabaseError as e: if self.verbosity >= 1: self.stderr.write( "ERROR: database error ({0}) occurred when processing chunk {1}-{2}" .format(e.message, i, i + size)) transaction.rollback(using=target_database) transaction.leave_transaction_management( using=target_database) raise e pbar.update(i - offset + 1) transaction.commit(using=target_database) transaction.leave_transaction_management(using=target_database) self.total_success += success self.total_failure += failure self.total_empty += empty self.total_ignored += ignored pbar.update(limit) pbar.finish()
import sys import getopt import unittest import urllib import urllib2 import indigo import indigo_inchi indigo = indigo.Indigo() indigo_inchi = indigo_inchi.IndigoInchi(indigo) indigo.setOption('ignore-stereochemistry-errors', 'true') base_url = "http://localhost:8080/" def make_request(request, data, use_post=True): global base_url data = urllib.urlencode(data) if data is not None else None if use_post: r = urllib2.urlopen(base_url + '/' + request, data) else: r = urllib2.urlopen(base_url + '/' + request + ("" if data is None else "?" + data)) return r class TestKetcherServerApi(unittest.TestCase): def test_knocknock(self): r = make_request("knocknock", None, False) self.assertEquals(200, r.code) self.assertEquals("You are welcome!", r.read().strip())
return self.FileWrapper(fd) if self.method == 'GET' else [''] except (IOError, OSError): raise self.HttpException( "402 Payment Required", # or 403, hmm.. "Must get more money for overtime") def is_form_request(self): return self.method == 'POST' and \ (self.content_type.startswith('application/x-www-form-urlencoded') or self.content_type.startswith('multipart/form-data')) try: import indigo import indigo_inchi application.indigo = indigo.Indigo() application.indigo_inchi = indigo_inchi.IndigoInchi(application.indigo) application.indigo.setOption('ignore-stereochemistry-errors', 'true') except: pass if __name__ == '__main__': import socket from wsgiref.simple_server import make_server def parse_args(): dir = sys.argv[1] if len(sys.argv) > 1 else '' addr = sys.argv[2] if len(sys.argv) > 2 else '' res = addr.rsplit(':', 1) return dir, \ res[0] if len(res) > 1 else '0.0.0.0', \