Chem.FeatMaps.FeatMaps

Package Chem :: Package FeatMaps :: Module FeatMaps |
[hide private]
[frames] | no frames]

# Source Code for Module Chem.FeatMaps.FeatMaps

      1  # $Id: FeatMaps.py 50 2006-08-31 04:10:00Z glandrum $

      2  #

      3  # Copyright (C) 2006 Greg Landrum

      4  #

      5  #   @@ All Rights Reserved  @@

      6  #

      7  import Geometry
      8  import Chem
      9  from Chem import ChemicalFeatures
     10  from Chem.FeatMaps.FeatMapPoint import FeatMapPoint
     11  import math
     12

     13 -class FeatMapScoreMode(object):
     14    All=0
     15    """ score each feature in the probe against every matching

     16        feature in the FeatMap.

     17    """
     18

     19    Closest=1
     20    """ score each feature in the probe against the closest

     21        matching feature in the FeatMap.

     22    """
     23

     24    Best=2
     25    """ score each feature in the probe against the matching

     26        feature in the FeatMap that leads to the highest score

     27    """
     28

     29 -class FeatDirScoreMode(object):
     30    Ignore=0
     31    """ ignore feature directions

     32    """
     33

     34    DotFullRange=1
     35    """ Use the dot product and allow negative contributions when

     36        directions are anti-parallel.

     37        e.g. score = dot(f1Dir,f2Dir)

     38    """
     39

     40    DotPosRange=2
     41    """ Use the dot product and scale contributions to lie between

     42        zero and one.

     43        e.g. score = ( dot(f1Dir,f2Dir) + 1 ) / 2

     44    """
     45

     46 -class FeatMapParams(object):
     47    """ one of these should be instantiated for each

     48    feature type in the feature map

     49    """
     50    radius=2.5
     51    " cutoff radius "
     52

     53    width=1.0
     54    " width parameter (e.g. the gaussian sigma) "
     55

     56 -  class FeatProfile(object):
     57      " scoring profile of the feature "
     58      Gaussian=0
     59      Triangle=1
     60      Box=2
     61

     62    featProfile=FeatProfile.Gaussian
     63

     64 -class FeatMap(object):
     65    dirScoreMode = FeatDirScoreMode.Ignore
     66    scoreMode=FeatMapScoreMode.All
     67    params = {}
     68 -  def __init__(self,params=None,feats=None,

     69                 weights=None):
     70      if params:
     71        self.params = params
     72      self._initializeFeats(feats,weights)
     73

     74 -  def _initializeFeats(self,feats,weights):
     75      self._feats = []
     76      if feats:
     77        if len(feats)!=len(weights):
     78          raise ValueError,'feats and weights lists must be the same length'
     79        for feat,weight in zip(feats,weights):
     80          self.AddFeature(feat,weight)
     81

     82 -  def AddFeature(self,feat,weight=None):
     83      if self.params and not self.params.has_key(feat.GetFamily()):
     84        raise ValueError,'feature family %s not found in params'%feat.GetFamily()
     85

     86      newFeat = FeatMapPoint()
     87      newFeat.initFromFeat(feat)
     88      newFeat.weight = weight
     89

     90      self.AddFeatPoint(newFeat)
     91

     92 -  def AddFeatPoint(self,featPt):
     93      if not isinstance(featPt,FeatMapPoint):
     94        raise ValueError,'addFeatPoint() must be called with a FeatMapPoint instance'
     95      if self.params and not self.params.has_key(featPt.GetFamily()):
     96        raise ValueError,'feature family %s not found in params'%featPt.GetFamily()
     97      self._feats.append(featPt)
     98

     99

    100 -  def GetFeatures(self):
    101      return self._feats
    102

    103 -  def GetNumFeatures(self):
    104      return len(self._feats)
    105

    106 -  def GetFeature(self, i):
    107      return self._feats[i]
    108

    109 -  def DropFeature(self,i):
    110      del self._feats[i]
    111

    112 -  def _loopOverMatchingFeats(self,oFeat):
    113      for sIdx,sFeat in enumerate(self._feats):
    114        if sFeat.GetFamily()==oFeat.GetFamily():
    115          yield sIdx,sFeat
    116

    117 -  def GetFeatFeatScore(self,feat1,feat2,typeMatch=True):
    118      """ feat1 is one of our feats

    119          feat2 is any Feature

    120

    121

    122      """
    123      if typeMatch and feat1.GetFamily()!=feat2.GetFamily():
    124        return 0.0
    125      d2 = feat1.GetDist2(feat2)
    126      params = self.params[feat1.GetFamily()]
    127      if d2>params.radius*params.radius:
    128        return 0.0
    129

    130      if params.featProfile==FeatMapParams.FeatProfile.Gaussian:
    131        score = math.exp(-d2/params.width)
    132      elif params.featProfile==FeatMapParams.FeatProfile.Triangle:
    133        d = math.sqrt(d2)
    134        if d<params.width:
    135          score = 1.-d/params.width
    136        else:
    137          score=0.0
    138      elif params.featProfile==FeatMapParams.FeatProfile.Box:
    139        score = 1.0
    140      weight = feat1.weight
    141      score *= weight
    142

    143      if self.dirScoreMode != FeatDirScoreMode.Ignore:
    144        dirScore = feat1.GetDirMatch(feat2)
    145        if self.dirScoreMode==FeatDirScoreMode.DotPosRange:
    146          dirScore = (dirScore + 1.0)/2.0
    147        elif self.dirScoreMode!=FeatDirScoreMode.DotFullRange:
    148          raise NotImplementedError,'bad feature dir score mode'
    149        score *= dirScore
    150

    151      return score
    152

    153 -  def ScoreFeats(self,featsToScore,mapScoreVect=[],featsScoreVect=[],

    154                   featsToFeatMapIdx=[]):
    155      nFeats = len(self._feats)
    156      if mapScoreVect and len(mapScoreVect)!=nFeats:
    157        raise ValueError,'if provided, len(mapScoreVect) should equal numFeats'
    158      nToScore = len(featsToScore)
    159      if featsScoreVect and len(featsScoreVect)!=nToScore:
    160        raise ValueError,'if provided, len(featsScoreVect) should equal len(featsToScore)'
    161      if featsToFeatMapIdx and len(featsToFeatMapIdx)!=nToScore:
    162        raise ValueError,'if provided, len(featsToFeatMapIdx) should equal len(featsToScore)'
    163

    164      if mapScoreVect:
    165        for i in range(nFeats): mapScoreVect[i]=0.0
    166      else:
    167        mapScoreVect = [0.0]*nFeats
    168

    169      if self.scoreMode==FeatMapScoreMode.Closest:
    170        defScore=1000.0
    171      else:
    172        defScore=0.0
    173      if featsScoreVect:
    174        for i in range(nToScore): featsScoreVect[i]=defScore
    175      else:
    176        featsScoreVect = [defScore]*nToScore
    177

    178      if not featsToFeatMapIdx:
    179        featsToFeatMapIdx = [None]*nToScore
    180

    181      for i in range(nToScore):
    182        if self.scoreMode != FeatMapScoreMode.All:
    183          featsToFeatMapIdx[i]=[-1]
    184        else:
    185          featsToFeatMapIdx[i]=[]
    186

    187      for oIdx,oFeat in enumerate(featsToScore):
    188        for sIdx,sFeat in self._loopOverMatchingFeats(oFeat):
    189          if self.scoreMode == FeatMapScoreMode.Closest:
    190            d = sFeat.GetDist2(oFeat)
    191            if d<featsScoreVect[oIdx]:
    192              featsScoreVect[oIdx]=d
    193              featsToFeatMapIdx[oIdx][0]=sIdx
    194          else:
    195            lScore = self.GetFeatFeatScore(sFeat,oFeat,typeMatch=False)
    196            if self.scoreMode == FeatMapScoreMode.Best:
    197              if lScore>featsScoreVect[oIdx]:
    198                featsScoreVect[oIdx]=lScore
    199                featsToFeatMapIdx[oIdx][0]=sIdx
    200            elif self.scoreMode == FeatMapScoreMode.All:
    201              featsScoreVect[oIdx] += lScore
    202              mapScoreVect[sIdx] += lScore
    203              featsToFeatMapIdx[oIdx].append(sIdx)
    204            else:
    205              raise ValueError,'bad score mode'
    206

    207      totScore = 0.0
    208      if self.scoreMode == FeatMapScoreMode.Closest:
    209        for oIdx,oFeat in enumerate(featsToScore):
    210          sIdx = featsToFeatMapIdx[oIdx][0]
    211          if sIdx>-1:
    212            lScore = self.GetFeatFeatScore(sFeat,oFeat,typeMatch=False)
    213            featsScoreVect[oIdx] = lScore
    214            mapScoreVect[sIdx] = lScore
    215            totScore += lScore
    216          else:
    217            featsScoreVect[oIdx] = 0
    218

    219      else:
    220        totScore = sum(featsScoreVect)
    221        if self.scoreMode == FeatMapScoreMode.Best:
    222          for oIdx,lScore in enumerate(featsScoreVect):
    223            sIdx = featsToFeatMapIdx[oIdx][0]
    224            if sIdx>-1:
    225              mapScoreVect[sIdx]=lScore
    226

    227      # replace placeholders:

    228      if self.scoreMode != FeatMapScoreMode.All:
    229        for elem in featsToFeatMapIdx:
    230          if elem==[-1]:
    231            elem.pop()
    232      return totScore
    233

    234

    235 -  def __str__(self):
    236      res = ''
    237      for i,feat in enumerate(self._feats):
    238        weight = feat.weight
    239        pos = feat.GetPos()
    240        res += '% 3d % 12s % 6.4f % 6.4f % 6.4f % 6.4f\n'%(i+1,

    241                                                           feat.GetFamily(),

    242                                                           pos.x,pos.y,pos.z,weight)
    243      return res
    244

    245

    246  #------------------------------------

    247  #

    248  #  doctest boilerplate

    249  #

    250 -def _test():
    251    import doctest,sys
    252    return doctest.testmod(sys.modules["__main__"])
    253

    254  if __name__ == '__main__':
    255    import sys
    256    failed,tried = _test()
    257    sys.exit(failed)
    258