rdkit.Chem.FeatMaps.FeatMaps

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

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

      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.Chem.FeatMaps.FeatMapPoint import FeatMapPoint
     12  import math
     13
     14
     15 -class FeatMapScoreMode(object):
     16    All = 0
     17    """ score each feature in the probe against every matching
     18        feature in the FeatMap.
     19    """
     20
     21    Closest = 1
     22    """ score each feature in the probe against the closest
     23        matching feature in the FeatMap.
     24    """
     25
     26    Best = 2
     27    """ score each feature in the probe against the matching
     28        feature in the FeatMap that leads to the highest score
     29    """
     30
     31
     32 -class FeatDirScoreMode(object):
     33    Ignore = 0
     34    """ ignore feature directions
     35    """
     36
     37    DotFullRange = 1
     38    """ Use the dot product and allow negative contributions when
     39        directions are anti-parallel.
     40        e.g. score = dot(f1Dir,f2Dir)
     41    """
     42
     43    DotPosRange = 2
     44    """ Use the dot product and scale contributions to lie between
     45        zero and one.
     46        e.g. score = ( dot(f1Dir,f2Dir) + 1 ) / 2
     47    """
     48
     49
     50 -class FeatMapParams(object):
     51    """ one of these should be instantiated for each
     52    feature type in the feature map
     53    """
     54    radius = 2.5
     55    " cutoff radius "
     56
     57    width = 1.0
     58    " width parameter (e.g. the gaussian sigma) "
     59
     60 -  class FeatProfile(object):
     61      " scoring profile of the feature "
     62      Gaussian = 0
     63      Triangle = 1
     64      Box = 2
     65
     66    featProfile = FeatProfile.Gaussian
     67
     68
     69 -class FeatMap(object):
     70    dirScoreMode = FeatDirScoreMode.Ignore
     71    scoreMode = FeatMapScoreMode.All
     72    params = {}
     73
     74 -  def __init__(self, params=None, feats=None, weights=None):
     75      if params:
     76        self.params = params
     77      self._initializeFeats(feats, weights)
     78
     79 -  def _initializeFeats(self, feats, weights):
     80      self._feats = []
     81      if feats:
     82        if len(feats) != len(weights):
     83          raise ValueError('feats and weights lists must be the same length')
     84        for feat, weight in zip(feats, weights):
     85          self.AddFeature(feat, weight)
     86
     87 -  def AddFeature(self, feat, weight=None):
     88      if self.params and not feat.GetFamily() in self.params:
     89        raise ValueError('feature family %s not found in params' % feat.GetFamily())
     90
     91      newFeat = FeatMapPoint()
     92      newFeat.initFromFeat(feat)
     93      newFeat.weight = weight
     94
     95      self.AddFeatPoint(newFeat)
     96
     97 -  def AddFeatPoint(self, featPt):
     98      if not isinstance(featPt, FeatMapPoint):
     99        raise ValueError('addFeatPoint() must be called with a FeatMapPoint instance')
    100      if self.params and not featPt.GetFamily() in self.params:
    101        raise ValueError('feature family %s not found in params' % featPt.GetFamily())
    102      self._feats.append(featPt)
    103
    104 -  def GetFeatures(self):
    105      return self._feats
    106
    107 -  def GetNumFeatures(self):
    108      return len(self._feats)
    109
    110 -  def GetFeature(self, i):
    111      return self._feats[i]
    112
    113 -  def DropFeature(self, i):
    114      del self._feats[i]
    115
    116 -  def _loopOverMatchingFeats(self, oFeat):
    117      for sIdx, sFeat in enumerate(self._feats):
    118        if sFeat.GetFamily() == oFeat.GetFamily():
    119          yield sIdx, sFeat
    120
    121 -  def GetFeatFeatScore(self, feat1, feat2, typeMatch=True):
    122      """ feat1 is one of our feats
    123          feat2 is any Feature
    124
    125
    126      """
    127      if typeMatch and feat1.GetFamily() != feat2.GetFamily():
    128        return 0.0
    129      d2 = feat1.GetDist2(feat2)
    130      params = self.params[feat1.GetFamily()]
    131      if d2 > params.radius * params.radius:
    132        return 0.0
    133
    134      if params.featProfile == FeatMapParams.FeatProfile.Gaussian:
    135        score = math.exp(-d2 / params.width)
    136      elif params.featProfile == FeatMapParams.FeatProfile.Triangle:
    137        d = math.sqrt(d2)
    138        if d < params.width:
    139          score = 1. - d / params.width
    140        else:
    141          score = 0.0
    142      elif params.featProfile == FeatMapParams.FeatProfile.Box:
    143        score = 1.0
    144      weight = feat1.weight
    145      score *= weight
    146
    147      if self.dirScoreMode != FeatDirScoreMode.Ignore:
    148        dirScore = feat1.GetDirMatch(feat2)
    149        if self.dirScoreMode == FeatDirScoreMode.DotPosRange:
    150          dirScore = (dirScore + 1.0) / 2.0
    151        elif self.dirScoreMode != FeatDirScoreMode.DotFullRange:
    152          raise NotImplementedError('bad feature dir score mode')
    153        score *= dirScore
    154
    155      return score
    156
    157 -  def ScoreFeats(self, featsToScore, mapScoreVect=[], featsScoreVect=[], featsToFeatMapIdx=[]):
    158      nFeats = len(self._feats)
    159      if mapScoreVect and len(mapScoreVect) != nFeats:
    160        raise ValueError('if provided, len(mapScoreVect) should equal numFeats')
    161      nToScore = len(featsToScore)
    162      if featsScoreVect and len(featsScoreVect) != nToScore:
    163        raise ValueError('if provided, len(featsScoreVect) should equal len(featsToScore)')
    164      if featsToFeatMapIdx and len(featsToFeatMapIdx) != nToScore:
    165        raise ValueError('if provided, len(featsToFeatMapIdx) should equal len(featsToScore)')
    166
    167      if mapScoreVect:
    168        for i in range(nFeats):
    169          mapScoreVect[i] = 0.0
    170      else:
    171        mapScoreVect = [0.0] * nFeats
    172
    173      if self.scoreMode == FeatMapScoreMode.Closest:
    174        defScore = 1000.0
    175      else:
    176        defScore = 0.0
    177      if featsScoreVect:
    178        for i in range(nToScore):
    179          featsScoreVect[i] = defScore
    180      else:
    181        featsScoreVect = [defScore] * nToScore
    182
    183      if not featsToFeatMapIdx:
    184        featsToFeatMapIdx = [None] * nToScore
    185
    186      for i in range(nToScore):
    187        if self.scoreMode != FeatMapScoreMode.All:
    188          featsToFeatMapIdx[i] = [-1]
    189        else:
    190          featsToFeatMapIdx[i] = []
    191
    192      for oIdx, oFeat in enumerate(featsToScore):
    193        for sIdx, sFeat in self._loopOverMatchingFeats(oFeat):
    194          if self.scoreMode == FeatMapScoreMode.Closest:
    195            d = sFeat.GetDist2(oFeat)
    196            if d < featsScoreVect[oIdx]:
    197              featsScoreVect[oIdx] = d
    198              featsToFeatMapIdx[oIdx][0] = sIdx
    199          else:
    200            lScore = self.GetFeatFeatScore(sFeat, oFeat, typeMatch=False)
    201            if self.scoreMode == FeatMapScoreMode.Best:
    202              if lScore > featsScoreVect[oIdx]:
    203                featsScoreVect[oIdx] = lScore
    204                featsToFeatMapIdx[oIdx][0] = sIdx
    205            elif self.scoreMode == FeatMapScoreMode.All:
    206              featsScoreVect[oIdx] += lScore
    207              mapScoreVect[sIdx] += lScore
    208              featsToFeatMapIdx[oIdx].append(sIdx)
    209            else:
    210              raise ValueError('bad score mode')
    211
    212      totScore = 0.0
    213      if self.scoreMode == FeatMapScoreMode.Closest:
    214        for oIdx, oFeat in enumerate(featsToScore):
    215          sIdx = featsToFeatMapIdx[oIdx][0]
    216          if sIdx > -1:
    217            lScore = self.GetFeatFeatScore(sFeat, oFeat, typeMatch=False)
    218            featsScoreVect[oIdx] = lScore
    219            mapScoreVect[sIdx] = lScore
    220            totScore += lScore
    221          else:
    222            featsScoreVect[oIdx] = 0
    223
    224      else:
    225        totScore = sum(featsScoreVect)
    226        if self.scoreMode == FeatMapScoreMode.Best:
    227          for oIdx, lScore in enumerate(featsScoreVect):
    228            sIdx = featsToFeatMapIdx[oIdx][0]
    229            if sIdx > -1:
    230              mapScoreVect[sIdx] = lScore
    231
    232      # replace placeholders:
    233      if self.scoreMode != FeatMapScoreMode.All:
    234        for elem in featsToFeatMapIdx:
    235          if elem == [-1]:
    236            elem.pop()
    237      return totScore
    238
    239 -  def __str__(self):
    240      res = ''
    241      for i, feat in enumerate(self._feats):
    242        weight = feat.weight
    243        pos = feat.GetPos()
    244        res += '% 3d % 12s % 6.4f % 6.4f % 6.4f % 6.4f\n' % (i + 1, feat.GetFamily(), pos.x, pos.y,
    245                                                             pos.z, weight)
    246      return res
    247