1
2
3
4
5
6
7
8
9
10 import collections
11
12 from rdkit import Chem
13 from rdkit.Chem import rdMolDescriptors as _rdMolDescriptors
14 from rdkit.Chem import rdPartialCharges, rdMolDescriptors
15 import rdkit.Chem.ChemUtils.DescriptorUtilities as _du
16 from rdkit.Chem.EState.EState import (MaxEStateIndex, MinEStateIndex,
17 MaxAbsEStateIndex, MinAbsEStateIndex)
18 from rdkit.Chem.QED import qed
19
20
22 return (hasattr(collections, 'Callable') and isinstance(thing, collections.Callable)) or \
23 hasattr(thing, '__call__')
24
25
26 _descList = []
27
28
30 global _descList, descList
31 from rdkit.Chem import GraphDescriptors, MolSurf, Lipinski, Fragments, Crippen, Descriptors3D
32 from rdkit.Chem.EState import EState_VSA
33 mods = [GraphDescriptors, MolSurf, EState_VSA, Lipinski, Crippen, Fragments]
34
35 otherMods = [Chem]
36
37 for nm, thing in namespace.items():
38 if nm[0] != '_' and _isCallable(thing):
39 _descList.append((nm, thing))
40
41 others = []
42 for mod in otherMods:
43 tmp = dir(mod)
44 for name in tmp:
45 if name[0] != '_':
46 thing = getattr(mod, name)
47 if _isCallable(thing):
48 others.append(name)
49
50 for mod in mods:
51 tmp = dir(mod)
52
53 for name in tmp:
54 if name[0] != '_' and name[-1] != '_' and name not in others:
55
56 if name[:2] == 'py' and name[2:] in tmp:
57 continue
58 if name == 'print_function':
59 continue
60 thing = getattr(mod, name)
61 if _isCallable(thing):
62 namespace[name] = thing
63 _descList.append((name, thing))
64 descList = _descList
65
66
67 MolWt = lambda *x, **y: _rdMolDescriptors._CalcMolWt(*x, **y)
68 MolWt.version = _rdMolDescriptors._CalcMolWt_version
69 MolWt.__doc__ = """The average molecular weight of the molecule
70
71 >>> MolWt(Chem.MolFromSmiles('CC'))
72 30.07
73 >>> MolWt(Chem.MolFromSmiles('[NH4+].[Cl-]'))
74 53.49...
75
76 """
77
78 HeavyAtomMolWt = lambda x: MolWt(x, True)
79 HeavyAtomMolWt.__doc__ = """The average molecular weight of the molecule ignoring hydrogens
80
81 >>> HeavyAtomMolWt(Chem.MolFromSmiles('CC'))
82 24.02...
83 >>> HeavyAtomMolWt(Chem.MolFromSmiles('[NH4+].[Cl-]'))
84 49.46
85
86 """
87 HeavyAtomMolWt.version = "1.0.0"
88
89 ExactMolWt = lambda *x, **y: _rdMolDescriptors.CalcExactMolWt(*x, **y)
90 ExactMolWt.version = _rdMolDescriptors._CalcExactMolWt_version
91 ExactMolWt.__doc__ = """The exact molecular weight of the molecule
92
93 >>> ExactMolWt(Chem.MolFromSmiles('CC'))
94 30.04...
95 >>> ExactMolWt(Chem.MolFromSmiles('[13CH3]C'))
96 31.05...
97
98 """
99
100
102 """ The number of valence electrons the molecule has
103
104 >>> NumValenceElectrons(Chem.MolFromSmiles('CC'))
105 14
106 >>> NumValenceElectrons(Chem.MolFromSmiles('C(=O)O'))
107 18
108 >>> NumValenceElectrons(Chem.MolFromSmiles('C(=O)[O-]'))
109 18
110 >>> NumValenceElectrons(Chem.MolFromSmiles('C(=O)'))
111 12
112
113 """
114 tbl = Chem.GetPeriodicTable()
115 return sum(
116 tbl.GetNOuterElecs(atom.GetAtomicNum()) - atom.GetFormalCharge() + atom.GetTotalNumHs()
117 for atom in mol.GetAtoms())
118
119
120 NumValenceElectrons.version = "1.1.0"
121
122
124 """ The number of radical electrons the molecule has
125 (says nothing about spin state)
126
127 >>> NumRadicalElectrons(Chem.MolFromSmiles('CC'))
128 0
129 >>> NumRadicalElectrons(Chem.MolFromSmiles('C[CH3]'))
130 0
131 >>> NumRadicalElectrons(Chem.MolFromSmiles('C[CH2]'))
132 1
133 >>> NumRadicalElectrons(Chem.MolFromSmiles('C[CH]'))
134 2
135 >>> NumRadicalElectrons(Chem.MolFromSmiles('C[C]'))
136 3
137
138 """
139 return sum(atom.GetNumRadicalElectrons() for atom in mol.GetAtoms())
140
141
142 NumRadicalElectrons.version = "1.1.0"
143
144
146 if not force and hasattr(mol, '_chargeDescriptors'):
147 return mol._chargeDescriptors
148 chgs = rdPartialCharges.ComputeGasteigerCharges(mol)
149 minChg = 500.
150 maxChg = -500.
151 for at in mol.GetAtoms():
152 chg = float(at.GetProp('_GasteigerCharge'))
153 minChg = min(chg, minChg)
154 maxChg = max(chg, maxChg)
155 res = (minChg, maxChg)
156 mol._chargeDescriptors = res
157 return res
158
159
163
164
165 MaxPartialCharge.version = "1.0.0"
166
167
171
172
173 MinPartialCharge.version = "1.0.0"
174
175
179
180
181 MaxAbsPartialCharge.version = "1.0.0"
182
183
187
188
189 MinAbsPartialCharge.version = "1.0.0"
190
191
193 fp = func(*((mol,) + args), **kwargs)
194 if hasattr(fp, 'GetNumOnBits'):
195 val = fp.GetNumOnBits()
196 else:
197 val = len(fp.GetNonzeroElements())
198 return float(val) / mol.GetNumHeavyAtoms()
199
200
201 FpDensityMorgan1 = lambda x: _FingerprintDensity(x, _rdMolDescriptors.GetMorganFingerprint, 1)
202 FpDensityMorgan2 = lambda x: _FingerprintDensity(x, _rdMolDescriptors.GetMorganFingerprint, 2)
203 FpDensityMorgan3 = lambda x: _FingerprintDensity(x, _rdMolDescriptors.GetMorganFingerprint, 3)
204 _du.setDescriptorVersion('1.0.0')(FpDensityMorgan1)
205 _du.setDescriptorVersion('1.0.0')(FpDensityMorgan2)
206 _du.setDescriptorVersion('1.0.0')(FpDensityMorgan3)
207
208 _setupDescriptors(locals())
209
210
212 """Creates a python based property function that can be added to the
213 global property list. To use, subclass this class and override the
214 __call__ method. Then create an instance and add it to the
215 registry. The __call__ method should return a numeric value.
216
217 Example:
218
219 class NumAtoms(Descriptors.PropertyFunctor):
220 def __init__(self):
221 Descriptors.PropertyFunctor.__init__(self, "NumAtoms", "1.0.0")
222 def __call__(self, mol):
223 return mol.GetNumAtoms()
224
225 numAtoms = NumAtoms()
226 rdMolDescriptors.Properties.RegisterProperty(numAtoms)
227 """
228
230 rdMolDescriptors.PythonPropertyFunctor.__init__(self, self, name, version)
231
233 raise NotImplementedError("Please implement the __call__ method")
234
235
236
237
238
239
241 import sys
242 import doctest
243 failed, _ = doctest.testmod(optionflags=doctest.ELLIPSIS, verbose=verbose)
244 sys.exit(failed)
245
246
247 if __name__ == '__main__':
248 _runDoctests()
249