• Docs »
• Ring Perception new

# Ring Perception new¶

## Problem¶

You want to determine whether two atoms belong to the same ring. See examples in Table 1.

Ring perception is one of the fundamental algorithms when handling chemical structures. While OEChem TK does not provide a solution for SSSR (Smallest Set of Smallest Rings) it includes wide range of functions (see Table 2) that answer related questions. This recipe will illustrate how to utilize these functions to determine whether two atoms belong to the same ring.

## Ingredients¶

 OEChem TK - cheminformatics toolkit

## Solution¶

The algorithm implemented in AtomsInSameRing is based on a simple concept: if two atoms belong to the same ring then there has to at least two alternative ring paths between them that are identified by using the OEShortestPath function.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 def AtomsInSameRing(atomA, atomB): if not atomA.IsInRing() or not atomB.IsInRing(): return False if atomA == atomB: return True firstpath = [a for a in oechem.OEShortestPath(atomA, atomB, oechem.OEAtomIsInChain())] firstpathlength = len(firstpath) if firstpathlength == 2: return True # neighbors if firstpathlength == 0: return False # not is same ring system smallestA = oechem.OEAtomGetSmallestRingSize(atomA) smallestB = oechem.OEAtomGetSmallestRingSize(atomB) if firstpathlength > smallestA and firstpathlength > smallestB: return False # too far away # try to find the second shortest different path excludepred = ChainAtomOrAlreadyTraversed(firstpath[1:-1]) secondpath = [a for a in oechem.OEShortestPath(atomA, atomB, excludepred)] secondpathlength = len(secondpath) if secondpathlength == 0: return False # can not be in the same ring if secondpathlength > smallestA and secondpathlength > smallestB: return False # too far away sumringsize = len(firstpath) + len(secondpath) - 2 if sumringsize > smallestA and sumringsize > smallestB: return False inringA = oechem.OEAtomIsInRingSize(atomA, sumringsize) inringB = oechem.OEAtomIsInRingSize(atomB, sumringsize) return inringA and inringB 

ChainAtomOrAlreadyTraversed is the atom predicate that is used with OEShortestPath to identify a second alternative path between two atoms.

  1 2 3 4 5 6 7 8 9 10 11 12 class ChainAtomOrAlreadyTraversed(oechem.OEUnaryAtomPred): def __init__(self, exclude): oechem.OEUnaryAtomPred.__init__(self) self.exclude = exclude def __call__(self, atom): if not atom.IsInRing(): return False return (atom in self.exclude) def CreateCopy(self): return ChainAtomOrAlreadyTraversed(self.exclude).__disown__() 

Usage:

prompt > python3 samering.py .ism
c1ccc2c(c1)cc[nH]2

atom  0 C in the same ring as  0 C  1 C  2 C  3 C  4 C  5 C
atom  1 C in the same ring as  0 C  1 C  2 C  3 C  4 C  5 C
atom  2 C in the same ring as  0 C  1 C  2 C  3 C  4 C  5 C
atom  3 C in the same ring as  0 C  1 C  2 C  3 C  4 C  5 C  6 C  7 C  8 N
atom  4 C in the same ring as  0 C  1 C  2 C  3 C  4 C  5 C  6 C  7 C  8 N
atom  5 C in the same ring as  0 C  1 C  2 C  3 C  4 C  5 C
atom  6 C in the same ring as  3 C  4 C  6 C  7 C  8 N
atom  7 C in the same ring as  3 C  4 C  6 C  7 C  8 N
atom  8 N in the same ring as  3 C  4 C  6 C  7 C  8 N


## Discussion¶

The following examples show how to use ring perception functions available in OEChem TK.

### Identifying ring systems of a molecule¶

 nrrings, ringlist = oechem.OEDetermineRingSystems(mol) disp = oedepict.OE2DMolDisplay(mol, opts) highlight = oedepict.OEHighlightByLasso(oechem.OEBlack) highlight.SetConsiderAtomLabelBoundingBox(True) ringpred = oechem.OEPartPredAtom(ringlist) for ringidx, color in zip(range(1, nrrings + 1), oechem.OEGetVividColors()): ringpred.SelectPart(ringidx) ringset = oechem.OEAtomBondSet(mol.GetAtoms(ringpred)) highlight.SetColor(color) oedepict.OEAddHighlighting(disp, highlight, ringset) oedepict.OERenderMolecule(image, disp)  Download code depict-ringsystem.py

### Identifying aromatic ring systems of a molecule¶

 nrrings, ringlist = oechem.OEDetermineAromaticRingSystems(mol) disp = oedepict.OE2DMolDisplay(mol, opts) highlight = oedepict.OEHighlightByLasso(oechem.OEBlack) highlight.SetConsiderAtomLabelBoundingBox(True) ringpred = oechem.OEPartPredAtom(ringlist) for ringidx, color in zip(range(1, nrrings + 1), oechem.OEGetVividColors()): ringpred.SelectPart(ringidx) ringset = oechem.OEAtomBondSet(mol.GetAtoms(ringpred)) highlight.SetColor(color) oedepict.OEAddHighlighting(disp, highlight, ringset) oedepict.OERenderMolecule(image, disp)  Download code depict-aromringsystem.py

### Identifying atom in certain ring size¶

 class LabelRingSize(oedepict.OEDisplayAtomPropBase): def __init__(self, maxringsize): self.maxringsize = maxringsize oedepict.OEDisplayAtomPropBase.__init__(self) def __call__(self, atom): if not atom.IsInRing(): return "" rings = [] for ringsize in range(3, self.maxringsize): if oechem.OEAtomIsInRingSize(atom, ringsize): rings.append(ringsize) if len(rings) == 0: return "" return "(" + ",".join([str(r) for r in rings]) + ")" def CreateCopy(self): return LabelRingSize(self.maxringsize).__disown__() scale = oedepict.OEScale_AutoScale opts = oedepict.OE2DMolDisplayOptions(width, height, scale) opts.SetAtomColorStyle(oedepict.OEAtomColorStyle_WhiteMonochrome) opts.SetAtomPropertyFunctor(LabelRingSize(maxringsize=10)) disp = oedepict.OE2DMolDisplay(mol, opts)  Download code depict-ringsize.py

### Identifying atom in certain aromatic ring size¶

 class LabelAromaticRingSize(oedepict.OEDisplayAtomPropBase): def __init__(self, maxringsize): self.maxringsize = maxringsize oedepict.OEDisplayAtomPropBase.__init__(self) def __call__(self, atom): if not atom.IsInRing(): return "" rings = [] for ringsize in range(3, self.maxringsize): if oechem.OEAtomIsInAromaticRingSize(atom, ringsize): rings.append(ringsize) if len(rings) == 0: return "" return "(" + ",".join([str(r) for r in rings]) + ")" def CreateCopy(self): return LabelAromaticRingSize(self.maxringsize).__disown__() scale = oedepict.OEScale_AutoScale opts = oedepict.OE2DMolDisplayOptions(width, height, scale) opts.SetAtomColorStyle(oedepict.OEAtomColorStyle_WhiteMonochrome) opts.SetAtomPropertyFunctor(LabelAromaticRingSize(maxringsize=10)) disp = oedepict.OE2DMolDisplay(mol, opts)  Download code depict-aromringsize.py

### Identifying atom smallest ring size¶

 class LabelSmallestRingSize(oedepict.OEDisplayAtomPropBase): def __init__(self): oedepict.OEDisplayAtomPropBase.__init__(self) def __call__(self, atom): if not atom.IsInRing(): return "" smallest = oechem.OEAtomGetSmallestRingSize(atom) return "(" + str(smallest) + ")" def CreateCopy(self): return LabelSmallestRingSize().__disown__() scale = oedepict.OEScale_AutoScale opts = oedepict.OE2DMolDisplayOptions(width, height, scale) opts.SetAtomColorStyle(oedepict.OEAtomColorStyle_WhiteMonochrome) opts.SetAtomPropertyFunctor(LabelSmallestRingSize()) disp = oedepict.OE2DMolDisplay(mol, opts)  Download code depict-smallestringsize.py