Hi Giovanni,
I while ago I wrote this code in Python to enumerate all/undefined chiral centers in a given molecule.

It works fairly well, although, you may want to check your structures if you're generating 3D coordinates, since at least the stable version of OpenBabel (2.3.2) has some issues with chiral centers in (multiple?)rings.


S

On 09/08/2016 12:48 AM, Giovanni Cincilla wrote:
Hi everybody,
Starting from a certain molecule with possibly undefined sp3 stereocenters
(R/S) is it possible to enumerate with OpenBabel all the possible
stereisomers as different molecules?
Any help is appreciated. Thanks
Gio



--
View this message in context: 
http://forums.openbabel.org/How-to-enumerate-all-possible-stereoisomers-of-a-molecule-with-a-not-defined-stereocenter-tp4659459.html
Sent from the General discussion mailing list archive at Nabble.com.

------------------------------------------------------------------------------
_______________________________________________
OpenBabel-discuss mailing list
OpenBabel-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openbabel-discuss



--

 Stefano Forli, PhD

 Assistant Professor of ISCB
 Molecular Graphics Laboratory

 Dept. of Integrative Structural
 and Computational Biology, MB-112A
 The Scripps Research Institute
 10550  North Torrey Pines Road
 La Jolla,  CA 92037-1000,  USA.

    tel: +1 (858)784-2055
    fax: +1 (858)784-2860
    email: fo...@scripps.edu
    http://www.scripps.edu/~forli/
import itertools


class ChiralEnumerator:
    """ chirality generator
        initialized with a molecule provides a generator
        that can be used to enumerate isomers of a molecule


        mol :   obmol
        chiralityType   : 'all' = generate all enantiomers for any chiral center
                          'undefined' = generate enantiomers for undefined chiral centers
                          'off' = disable enantiomer generation
        maxIter         : maximum number of enantiomers to generate
        verbose         : print status of generation
    """
    def __init__(self, mol, chiralityType='all', maxIter=50, verbose=True):
        """ """
        self.verbose = verbose
        self.mol = mol
        self.maxIter = maxIter
        self.chiralityType = chiralityType
        self.active = False
        self._stop = False
        self._iterations = 0
        self.labels = [ 'R', 'S'] # note: this is arbitrary!
        self.chiralSet = []
        if self.mol.IsChiral() and (not self.chiralityType=='off'):
            self.chiral = []
            self.chiralDefined = []
            self.blacklist = self.findBlacklistCenters()
            self.facade = ob.OBStereoFacade(self.mol)

            # find which atoms are to be considered chiral
            for a in ob.OBMolAtomIter(self.mol):
                idx = a.GetIdx()#-1
                if self.facade.HasTetrahedralStereo(idx) and not idx in self.blacklist:
                    self.chiral.append( idx )
                    ts = self.facade.GetTetrahedralStereo(idx)
                    config = ts.GetConfig()
                    if config.specified:
                        self.chiralDefined.append(idx)
                    else:
                        config.specified = True
                        ts.SetConfig(config)
            if len(self.chiral) > 0:
                self.active = True
                msg = ('[ChiralEnumerator] chirality Implicit[%d] Explicit[%d]'
                        '' % (len(self.chiral), len(self.chiralDefined)))
                self.vprint(msg)
                if self.chiralityType == 'all':
                    self.chiralAccepted = self.chiral
                    msg = ('[ChiralEnumerator] chiral set ALL [%d] atoms' % len(self.chiralAccepted))
                elif self.chiralityType == 'undefined':
                    self.chiralAccepted = set(self.chiral) - set(self.chiralDefined)
                    msg = ('[ChiralEnumerator] chiral set UNDEFINED [%d] atoms' % len(self.chiralAccepted))
                self.vprint(msg)
                self.chiralSet = []
                tmp = {}
                for idx in self.chiralAccepted:
                    ref1 = self.facade.GetTetrahedralStereo(idx).GetConfig().refs
                    ref2 = ( ref1[1], ref1[0], ref1[2] )
                    self.chiralSet.append((ref1, ref2))
                self.chiralSet = list( itertools.product( *self.chiralSet) )
        self.vprint("\n\n\n[ChiralEnumerator]: %d chiral centers accepted" % len(self.chiralSet) )

    def __iter__(self):
        """" """
        return self

    def next(self):
        """ """
        if self._iterations >= self.maxIter:
            self._stop = True
        if self._stop:
            raise StopIteration
        if not self.active:
            self._stop = True
            return self.mol
        else:
            #if True:
            try:
                refs = self.chiralSet.pop()
                msg = ('[enumchiral] |%s| enantiomer to be generated' % str(refs))  # (%s)'
                        #'' % (','.join([self.labels[x-1] for x in refs ]), refs))
                self.vprint(msg)
                self._iterations += 1
                for idx, aIdx in enumerate(self.chiralAccepted):
                    ts = self.facade.GetTetrahedralStereo(aIdx)
                    config = ts.GetConfig()
                    config.refs = ( refs[idx][0], refs[idx][1], refs[idx][2]) 
                    x = ts.SetConfig(config)
                #print ""
                canonic = ob.OBMol()
                obc = ob.OBConversion()
                obc.SetInAndOutFormats('smi', 'can')
                can = obc.WriteString(self.mol)
                self.vprint("CANONICAL SMILE ENANTIOMER: %s"% can.strip())
                obc.ReadString(canonic, can)
                return canonic
            except IndexError:
                raise StopIteration

    def vprint(self, string, addnewline=True, flush=False, rewind=False):
        """ debugging printing"""
        if not self.verbose:
            return
        msg = ''
        if rewind:
            msg += '\r'
        msg += "VERBOSE: %s" % string
        if not addnewline:
            print msg,
        else:    
            print msg
        if flush:
            sys.stdout.flush()

    def findBlacklistCenters(self):
        """ identify unwanted patterns (adamantane, for now) to avoid combinatorial 
            enumeration of its chiral centers
        """
        pattern = [ 'C1C3CC2CC(CC1C2)C3'] 
        m = ob.OBSmartsPattern()
        for p in pattern:
            m.Init(p)
            found = m.Match(self.mol)
            if found:
                if self.verbose:
                    print "[findBlacklistCenters]: found unwanted!", p
                return [ x for x in m.GetUMapList() ][0]
        return ()


if __name__ == '__main__':
    import sys, os
    import pybel
    ob = pybel.ob

    name, ext = os.path.splitext(sys.argv[1])
    ext = ext[1:].lower()
    for pmol in pybel.readfile(ext, sys.argv[1]):
        mol = pmol.OBMol
        for chiral in ChiralEnumerator(mol, chiralityType='all',
                        maxIter = 50, verbose = False):
            s = pybel.Molecule(chiral)
            print s.strip()
            
------------------------------------------------------------------------------
_______________________________________________
OpenBabel-discuss mailing list
OpenBabel-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openbabel-discuss

Reply via email to