1
2
3
4
5
6
7
8
9
10 """ generation of 2D pharmacophores
11
12 **Notes**
13
14 - The terminology for this gets a bit rocky, so here's a glossary of what
15 terms used here mean:
16
17 1) *N-point pharmacophore* a combination of N features along with
18 distances betwen them.
19
20 2) *N-point proto-pharmacophore*: a combination of N feature
21 definitions without distances. Each N-point
22 proto-pharmacophore defines a manifold of potential N-point
23 pharmacophores.
24
25 3) *N-point scaffold*: a collection of the distances defining
26 an N-point pharmacophore without feature identities.
27
28 See Docs/Chem/Pharm2D.triangles.jpg for an illustration of the way
29 pharmacophores are broken into triangles and labelled.
30
31 See Docs/Chem/Pharm2D.signatures.jpg for an illustration of bit
32 numbering
33
34 """
35 from __future__ import print_function
36
37 from rdkit.Chem.Pharm2D import Utils, SigFactory
38 from rdkit.RDLogger import logger
39
40 logger = logger()
41
42 _verbose = 0
43
44
46 """ Internal use only
47
48 """
49 if _verbose:
50 print('match:', match)
51 nPts = len(match)
52 distsToCheck = Utils.nPointDistDict[nPts]
53 nDists = len(distsToCheck)
54 dist = [0] * nDists
55 bins = sigFactory.GetBins()
56 minD, maxD = bins[0][0], bins[-1][1]
57
58 for i in range(nDists):
59 pt0, pt1 = distsToCheck[i]
60 minSeen = maxD
61 for idx1 in match[pt0]:
62 for idx2 in match[pt1]:
63 minSeen = min(minSeen, dMat[idx1, idx2])
64 if minSeen == 0 or minSeen < minD:
65 return
66
67 d = int(minSeen)
68
69 if d == 0 or d < minD or d >= maxD:
70 return
71 dist[i] = d
72
73 idx = sigFactory.GetBitIdx(featureSet, dist, sortIndices=False)
74 if _verbose:
75 print('\t', dist, minD, maxD, idx)
76
77 if sigFactory.useCounts:
78 sig[idx] = sig[idx] + 1
79 else:
80 sig.SetBit(idx)
81 return idx
82
83
85 """ generates a 2D fingerprint for a molecule using the
86 parameters in _sig_
87
88 **Arguments**
89
90 - mol: the molecule for which the signature should be generated
91
92 - sigFactory : the SigFactory object with signature parameters
93 NOTE: no preprocessing is carried out for _sigFactory_.
94 It *must* be pre-initialized.
95
96 - perms: (optional) a sequence of permutation indices limiting which
97 pharmacophore combinations are allowed
98
99 - dMat: (optional) the distance matrix to be used
100
101 - bitInfo: (optional) used to return the atoms involved in the bits
102
103 """
104 if not isinstance(sigFactory, SigFactory.SigFactory):
105 raise ValueError('bad factory')
106 featFamilies = sigFactory.GetFeatFamilies()
107 if _verbose:
108 print('* feat famillies:', featFamilies)
109 nFeats = len(featFamilies)
110 minCount = sigFactory.minPointCount
111 maxCount = sigFactory.maxPointCount
112 if maxCount > 3:
113 logger.warning(' Pharmacophores with more than 3 points are not currently supported.\n' +
114 'Setting maxCount to 3.')
115 maxCount = 3
116
117
118 if dMat is None:
119 from rdkit import Chem
120 useBO = sigFactory.includeBondOrder
121 dMat = Chem.GetDistanceMatrix(mol, useBO)
122
123
124 if perms is None:
125 perms = []
126 for count in range(minCount, maxCount + 1):
127 perms += Utils.GetIndexCombinations(nFeats, count)
128
129
130 featMatches = sigFactory.GetMolFeats(mol)
131 if _verbose:
132 print(' featMatches:', featMatches)
133
134 sig = sigFactory.GetSignature()
135 for perm in perms:
136
137
138 featClasses = [0]
139 for i in range(1, len(perm)):
140 if perm[i] == perm[i - 1]:
141 featClasses.append(featClasses[-1])
142 else:
143 featClasses.append(featClasses[-1] + 1)
144
145
146
147 matchPerms = [featMatches[x] for x in perm]
148 if _verbose:
149 print('\n->Perm: %s' % (str(perm)))
150 print(' matchPerms: %s' % (str(matchPerms)))
151
152
153 matchesToMap = Utils.GetUniqueCombinations(matchPerms, featClasses)
154 for i, entry in enumerate(matchesToMap):
155 entry = [x[1] for x in entry]
156 matchesToMap[i] = entry
157 if _verbose:
158 print(' mtM:', matchesToMap)
159
160 for match in matchesToMap:
161 if sigFactory.shortestPathsOnly:
162 idx = _ShortestPathsMatch(match, perm, sig, dMat, sigFactory)
163 if idx is not None and bitInfo is not None:
164 l = bitInfo.get(idx, [])
165 l.append(match)
166 bitInfo[idx] = l
167 return sig
168