Package rdkit :: Package Chem :: Package FeatMaps :: Module FeatMapParser

[hide private]
[frames] | no frames]

# Source Code for Module rdkit.Chem.FeatMaps.FeatMapParser

      1  # $Id$
      2  #
      3  # Copyright (C) 2006 Greg Landrum
      4  #
      5  #   @@ All Rights Reserved @@
      6  #  This file is part of the RDKit.
      7  #  The contents are covered by the terms of the BSD license
      8  #  which is included in the file license.txt, found at the root
      9  #  of the RDKit source tree.
     10  #
     11  from rdkit import Geometry
     12  from rdkit.Chem import ChemicalFeatures
     13  from rdkit.Chem.FeatMaps import FeatMaps,FeatMapPoint
     14  import re
     15
     16  """
     17
     18  ScoreMode=All
     19  DirScoreMode=Ignore
     20
     21  BeginParams
     22    family=Aromatic radius=2.5 width=1.0 profile=Gaussian
     23    family=Acceptor radius=1.5
     24  EndParams
     25
     26  # optional
     27  BeginPoints
     28    family=Acceptor pos=(1.0, 0.0, 5.0) weight=1.25 dir=(1, 1, 0)
     29    family=Aromatic pos=(0.0,1.0,0.0) weight=2.0 dir=(0,0,1) dir=(0,0,-1)
     30    family=Acceptor pos=(1.0,1.0,2.0) weight=1.25
     31  EndPoints
     32
     33  """
     34
     35 -class FeatMapParseError(ValueError):
     36    pass
     37
     38 -class FeatMapParser(object):
     39    data=None
     40 -  def __init__(self,file=None,data=None):
     41      if file:
     42        self.data=file.readlines()
     43      elif data:
     44        self.SetData(data)
     45      self._lineNum=0
     46
     47 -  def SetData(self,data):
     48      if isinstance(data,str):
     49        self.data=data.split('\n')
     50      else:
     51        self.data=data
     52      self._lineNum=0
     53
     54 -  def _NextLine(self):
     55      txt = ''
     56      while 1:
     57        try:
     58          l = self.data[self._lineNum].split('#')[0].strip()
     59        except IndexError:
     60          break
     61        self._lineNum+=1
     62        if l:
     63          txt += l
     64          if l[-1]!='\\':
     65            break
     66      return txt
     67
     68 -  def Parse(self,featMap=None):
     69      if featMap is None:
     70        featMap = FeatMaps.FeatMap()
     71
     72      l = self._NextLine().strip()
     73      while l:
     74        splitL = l.split('=')
     75        if len(splitL)==1:
     76          keyword=splitL[0].strip().lower()
     77          if keyword=='beginpoints':
     78            pts=self.ParseFeatPointBlock()
     79            for pt in pts:
     80              featMap.AddFeatPoint(pt)
     81          elif keyword=='beginparams':
     82            featMap.params=self.ParseParamBlock()
     83          else:
     84            raise FeatMapParseError('Unrecognized keyword %s on line %d'%(keyword,self._lineNum))
     85        else:
     86          keyword = splitL[0].strip().lower()
     87          val = splitL[1].strip()
     88          if keyword=='scoremode':
     89            try:
     90              featMap.scoreMode=getattr(FeatMaps.FeatMapScoreMode,val)
     91            except AttributeError:
     92              raise FeatMapParseError('ScoreMode %s not recognized on line %d'%(val,self._lineNum))
     93          elif keyword=='dirscoremode':
     94            try:
     95              featMap.dirScoreMode=getattr(FeatMaps.FeatDirScoreMode,val)
     96            except AttributeError:
     97              raise FeatMapParseError('DirScoreMode %s not recognized on line %d'%(val,self._lineNum))
     98          else:
     99            raise FeatMapParseError('Unrecognized keyword %s on line %d'%(keyword,self._lineNum))
    100        l = self._NextLine().strip()
    101      return featMap
    102
    103 -  def ParseParamBlock(self):
    104      paramLineSplitter = re.compile(r'([a-zA-Z]+) *= *(\S+)')
    105      params = {}
    106
    107      l = self._NextLine()
    108      while l and l!='EndParams':
    109        param = FeatMaps.FeatMapParams()
    110        vals=paramLineSplitter.findall(l)
    111        for name,val in vals:
    112          name = name.lower()
    113          if name=='family':
    114            family=val
    115          elif name=='radius':
    116            param.radius=float(val)
    117          elif name=='width':
    118            param.width=float(val)
    119          elif name=='profile':
    120            try:
    121              param.featProfile=getattr(param.FeatProfile,val)
    122            except AttributeError:
    123              raise FeatMapParseError('Profile %s not recognized on line %d'%(val,self._lineNum))
    124          else:
    125            raise FeatMapParseError('FeatMapParam option %s not recognized on line %d'%(name,self._lineNum))
    126        params[family]=param
    127        l = self._NextLine()
    128
    129      if l!='EndParams':
    130        raise FeatMapParseError('EndParams line not found')
    131
    132      return params
    133
    134 -  def _parsePoint(self,txt):
    135      txt = txt.strip()
    136      startP=0
    137      endP=len(txt)
    138      if txt[0]=='(':
    139        startP += 1
    140      if txt[-1]==')':
    141        endP -= 1
    142      txt = txt[startP:endP]
    143      splitL = txt.split(',')
    144      if len(splitL) != 3:
    145        raise ValueError('Bad location string')
    146      vs = [float(x) for x in splitL]
    147      pt = Geometry.Point3D(vs[0],vs[1],vs[2])
    148      return pt
    149
    150
    151 -  def ParseFeatPointBlock(self):
    152      featLineSplitter = re.compile(r'([a-zA-Z]+) *= *')
    153      feats = []
    154
    155      l = self._NextLine()
    156      while l and l!='EndPoints':
    157        vals=featLineSplitter.split(l)
    158        while vals.count(''): vals.remove('')
    159        p = FeatMapPoint.FeatMapPoint()
    160
    161        i=0
    162        while i<len(vals):
    163          name = vals[i].lower()
    164          if name=='family':
    165            i+=1
    166            val = vals[i].strip()
    167            p.SetFamily(val)
    168          elif name=='weight':
    169            i+=1
    170            val = float(vals[i])
    171            p.weight = val
    172          elif name=='pos':
    173            i+=1
    174            val = vals[i]
    175            pos = self._parsePoint(val)
    176            p.SetPos(pos)
    177          elif name=='dir':
    178            i+=1
    179            val = vals[i]
    180            pos = self._parsePoint(val)
    181            p.featDirs.append(pos)
    182          else:
    183            raise FeatMapParseError('FeatPoint option %s not recognized on line %d'%(name,self._lineNum))
    184          i+=1
    185        feats.append(p)
    186        l = self._NextLine()
    187      return feats
    188  #------------------------------------
    189  #
    190  #  doctest boilerplate
    191  #
    192 -def _test():
    193    import doctest,sys
    194    return doctest.testmod(sys.modules["__main__"])
    195
    196  if __name__ == '__main__':
    197    import sys
    198    failed,tried = _test()
    199    sys.exit(failed)
    200