1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """
16 This module implements the HydrogenBondBuilder class which builds hydrogen
17 bonds between appropriate atoms.
18
19 """
20
21
22 from PyBabel.atomTypes import AtomHybridization
23 from PyBabel.bo import BondOrder
24
25 from MolKit.molecule import Atom, AtomSet, HydrogenBond
26 from MolKit.distanceSelector import DistanceSelector
27
28
29 import Numeric, math
30
31
32 sp2Donors = ['Nam', 'Ng+', 'Npl']
33 sp3Donors = ['N3+', 'O3','S3']
34 allDonors = ['Nam', 'Ng+', 'Npl', 'N3+', 'O3','S3']
35
36
37 sp2Acceptors = ['O2', 'O-', 'Npl', 'Nam']
38 sp3Acceptors = ['S3', 'O3']
39 allAcceptors = ['O2', 'O-', 'Npl', 'Nam', 'S3', 'O3']
40
41
42
43
44
46 d = Numeric.array(c2) - Numeric.array(c1)
47 ans = math.sqrt(Numeric.sum(d*d))
48 return round(ans, 3)
49
50
52
53
54
55 acCoords = ac.coords
56 hCoords = hat.coords
57 dCoords = don.coords
58 pt1 = Numeric.array(acCoords, 'f')
59 pt2 = Numeric.array(hCoords, 'f')
60 pt3 = Numeric.array(dCoords, 'f')
61
62
63
64 v1 = Numeric.array(pt1 - pt2)
65 v2 = Numeric.array(pt3 - pt2)
66 dist1 = math.sqrt(Numeric.sum(v1*v1))
67 dist2 = math.sqrt(Numeric.sum(v2*v2))
68 sca = Numeric.dot(v1, v2)/(dist1*dist2)
69 if sca>1.0:
70 sca = 1.0
71 elif sca<-1.0:
72 sca = -1.0
73 ang = math.acos(sca)*180./math.pi
74 return round(ang, 5)
75
76
78 pth = [pt[0], pt[1], pt[2], 1.0]
79 return Numeric.matrixmultiply(mat, pth)[:3]
80
81
89
90
91 distCutoff=2.25
92 distCutoff2=3.00
93 d2min=120
94 d2max=180
95 d3min=120
96 d3max=180
97 a2min=110
98 a2max=150
99 a3min=100
100 a3max=150
101
102
104 """
105 object which can build hydrogen bonds between atoms according
106 to their coords and atom type
107 """
108
109 - def __init__(self, distCutoff=distCutoff, distCutoff2=distCutoff2,
110 d2min=d2min, d2max=d2max, d3min=d3min, d3max=d3max,
111 a2min=a2min, a2max=a2max, a3min=a3min, a3max=a3max,
112 donorTypes=allDonors, acceptorTypes=allAcceptors,
113 distOnly=False):
114 d = self.paramDict = {}
115 d['distCutoff'] = distCutoff
116 d['distCutoff2'] = distCutoff2
117 d['d2min'] = d2min
118 d['d2max'] = d2max
119 d['d3min'] = d3min
120 d['d3max'] = d3max
121 d['a2min'] = a2min
122 d['a2max'] = a2max
123 d['a3min'] = a3min
124 d['a3max'] = a3max
125 d['donorTypes'] = donorTypes
126 d['acceptorTypes'] = acceptorTypes
127 d['distOnly'] = distOnly
128 self.distSelector = DistanceSelector(return_dist=0)
129
130
132 try:
133 ats.babel_type
134 ats._bndtyped
135 except AttributeError:
136 babel = AtomHybridization()
137 bond_orderer = BondOrder()
138 tops = ats.top.uniq()
139 for mol in tops:
140 babel.assignHybridization(mol.allAtoms)
141 bond_orderer.assignBondOrder(mol.allAtoms, mol.allAtoms.bonds[0])
142 mol.allAtoms._bndtyped = 1
143
144
146 tops = ats.top.uniq()
147 for mol in tops:
148 for a in mol.allAtoms:
149 if hasattr(a, 'hbonds'):
150 for item in a.hbonds:
151 del item
152 delattr(a, 'hbonds')
153
154
155 - def build(self, group1, group2=None, reset=True, paramDict=None):
156 """atDict <- build(group1, group2, reset, paramDict=None, **kw):
157 group1: atoms
158 group2: atoms
159 reset: remove all previous hbonds, default True!
160
161 paramDict: a dictionary with these keys and default values
162 distCutoff: 2.25 hydrogen--acceptor distance
163 distCutoff2: 3.00 donor... acceptor distance
164 d2min: 120 <min theta for sp2 hybridized donors>
165 d2max: 180 <max theta for sp2 hybridized donors>
166 d3min: 120 <min theta for sp3 hybridized donors>
167 d3max: 170 <max theta for sp3 hybridized donors>
168
169 a2min: 120 <min phi for sp2 hybridized donors>
170 a2max: 150 <max phi for sp2 hybridized donors>
171 a3min: 100 <min phi for sp3 hybridized donors>
172 a3max: 150 <max phi for sp3 hybridized donors>
173 @@FIX THIS: these do not seem to be input here
174 donorTypes = allDonors
175 acceptorTypes = allAcceptors
176 """
177
178 if paramDict is None:
179 paramDict = self.paramDict
180
181
182 if group2 is None:
183 group2 = group1
184
185
186
187 if group1.__class__!=Atom:
188 group1 = group1.findType(Atom)
189
190 if not len(group1):
191 return "ERROR"
192 self.check_babel_types(group1)
193
194
195 if group2.__class__!=Atom:
196 group2 = group2.findType(Atom)
197
198 if not len(group2):
199 return "ERROR"
200 self.check_babel_types(group2)
201
202 if reset:
203
204 self.reset(group1)
205 self.reset(group2)
206
207
208
209
210
211 atDict = {}
212 dict1 = self.buildD(group1, paramDict)
213
214
215
216
217
218 if group1==group2:
219
220 atD1 = self.process(dict1, dict1, paramDict)
221
222 else:
223
224
225
226 dict2 = self.buildD(group2, paramDict)
227 atD1 = self.process(dict1, dict2, paramDict)
228 atD2 = self.process(dict2, dict1, paramDict)
229
230
231
232 if type(atD1)==type(atDict):
233 atDict.update(atD1)
234 if group1!=group2 and type(atD2)==type(atDict):
235 atDict.update(atD2)
236
237
238 return atDict
239
240
256
257
259
260 sp2 = []
261 sp3 = []
262 for item in sp2Donors:
263 if item in donorList: sp2.append(item)
264 for item in sp3Donors:
265 if item in donorList: sp3.append(item)
266
267 dAts2 = ats.get(lambda x, l=sp2: x.babel_type in l)
268 if not dAts2: dAts2=AtomSet([])
269 else:
270 dAts2 = self.checkForPossibleH(dAts2, 3)
271
272 dAts3 = ats.get(lambda x, l=sp3: x.babel_type in l)
273 if not dAts3: dAts3=AtomSet([])
274 else: dAts3 = self.checkForPossibleH(dAts3, 4)
275 return dAts2, dAts3
276
277
279 ntypes = ['Npl', 'Nam']
280 npls = accAts.get(lambda x, ntypes=ntypes: x.babel_type=='Npl')
281 nams = accAts.get(lambda x, ntypes=ntypes: x.babel_type=='Nam')
282
283 restAts = accAts.get(lambda x, ntypes=ntypes: x.babel_type not in ntypes)
284 if not restAts: restAts = AtomSet([])
285
286 if npls:
287
288 for at in npls:
289 s = 0
290 for b in at.bonds:
291 if b.bondOrder=='aromatic':
292 s = s + 2
293 else: s = s + b.bondOrder
294
295
296 if s<4:
297 restAts.append(at)
298 if nams:
299
300 for at in nams:
301 s = 0
302 for b in at.bonds:
303 if b.bondOrder=='aromatic':
304 s = s + 2
305 else: s = s + b.bondOrder
306
307 if s<3:
308 restAts.append(at)
309 return restAts
310
311
313
314
315 sp2 = []
316 sp3 = []
317 for item in sp2Acceptors:
318 if item in acceptorList: sp2.append(item)
319 for item in sp3Acceptors:
320 if item in acceptorList: sp3.append(item)
321
322 dAts2 = AtomSet(ats.get(lambda x, l=sp2: x.babel_type in l))
323 if dAts2:
324 dAts2 = self.filterAcceptors(dAts2)
325 dAts3 = AtomSet(ats.get(lambda x, l=sp3: x.babel_type in l))
326 return dAts2, dAts3
327
328
329 - def buildD(self, ats, paramDict=None):
330 if paramDict is None:
331 paramDict = self.paramDict
332
333 if not paramDict.has_key('distCutoff'):
334 paramDict['distCutoff'] = 2.25
335 if not paramDict.has_key('distCutoff2'):
336 paramDict['distCutoff2'] = 3.00
337 if not paramDict.has_key('d2min'):
338 paramDict['d2min'] = 120.
339 if not paramDict.has_key('d2max'):
340 paramDict['d2max'] = 180.
341 if not paramDict.has_key('d3min'):
342 paramDict['d3min'] = 120.
343 if not paramDict.has_key('d3max'):
344 paramDict['d3max'] = 170.
345 if not paramDict.has_key('a2min'):
346 paramDict['a2min'] = 130.
347 if not paramDict.has_key('a2max'):
348 paramDict['a2max'] = 170.
349 if not paramDict.has_key('a3min'):
350 paramDict['a3min'] = 120.
351 if not paramDict.has_key('a3max'):
352 paramDict['a3max'] = 170.
353 if not paramDict.has_key('distOnly'):
354 paramDict['distOnly'] = 0
355 if not paramDict.has_key('donorTypes'):
356 paramDict['donorTypes'] = allDonors
357 if not paramDict.has_key('acceptorTypes'):
358 paramDict['acceptorTypes'] = allAcceptors
359
360 d = {}
361 donorTypes = paramDict['donorTypes']
362 donor2Ats, donor3Ats = self.getHBDonors(ats, donorTypes)
363 d23 = donor2Ats + donor3Ats
364
365
366 hydrogen_atoms = ats.get(lambda x: x.element=='H' and len(x.bonds))
367
368 hAts = AtomSet(hydrogen_atoms.get(lambda x, donorTypes=donorTypes:
369 x.bonds[0].atom1.babel_type in donorTypes\
370 or x.bonds[0].atom2.babel_type in donorTypes))
371 d['hAts'] = hAts
372 d['donor2Ats'] = donor2Ats
373 d['donor3Ats'] = donor3Ats
374
375 acceptorTypes = paramDict['acceptorTypes']
376
377 acceptor2Ats, acceptor3Ats = self.getHBAcceptors(ats, acceptorTypes)
378 d['acceptor2Ats'] = acceptor2Ats
379 d['acceptor3Ats'] = acceptor3Ats
380 if acceptor2Ats:
381 acceptorAts = acceptor2Ats
382 if acceptor3Ats:
383 acceptorAts = acceptorAts + acceptor3Ats
384 elif acceptor3Ats:
385 acceptorAts = acceptor3Ats
386 else:
387
388 acceptorAts = None
389 d['acceptorAts'] = acceptorAts
390 return d
391
392
394 pass
395
396
397
398
399
400
401
402 - def process(self, dict1, dict2, paramDict):
403
404 hAts = dict1['hAts']
405 tAts = hAts
406 dist = paramDict['distCutoff']
407 distOnly = paramDict['distOnly']
408
409 if not hAts:
410
411 tAts = dict1['donor2Ats'] + dict1['donor3Ats']
412 dist = paramDict['distCutoff2']
413
414 acceptorAts = dict2['acceptorAts']
415
416 if not acceptorAts or not tAts:
417 return {}, {}
418
419
420
421
422 atDict = self.distSelector.select(tAts, acceptorAts, dist)
423
424
425
426 atDict = self.removeNeighbors(atDict)
427
428 donor2Ats = dict1['donor2Ats']
429 donor3Ats = dict1['donor3Ats']
430 acceptor2Ats = dict2['acceptor2Ats']
431 acceptor3Ats = dict2['acceptor3Ats']
432
433 if distOnly:
434
435 self.makeBonds(atDict, donor2Ats, donor3Ats, \
436 acceptor2Ats, acceptor3Ats, paramDict)
437 return atDict
438
439 badAtDict = self.filterBasedOnAngs(atDict, donor2Ats, donor3Ats, \
440 acceptor2Ats, acceptor3Ats, paramDict)
441 atDict = self.removeBadAts(atDict, badAtDict)
442 if atDict is None:
443 atDict = {}
444 return atDict
445
446
447 - def makeBonds(self, pD, d2Ats, d3Ats, a2Ats, a3ats, paramDict):
448 for k in pD.keys():
449 if k.element=='H':
450 if hasattr(k, 'hbonds') and len(k.hbonds):
451 continue
452 d = k.bonds[0].atom1
453 if id(d)==id(k): d = k.bonds[0].atom2
454
455 h = k
456 else:
457 d = k
458 h = None
459
460 for ac in pD[k]:
461 if ac==d: continue
462 dSp2 = d in d2Ats
463 aSp2 = ac in a2Ats
464 if dSp2:
465 if aSp2: typ = 22
466 else: typ = 23
467 elif aSp2: typ = 32
468 else: typ = 33
469
470 alreadyBonded = 0
471 if hasattr(d, 'hbonds') and hasattr(ac,'hbonds'):
472 for hb in d.hbonds:
473 if hb.donAt==ac or hb.accAt==ac:
474 alreadyBonded = 1
475
476 if not alreadyBonded:
477 newHB = HydrogenBond(d, ac, h, typ=typ)
478 if not hasattr(ac, 'hbonds'):
479 ac.hbonds=[]
480 if not hasattr(d, 'hbonds'):
481 d.hbonds=[]
482 ac.hbonds.append(newHB)
483 d.hbonds.append(newHB)
484 if h is not None:
485
486 h.hbonds = [newHB]
487
488
490 badAtDict = {}
491 d2max = paramDict['d2max']
492 d2min = paramDict['d2min']
493 d3max = paramDict['d3max']
494 d3min = paramDict['d3min']
495
496 a2max = paramDict['a2max']
497 a2min = paramDict['a2min']
498 a3max = paramDict['a3max']
499 a3min = paramDict['a3min']
500
501 for k in pD.keys():
502 if k.element=='H':
503 d = k.bonds[0].atom1
504 if id(d)==id(k): d = k.bonds[0].atom2
505
506 h = k
507 else:
508 d = k
509 h = None
510 badAts = AtomSet([])
511 ct = 0
512 for ac in pD[k]:
513 if h is not None:
514 ang = getAngle(ac, h, d)
515 else:
516 acN = ac.bonds[0].atom1
517 if id(acN) == id(ac): acN = ac.bonds[0].atom2
518
519 ang = getAngle(d, ac, acN)
520
521 dSp2 = d in d2Ats
522 aSp2 = ac in a2Ats
523
524 if h is not None:
525 if dSp2:
526 upperLim = d2max
527 lowerLim = d2min
528
529
530 else:
531 upperLim = d3max
532 lowerLim = d3min
533
534
535 else:
536
537 if dSp2:
538 upperLim = a2max
539 lowerLim = a2min
540
541
542 else:
543 upperLim = a3max
544 lowerLim = a3min
545
546
547 if ang>lowerLim and ang <upperLim:
548
549 if dSp2:
550 if aSp2: typ = 22
551 else: typ = 23
552 elif aSp2: typ = 32
553 else: typ = 33
554
555 alreadyBonded = 0
556 if hasattr(d, 'hbonds') and hasattr(ac,'hbonds'):
557 for hb in d.hbonds:
558 if hb.donAt==ac or hb.accAt==ac:
559 alreadyBonded = 1
560 if not alreadyBonded:
561 newHB = HydrogenBond(d, ac, h, theta=ang, typ=typ)
562 if not hasattr(ac, 'hbonds'):
563 ac.hbonds=[]
564 if not hasattr(d, 'hbonds'):
565 d.hbonds=[]
566 ac.hbonds.append(newHB)
567 d.hbonds.append(newHB)
568 if h is not None:
569
570 h.hbonds = [newHB]
571
572
573
574 else:
575 badAts.append(ac)
576 ct = ct + 1
577 badAtDict[k] = badAts
578 return badAtDict
579
580
582
583 badKeys= badAtDict.keys()
584 for at in atDict.keys():
585 if at not in badKeys:
586 continue
587 if not len(badAtDict[at]):
588 continue
589 closeAts = atDict[at]
590 badAts = badAtDict[at]
591 goodAts = []
592 for i in range(len(closeAts)):
593 cAt = closeAts[i]
594 if cAt not in badAts:
595 goodAts.append(cAt)
596 if len(goodAts):
597 atDict[at] = goodAts
598 else:
599 del atDict[at]
600 return atDict
601
602
604
605
606 for at in atDict.keys():
607 closeAts = atDict[at]
608 bondedAts = AtomSet([])
609 for b in at.bonds:
610
611 at2 = b.atom1
612 if id(at2)==id(at): at2 = b.atom2
613 bondedAts.append(at2)
614
615
616 for b2 in at2.bonds:
617 at3 = b2.atom1
618 if id(at3)==id(at2): at3 = b.atom2
619
620 if id(at3)!=id(at):
621 bondedAts.append(at3)
622
623
624
625
626 bondedAts = bondedAts.uniq()
627 goodAts = []
628 for i in range(len(closeAts)):
629 cAt = closeAts[i]
630 if cAt not in bondedAts:
631 goodAts.append(cAt)
632 if len(goodAts):
633 atDict[at] = goodAts
634 else:
635 del atDict[at]
636 return atDict
637
638
640 donorList = paramDict['donorTypes']
641
642
643 hats = AtomSet(nodes.get(lambda x: x.element=='H'))
644
645
646 if hats:
647 dAts = AtomSet([])
648 for at in hats:
649 for b in at.bonds:
650 at2 = b.atom1
651 if id(at2)==id(at): at2 = b.atom2
652 dAts.append(at2)
653
654 else:
655 dAts = nodes
656
657 sp2 = []
658 for t in ['Nam', 'Ng+', 'Npl']:
659 if t in donorList:
660 sp2.append(t)
661
662
663 sp2DAts = None
664 if len(sp2):
665 sp2DAts = AtomSet(dAts.get(lambda x, sp2=sp2: x.babel_type in sp2))
666
667 hsp2 = AtomSet([])
668 if sp2DAts:
669 if hats:
670 hsp2 = AtomSet(hats.get(lambda x, sp2DAts=sp2DAts:x.bonds[0].atom1 \
671 in sp2DAts or x.bonds[0].atom2 in sp2DAts))
672 if sp2DAts:
673
674 n2Dons = AtomSet(sp2DAts.get(lambda x: x.element=='N'))
675 if n2Dons:
676 n2Dons.bl=0
677 for at in n2Dons:
678 for b in at.bonds:
679 if type(b.bondOrder)==type(2):
680 at.bl = at.bl + b.bondOrder
681 else:
682 at.bl = at.bl + 2
683
684 nH = at.findHydrogens()
685 at.bl = at.bl - len(nH)
686 badAts = AtomSet(n2Dons.get(lambda x: x.bl>2))
687 if badAts:
688 sp2DAts = sp2DAts - badAts
689 delattr(n2Dons,'bl')
690
691 sp3 = []
692 for t in ['N3+', 'S3', 'O3']:
693 if t in donorList:
694 sp3.append(t)
695 n3DAts = None
696 if 'N3+' in sp3:
697 n3DAts = AtomSet(dAts.get(lambda x: x.babel_type=='N3+'))
698 o3DAts = None
699 if 'O3' in sp3:
700 o3DAts = AtomSet(dAts.get(lambda x: x.babel_type=='O3'))
701 if o3DAts:
702
703 badO3s = AtomSet([])
704 for at in o3DAts:
705 if len(at.bonds)<2: continue
706 if len(at.findHydrogens()): continue
707 else:
708 badO3s.append(at)
709 if len(badO3s):
710 o3DAts = o3DAts - badO3s
711 s3DAts = None
712 if 'S3' in sp3:
713 s3DAts = AtomSet(dAts.get(lambda x: x.babel_type=='S3'))
714 sp3DAts = AtomSet([])
715 for item in [n3DAts, o3DAts, s3DAts]:
716 if item:
717 sp3DAts = sp3DAts + item
718 hsp3 = AtomSet([])
719 if sp3DAts:
720 if hats:
721 hsp3 = AtomSet(hats.get(lambda x, sp3DAts=sp3DAts:x.bonds[0].atom1 \
722 in sp3DAts or x.bonds[0].atom2 in sp3DAts))
723 hsp = hsp2 + hsp3
724
725
726
727 return hsp, sp2DAts, sp3DAts
728
730 acceptorList = paramDict['acceptorTypes']
731
732
733 sp2 = []
734 for t in ['Npl', 'Nam']:
735 if t in acceptorList: sp2.append(t)
736 n2Accs = None
737 if 'Npl' in sp2:
738 n2Accs = AtomSet(nodes.get(lambda x: x.babel_type=='Npl'))
739 if 'Nam' in sp2:
740 n2Accs2 = AtomSet(nodes.get(lambda x: x.babel_type=='Nam'))
741 if n2Accs2:
742 if n2Accs:
743 n2Accs = n2Accs+n2Accs2
744 else:
745 n2Accs = n2Accs2
746 if n2Accs is None:
747 n2Accs = AtomSet([])
748
749 o_sp2 = []
750 for t in ['O2', 'O-']:
751 if t in acceptorList: sp2.append(t)
752
753 o2Accs = None
754 if 'O2' in o_sp2:
755 o2Accs = AtomSet(nodes.get(lambda x: x.babel_type=='O2'))
756 if 'O-' in sp2:
757 o2Accs2 = AtomSet(nodes.get(lambda x: x.babel_type=='O-'))
758 if o2Accs2:
759 if o2Accs:
760 o2Accs = o2Accs+o2Accs2
761 else:
762 o2Accs = o2Accs2
763 if o2Accs is None:
764 o2Accs = AtomSet([])
765
766
767 o3Accs = None
768 if 'O3' in acceptorList:
769 o3Accs = AtomSet(nodes.get(lambda x: x.babel_type=='O3'))
770 if o3Accs is None: o3Accs = AtomSet([])
771
772 s3Accs = None
773 if 'S3' in acceptorList:
774 s3Accs = AtomSet(nodes.get(lambda x: x.babel_type=='S3'))
775 if s3Accs is None: s3Accs = AtomSet([])
776
777 ret2Ats = AtomSet([])
778 for item in [n2Accs, o2Accs]:
779 ret2Ats = ret2Ats + item
780
781 ret3Ats = AtomSet([])
782 for item in [s3Accs, o3Accs]:
783 ret3Ats = ret3Ats + item
784 if ret2Ats: print 'ret2Ats=', ret2Ats.name
785 else: print 'no ret2Ats'
786 if ret3Ats: print 'ret3Ats=', ret3Ats.name
787 else: print 'no ret3Ats'
788 return ret2Ats, ret3Ats
789