1
2
3
4
5
6
7 """ Functionality for SATIS typing atoms
8
9 """
10 import Chem
11
12 _debug = 0
13
14
15
16
17
18 aldehydePatt = Chem.MolFromSmarts('[CD2]=[OD1]')
19 ketonePatt = Chem.MolFromSmarts('[CD3]=[OD1]')
20 amidePatt = Chem.MolFromSmarts('[CD3](=[OD1])-[#7]')
21 esterPatt = Chem.MolFromSmarts('C(=[OD1])-O-[#6]')
22 carboxylatePatt = Chem.MolFromSmarts('C(=[OD1])-[OX1]')
23 carboxylPatt = Chem.MolFromSmarts('C(=[OD1])-[OX2]')
24
25 specialCases = ((carboxylatePatt,97),
26 (esterPatt,96),
27 (carboxylPatt,98),
28 (amidePatt,95),
29 (ketonePatt,94),
30 (aldehydePatt,93))
31
32
34 """ returns SATIS codes for all atoms in a molecule
35
36 The SATIS definition used is from:
37 J. Chem. Inf. Comput. Sci. _39_ 751-757 (1999)
38
39 each SATIS code is a string consisting of _neighborsToInclude_ + 1
40 2 digit numbers
41
42 **Arguments**
43
44 - mol: a molecule
45
46 - neighborsToInclude (optional): the number of neighbors to include
47 in the SATIS codes
48
49 **Returns**
50
51 a list of strings nAtoms long
52
53 """
54 global specialCases
55
56 nAtoms = mol.GetNumAtoms()
57 atomicNums = [0]*nAtoms
58 atoms = mol.GetAtoms()
59 for i in xrange(nAtoms):
60 atomicNums[i] = atoms[i].GetAtomicNum()
61
62 nSpecialCases = len(specialCases)
63 specialCaseMatches = [None]*nSpecialCases
64 for i,(patt,idx) in enumerate(specialCases):
65 if mol.HasSubstructMatch(patt):
66 specialCaseMatches[i] = mol.GetSubstructMatches(patt)
67 else:
68 specialCaseMatches[i] = ()
69
70 codes = [None]*nAtoms
71 for i in range(nAtoms):
72 code = [99]*(neighborsToInclude+1)
73 atom = atoms[i]
74 atomIdx = atom.GetIdx()
75 code[0] = min(atom.GetAtomicNum(),99)
76 bonds = atom.GetBonds()
77 nBonds = len(bonds)
78 otherIndices = [-1]*nBonds
79 if _debug: print code[0],
80 for j in range(nBonds):
81 otherIndices[j] = bonds[j].GetOtherAtom(atom).GetIdx()
82 if _debug: print otherIndices[j],
83 if _debug: print
84 otherNums = [atomicNums[x] for x in otherIndices] + \
85 [1]*atom.GetTotalNumHs()
86 otherNums.sort()
87
88 nOthers = len(otherNums)
89 if nOthers > neighborsToInclude:
90 otherNums.reverse()
91 otherNums = otherNums[:neighborsToInclude]
92 otherNums.reverse()
93 for j in range(neighborsToInclude):
94 code[j+1] = min(otherNums[j],99)
95 else:
96 for j in range(nOthers):
97 code[j+1] = min(otherNums[j],99)
98 if nOthers < neighborsToInclude and code[0] in [6,8]:
99 found = 0
100 for j in range(nSpecialCases):
101 for matchTuple in specialCaseMatches[j]:
102 if atomIdx in matchTuple:
103 code[-1] = specialCases[j][1]
104 found = 1
105 break
106 if found:
107 break
108
109 codes[i] = ''.join(['%02d'%(x) for x in code])
110 return codes
111
112 if __name__ == '__main__':
113 smis = ['CC(=O)NC','CP(F)(Cl)(Br)(O)',
114 'O=CC(=O)C','C(=O)OCC(=O)O','C(=O)[O-]']
115 for smi in smis:
116 print smi
117 m = Chem.MolFromSmiles(smi)
118 codes = SATISTypes(m)
119 print codes
120