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