Package AutoDockTools :: Module autoflexCommands
[hide private]
[frames] | no frames]

Source Code for Module AutoDockTools.autoflexCommands

   1  ############################################################################# 
   2  # 
   3  # Author: Ruth HUEY, Michel F. SANNER 
   4  # 
   5  # Copyright: M. Sanner TSRI 2000 
   6  # 
   7  ############################################################################# 
   8  # 
   9  # 
  10  # $Header: /opt/cvs/python/packages/share1.5/AutoDockTools/autoflexCommands.py,v 1.57.2.2 2007/08/16 21:10:48 vareille Exp $ 
  11  # 
  12  # $Id: autoflexCommands.py,v 1.57.2.2 2007/08/16 21:10:48 vareille Exp $ 
  13  # 
  14  # 
  15  # 
  16  # 
  17  # 
  18  # 
  19  # 
  20   
  21  """ 
  22  This Module facilitates producing a  files for AutoDock. The steps in this process are: 
  23   
  24      * Set the macromolecule:  
  25   
  26          o Read a PDBQT Macromolecule  
  27   
  28          o Choose Macromol... 
  29   
  30      * Select which residues are to be flexible in macromolecule using Pmv selection tools: 
  31   
  32          o ICOM Select  
  33   
  34          o SelectFromString 
  35   
  36          o Select Spherical Region 
  37   
  38      * The results of the previous steps are written to a file. The user selects a filename via a filebrowser.   
  39       
  40  """ 
  41  import Numeric 
  42   
  43  from DejaVu import viewerConst 
  44  from ViewerFramework.VFCommand import CommandGUI 
  45  ##  from ViewerFramework.gui import InputFormDescr 
  46  from mglutil.gui.InputForm.Tk.gui import InputFormDescr 
  47  from mglutil.gui.InputForm.Tk.gui import InputFormDescr 
  48  from mglutil.gui.BasicWidgets.Tk.thumbwheel import ThumbWheel 
  49  from mglutil.gui.BasicWidgets.Tk.customizedWidgets import ListChooser,\ 
  50                                                  ExtendedSliderWidget 
  51   
  52  from Pmv.mvCommand import MVCommand, MVBondICOM, MVAtomICOM 
  53  from MolKit.tree import TreeNode, TreeNodeSet 
  54  from MolKit.molecule import Atom, AtomSet, BondSet 
  55  from MolKit.protein import Residue, ResidueSet, Chain 
  56  from MolKit.pdbWriter import PdbqtWriter 
  57  from MolKit.bondSelector import RotatableBondSelector, AmideBondSelector 
  58  from MolKit.bondSelector import GuanidiniumBondSelector, LeafBondSelector 
  59   
  60  from Pmv.guiTools import MoleculeChooser 
  61  import types, string, Tkinter, os, Pmw 
  62  from AutoDockTools.autotorsCommands import MAXTORS, SetRotatableBonds 
  63  from AutoDockTools.atomTypeTools import AutoDock4_AtomTyper 
  64   
  65  from SimpleDialog import SimpleDialog 
  66   
  67  menuText = {} 
  68  menuText['AutoFlexMB'] = 'Flexible Residues' 
  69  menuText['InputMB'] = 'Input' 
  70  menuText['Read Macro'] = 'Open Macromolecule...' 
  71  menuText['Choose Macro'] = 'Choose Macromolecule...' 
  72  menuText['Set Residues'] = 'Choose Torsions in Currently Selected Residues...' 
  73  menuText['Set Hinge'] = 'Set up Hinge...' 
  74  menuText['Edit Hinge'] = 'Edit Hinge...' 
  75  menuText['Step Back'] = 'Redisplay Macromolecule' 
  76  menuText['WriteMB'] = 'Output' 
  77  menuText['writeFlexible'] = 'Save Flexible PDBQT...' 
  78  menuText['writeRigid'] = 'Save Rigid PDBQT...' 
  79  menuText['writeDir'] = 'Save Multiple Flexible PDBQTS...' 
  80   
  81   
  82   
83 -class AF_MacroReader(MVCommand):
84 """ allows user to select a filename for the macromolecule""" 85 86
87 - def onRemoveObjectFromViewer(self, obj):
88 if hasattr(self.vf, 'flexDict'): 89 dict = self.vf.flexDict 90 if dict.has_key('macrofilename'): 91 ok = False 92 macrofilename = dict['macrofilename'] 93 for m in self.vf.Mols: 94 if m.parser.filename==macrofilename: 95 ok = True 96 break 97 if not ok: 98 del dict['macrofilename'] 99 if dict.has_key('macroname') and dict['macroname'] not in self.vf.Mols.name: 100 del dict['macroname'] 101 if dict.has_key('macromol') and dict['macromol']: 102 del dict['macromol']
103 104
105 - def onAddCmdToViewer(self):
106 if not hasattr(self.vf, 'flexDict'): 107 self.vf.flexDict={} 108 if not self.vf.commands.has_key('readPDBQT'): 109 self.vf.loadCommand('fileCommands', 'readPDBQT', 'Pmv')
110 111
112 - def guiCallback(self):
113 """called each time the 'select pdbqt macromolecule' button is pressed""" 114 macroFile = self.vf.askFileOpen(types=[('PDBQT files', '*.pdbqt')], 115 title = 'PDBQT Macromolecule File:') 116 if macroFile: 117 filename=os.path.split(macroFile)[-1] 118 ext = os.path.splitext(filename)[1] 119 if ext!='.pdbqt': 120 msg = 'File can only be PDBQT format' 121 self.warningMsg(msg) 122 return 'ERROR' 123 self.doitWrapper(macroFile)
124 125
126 - def __call__(self, macroFile, **kw):
127 """None<-ADflex_readMacro(macroFile)""" 128 if not macroFile: return 'ERROR' 129 ext = os.path.splitext(macroFile)[1] 130 if ext!='.pdbqt': 131 msg = 'File must be PDBQT format' 132 self.warningMsg(msg) 133 return 'ERROR' 134 apply(self.doitWrapper, (macroFile,), kw)
135 136
137 - def doit(self, macroFile):
138 mollist = self.vf.readPDBQT(macroFile) 139 if not len(mollist): return 'ERROR' 140 mol = mollist[0] 141 mol.allAtoms.used = 0 142 dict = self.vf.flexDict 143 dict['macrofilename'] = macroFile 144 dict['macroname'] = mol.name 145 dict['macromol'] = mol
146 147 148 AF_MacroReaderGUI=CommandGUI() 149 AF_MacroReaderGUI.addMenuCommand('AutoToolsBar', menuText['AutoFlexMB'], \ 150 menuText['Read Macro'], cascadeName = menuText['InputMB']) 151 152 153
154 -class AF_MacroChooser(MVCommand):
155 """ allows user to choose a molecule already present for the macromolecule""" 156 157
158 - def __init__(self, mode='single', title = 'Choose Macromolecule'):
159 MVCommand.__init__(self) 160 self.mode = mode 161 self.title = title
162 163
164 - def onRemoveObjectFromViewer(self, obj):
165 if hasattr(self.vf, 'flexDict'): 166 dict = self.vf.flexDict 167 if dict.has_key('macrofilename'): 168 ok = False 169 macrofilename = dict['macrofilename'] 170 for m in self.vf.Mols: 171 if m.parser.filename==macrofilename: 172 ok = True 173 break 174 if not ok: 175 del dict['macrofilename'] 176 if dict.has_key('macroname') and dict['macroname'] not in self.vf.Mols.name: 177 del dict['macroname'] 178 if dict.has_key('macromol') and dict['macromol']: 179 del dict['macromol']
180 181 182
183 - def chooseMolecule_cb(self, event = None):
184 """called each time the 'choose Molecule' button is pressed""" 185 mols = self.chooser.getMolSet() 186 kw = {'redraw':0} 187 if mols: apply(self.doitWrapper, (mols,), kw) 188 self.chooser.form.withdraw()
189 190
191 - def guiCallback(self):
192 self.chooser = MoleculeChooser(self.vf, self.mode, self.title) 193 self.chooser.ipf.append({'name':'Select Button', 194 'widgetType':Tkinter.Button, 195 'text':'Select Molecule', 196 'wcfg':{'bd':6}, 197 'gridcfg':{'sticky':Tkinter.E+Tkinter.W}, 198 'command': self.chooseMolecule_cb}) 199 self.form = self.chooser.go(modal=0, blocking=0) 200 lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb 201 lb.bind("<Double-Button-1>",self.chooseMolecule_cb)
202 203
204 - def __call__(self, nodes, **kw):
205 """None<-ADflex_chooseMacro(nodes)""" 206 nodes = self.vf.expandNodes(nodes) 207 if not len(nodes): return 'ERROR' 208 apply(self.doitWrapper, (nodes,), kw)
209 210
211 - def doit(self, nodes, **kw):
212 nodes = self.vf.expandNodes(nodes) 213 if not len(nodes): return 'ERROR' 214 mol = nodes[0] 215 mol.allAtoms.used=0 216 #if mol is from a pdbqt file, do not need to add 'q' or 't' 217 filetype = os.path.splitext(os.path.basename(mol.parser.filename))[1] 218 msg = "" 219 chargeMsg = "" 220 typeMsg = "" 221 if filetype!='.pdbqt': 222 #make sure all atoms have charge: 'q' 223 ats = mol.allAtoms.get(lambda x: x.chargeSet==None) 224 if len(ats): 225 mol.buildBondsByDistance() 226 self.vf.computeGasteiger(mol, topCommand=0) 227 chargeMsg = "added gasteiger charges " 228 #make sure that all atoms have autodock_element: 't' 229 ats = mol.allAtoms.get(lambda x: hasattr(x, 'autodock_element')) 230 if len(ats)!= len(mol.allAtoms): 231 ad4_typer = AutoDock4_AtomTyper() 232 mol.buildBondsByDistance() 233 ad4_typer.setAutoDockElements(mol) 234 typeMsg = " added autodock4 atom types " 235 if len(chargeMsg): 236 msg += chargeMsg 237 if len(typeMsg): 238 msg = msg + ' and ' + typeMsg + ' to ' + mol.name 239 elif len(typeMsg): 240 msg = typeMsg + ' to ' + mol.name 241 hs = mol.allAtoms.get(lambda x: x.element=='H' and len(x.bonds)) 242 nphs = hs.get(lambda x: x.bonds[0].atom1.element=='C' or x.bonds[0].atom2.element=='C') 243 if len(nphs): 244 lenNPHS = 0 245 beforeLen = len(mol.allAtoms) 246 if 'automerge_nphs' in kw.keys(): 247 self.vf.mergeNPHSGC(mol.allAtoms) 248 else: 249 nphs_msg="There appear to be some nonpolar hydrogen in "+ mol.name+ " Do you wish to merge them to conform to AutoDock4 atom types? " 250 d = SimpleDialog(self.vf.GUI.ROOT, text=nphs_msg, 251 buttons=['No', 'Yes'], default=1, 252 title="Merge Non-polar Hydrogens?") 253 mergeNPHS = d.go() 254 if mergeNPHS: 255 self.vf.mergeNPHSGC(mol.allAtoms) 256 lenNPHS = beforeLen - len(mol.allAtoms) 257 if lenNPHS: 258 msg = msg + " and merged " + str(lenNPHS) + " non-polar hydrogens" 259 if len(msg): 260 self.warningMsg(msg) 261 dict = self.vf.flexDict 262 dict['macroname'] = mol.name 263 dict['macrofilename'] = mol.parser.filename 264 dict['macromol'] = mol 265 if hasattr(self.vf, 'gpo') and hasattr(self.vf.gpo, 'receptor') and self.vf.gpo.receptor==mol: 266 msg = mol.name + " is currently the 'macromolecule'\nin the Grid menu. Make sure the macromolecule specified in the gpf does not include the flexible residues!!" 267 self.warningMsg(msg)
268 269
270 - def onPick(self,event):
271 listChooser = self.ipf.entryByName['Molecule']['widget'] 272 tkListBox = listChooser.lb 273 atom,geom = self.vf.findPickedAtom(event) 274 if atom: 275 pickedMol = atom.top 276 #then need to make pickedMol the selection in self.lc 277 for i in range(len(listChooser.entries)): 278 listChooserlist=string.split(listChooser.entries[i][0]) 279 if pickedMol.name == listChooserlist[0]: 280 self.pickedMolIndex= i 281 tkListBox.select_clear(0,'end') 282 listChooser.select(i) 283 return 284 t= "error: %s not in mv.Mols" %pickedMol.name 285 self.vf.warningMsg(t)
286 287 288 AF_MacroChooserGUI=CommandGUI() 289 AF_MacroChooserGUI.addMenuCommand('AutoToolsBar', menuText['AutoFlexMB'], 290 menuText['Choose Macro'], cascadeName = menuText['InputMB']) 291 292 293
294 -class AF_SelectResidues(MVCommand):
295 """ allows user to set up a set of residues in macromolecule whose sidechains are to be flexed in an autodock run""" 296 297
298 - def onAddCmdToViewer(self):
299 if not hasattr(self.vf, 'flexDict'): 300 self.vf.flexDict={} 301 if not hasattr(self.vf, 'colorByAtomType'): 302 self.vf.loadCommand('colorCommands', 'colorByAtomType', 'Pmv') 303 self.torscount = 0
304 305
306 - def guiCallback(self):
307 """called each time the 'Set Selected Residues' button is pressed""" 308 if not self.vf.flexDict.has_key('macroname'): 309 t='select protein first' 310 self.vf.warningMsg(t) 311 return 'ERROR' 312 else: macroname=self.vf.flexDict['macroname'] 313 if len(self.vf.selection)==0: 314 msg = "Please select residues to be modelled as flexible first!" 315 self.warningMsg(msg) 316 return 'ERROR' 317 nodes = self.vf.getSelection() 318 nodes = nodes.findType(Residue).uniq() 319 if not len(nodes): 320 t='no current residues selected' 321 self.vf.warningMsg(t) 322 return 'ERROR' 323 #warn if there is there is not a specific subselection 324 mol = nodes[0].top 325 title = "Process ALL residues in %s?" %mol.name 326 if len(nodes)==len(mol.chains.residues): 327 msg="CAUTION: currently processing all the residues in "+mol.name+ " will be very time consuming. Do you wish to continue? " 328 d = SimpleDialog(self.vf.GUI.ROOT, text=msg, 329 buttons=['No', 'Yes'], default=1, 330 title=title) 331 useAll = d.go() 332 if not useAll: 333 return "ERROR" 334 if not nodes.__class__==ResidueSet: 335 self.vf.setIcomLevel(Residue, topCommand=0) 336 nodes = nodes.findType(Residue).uniq() 337 mol = nodes[0].top 338 mol.allAtoms.used=0 339 kw = {'redraw':0} 340 self.torscount = 0 341 apply(self.doitWrapper, (nodes,), kw)
342 343
344 - def __call__(self, nodes=None, **kw):
345 nodes = self.vf.expandNodes(nodes) 346 if not len(nodes): return "ERROR" 347 if nodes.__class__ != ResidueSet: 348 nodes = nodes.findType(Residue).uniq() 349 apply(self.doitWrapper, (nodes,), kw)
350 351
352 - def doit(self, nodes):
353 flex_residues = self.vf.expandNodes(nodes) 354 if not len(flex_residues): return 'ERROR' 355 356 #remove all prolines 357 proList = ResidueSet(filter(lambda x: x.type=='PRO', flex_residues)) 358 if proList: 359 flex_residues = flex_residues - proList 360 361 #remove all waters 362 h20List = ResidueSet(filter(lambda x: x.type=='HOH', flex_residues)) 363 if h20List: 364 flex_residues = flex_residues - h20List 365 366 if not len(flex_residues): 367 t='No non-water and non-proline Residues selected!' 368 self.vf.warningMsg(t) 369 return 'ERROR' 370 371 map(self.setAutoFlexFields, flex_residues) 372 #map(self.setSideChain, flex_residues) 373 #map(self.setTorsionFields,flex_residues) 374 #for item in flex_residues: 375 # self.setTorsionFields(item) 376 #map(self.getAmideBonds,flex_residues) 377 #remove any residues with no possible torsions 378 flexList = filter(lambda x: x.torscount!=0, flex_residues) 379 flexList = ResidueSet(flexList) 380 if not len(flexList): 381 t='Current Selected Residues have no active torsions!' 382 self.vf.warningMsg(t) 383 return 'ERROR' 384 self.torscount = Numeric.add.reduce(flexList.torscount) 385 mol = flex_residues[0].top 386 allResidues = mol.findType(Residue) 387 rigidResidues = allResidues-flex_residues 388 dict = self.vf.flexDict 389 dict['flex_residues'] = flex_residues 390 dict['flex_residues_number'] = len(flex_residues) 391 dict['rigidResidues'] = rigidResidues 392 self.vf.ADflex_processResidues.guiCallback()
393 394
395 - def setAutoFlexFields(self, res):
396 #process residues 397 if hasattr(res, 'setup'): 398 return 399 res.setup = 1 400 res.atoms.used = 0 401 res.atoms.bonds[0].possibleTors = 0 402 res.atoms.bonds[0].activeTors = 0 403 backbone_names = ['C','N','O','HN','HN1','HN2', 'HA', 404 'H1','H2','H3','HO', 'H'] 405 #includes CA 406 sidechain = res.atoms.get(lambda x: x.name not in backbone_names) 407 res.sideChain = sidechain 408 bondlist = res.bondlist = sidechain.bonds[0] 409 bondlist.leaf = 0 410 bondlist.possibleTors = 0 411 bondlist.activeTors = 0 412 rbs = RotatableBondSelector() 413 rotatables = rbs.select(bondlist) 414 for b in rotatables: 415 b.possibleTors = 1 416 b.activeTors = 1 417 amides = AmideBondSelector().select(bondlist) 418 for b in amides: 419 b.activeTors = 0 420 b.possibleTors = 1 421 guanidiniums = GuanidiniumBondSelector().select(bondlist) 422 for b in guanidiniums: 423 b.activeTors = 0 424 b.possibleTors = 1 425 leaves = LeafBondSelector().select(bondlist) 426 for b in leaves: 427 b.activeTors = 0 428 b.possibleTors = 0 429 res.torscount = len(bondlist.get(lambda x: x.activeTors==1)) 430 #this field is not used in AutoDock4 431 res.torsdof = res.torscount 432 res.torscount = len(bondlist.get(lambda x: x.activeTors==1)) 433 res.torsdof = res.torscount 434 435 caAtoms = res.atoms.get(lambda x: x.name=='CA') 436 #get returns an AtomSet 437 if caAtoms: #this checks for len(caAtoms) 438 res.rootlist = caAtoms 439 elif self.vf.hasGui: 440 #use inputForm to get root atom and atoms for flexible part 441 rootname = Tkinter.StringVar() 442 if hasattr(res, 'rootlist'): 443 rootname.set(res.rootlist[0].name) 444 else: 445 at0 = res.atoms.get(lambda x: x._uniqIndex==0)[0] 446 rootname.set(at0.name) 447 s = 'Set Root Atom for ' + res.name 448 ifd = InputFormDescr(title=s) 449 ifd.append({'name':'sideChainLC', 450 'widgetType': 'ListChooser', 451 'mode': 'single', 452 'entries':res.atoms.name, 453 'title': 'Select Root Atom', 454 'lbwcfg':{'height':20,'selectforeground':'red','exportselection':0}, 455 'gridcfg':{'sticky':Tkinter.W +Tkinter.E}}), 456 vals= self.vf.getUserInput(ifd, modal=1, blocking=1) 457 if vals: 458 try: 459 atList = vals['sideChainLC'] 460 res.rootlist = res.atoms.get(lambda x, atList=atList: x.name==atList[0]) 461 res.sideChain = res.atoms 462 except: 463 msg = 'rootatom not in res, using defaults' 464 self.vf.warningMsg(msg) 465 res.rootlist = AtomSet([res.atoms.get(lambda x: x._uniqIndex == 0)[0]]) 466 res.sideChain = res.atoms 467 else: 468 msg = 'rootatom not in res, using defaults' 469 self.vf.warningMsg(msg) 470 res.rootlist = AtomSet([res.atoms.get(lambda x: x._uniqIndex == 0)[0]]) 471 res.sideChain = res.atoms 472 473 else: 474 res.rootlist = AtomSet([res.atoms.get(lambda x: x._uniqIndex == 0)[0]]) 475 res.sideChain = res.atoms
476 477 478 AF_SelectResiduesGUI = CommandGUI() 479 AF_SelectResiduesGUI.addMenuCommand('AutoToolsBar', menuText['AutoFlexMB'],menuText['Set Residues']) 480 481 482
483 -class AF_ProcessResidues(SetRotatableBonds, MVBondICOM):
484 """ allows user to process interactively a set of residues in macromolecule whose sidechains are to be flexed in an autodock run""" 485 486
487 - def __init__(self, func=None):
488 SetRotatableBonds.__init__(self) 489 MVBondICOM.__init__(self) 490 self.save = None 491 self.guiUp = 0 492 self.pickLevel = 'parts'
493 494
495 - def onAddCmdToViewer(self):
496 if not hasattr(self.vf, 'flexDict'): 497 self.vf.flexDict = {} 498 if not hasattr(self.vf, 'colorByAtomType'): 499 self.vf.loadCommand('colorCommands', 'colorByAtomType', 'Pmv') 500 if not hasattr(self.vf, 'setICOM'): 501 self.vf.loadCommand('interactiveCommands', 'setICOM', 'Pmv') 502 if self.vf.hasGui and not self.torsStr: 503 self.torsStr = Tkinter.StringVar()
504 505
506 - def guiCallback(self):
507 """called INDIRECTLY each time the 'Choose Torsions in Currently Selected Residues...' button is pressed""" 508 if not self.vf.flexDict.has_key('flex_residues'): 509 t='select residues first' 510 self.vf.warningMsg(t) 511 return 'ERROR' 512 nodes = self.vf.flexDict['flex_residues'] 513 self.mol = nodes[0].top 514 if not len(nodes): 515 t='no residues selected' 516 self.vf.warningMsg(t) 517 return 'ERROR' 518 if not nodes.__class__==ResidueSet: 519 t='selection must be of type ResidueSet' 520 self.vf.warningMsg(t) 521 return 'ERROR' 522 self.changeFlexResCt(0) 523 if not hasattr(self, 'ifd'): 524 self.torsStr= Tkinter.StringVar() 525 s = 'Number of rotatable bonds ='+str(0)+ ' / '+str(MAXTORS)+'\n' 526 self.torsStr.set(s) 527 self.renameAromatic= Tkinter.IntVar() 528 infoStr = 'Pick or drag-&-pick bonds. \nGreen = rotatable, \nMagenta = non-rotatable, \nRed = unrotatable.\n\n' 529 ifd = self.ifd=InputFormDescr(title='Torsion Count') 530 ifd.append({'name': 'maxTorsLab', 531 'widgetType':Tkinter.Label, 532 'wcfg':{'text':infoStr}, 533 'gridcfg':{'sticky':Tkinter.W + Tkinter.E}}), 534 ifd.append({'name':'torsEntryLab', 535 'widgetType':Tkinter.Label, 536 'wcfg':{'textvariable':self.torsStr}, 537 'gridcfg':{'sticky':Tkinter.W +Tkinter.E}}), 538 ifd.append({'name': 'noAmideBut', 539 'widgetType':Tkinter.Checkbutton, 540 'wcfg':{'text':'amide torsions are allowed', 541 #'activebackground':'white', 542 'selectcolor':'white', 543 'indicatoron':0, 544 'command':self.setNoAmideTors_cb}, 545 'gridcfg':{'sticky':Tkinter.W+Tkinter.E, 'columnspan':2}}), 546 ifd.append({'name': 'closeBut', 547 'widgetType':Tkinter.Button, 548 'wcfg':{'text':'Close','command':self.close_cb}, 549 'gridcfg':{'sticky':Tkinter.W+Tkinter.E, 'columnspan':2}}) 550 self.form= self.vf.getUserInput(self.ifd, modal=0, blocking=0) 551 else: 552 if hasattr(self,'form'): 553 self.form.root.deiconify() 554 ## !@@! Is THIS APPROPRIATE?!?!? 555 if hasattr(self.vf.ADflex_setResidues,'torscount'): 556 self.torscount = self.vf.ADflex_setResidues.torscount 557 else: 558 self.torscount = 0 559 self.currentNodes=nodes.sideChain 560 self.vf.displayLines(self.currentNodes, topCommand=0) 561 self.vf.displayLines(self.currentNodes, only=1, topCommand=0, redraw=1) 562 pTbndset = self.currentNodes.bonds[0].get(lambda x:x.activeTors==1) 563 pTatomset = (pTbndset.atom1 + pTbndset.atom2).uniq() 564 if len(pTatomset): 565 geom = self.mol.geomContainer.geoms['AtomLabels'] 566 geom.Set(billboard=True, fontStyle='solid', fontScales=(.3,.3,.3,)) 567 self.vf.labelByProperty(pTatomset, ('name', ), topCommand=0,location='Last', redraw=1) 568 self.buildCol(self.mol, self.torscount) 569 self.pTatomset = pTatomset 570 self.save = self.vf.ICmdCaller.commands.value[None] 571 self.vf.setICOM(self, topCommand = 0) 572 self.vf.setIcomLevel( Atom ) 573 self.vf.flexDict['torscount'] = self.torscount
574 #need to set up display by torsion activity here 575 576
577 - def close_cb(self, event=None):
578 #at this point, remove any residues which have no active torsions left 579 dict = self.vf.flexDict 580 flex_residues = dict['flex_residues'] 581 badList = [] 582 for item in flex_residues: 583 if not hasattr(item,'torscount'): 584 badList.append(item) 585 if not item.torscount: 586 print "eliminating", item.name 587 badList.append(item) 588 badSet = ResidueSet(badList) 589 flex_residues = flex_residues - badSet 590 dict['flex_residues'] = flex_residues 591 dict['rigidResidues'] = dict['rigidResidues']+badSet 592 dict['flex_residues_number'] = len(flex_residues) 593 if len(badSet): 594 badAtoms = badSet.atoms 595 self.currentNodes = self.currentNodes-badAtoms 596 self.changeFlexResCt(0) 597 self.vf.displayLines(self.currentNodes, only=1) 598 self.vf.colorByAtomType(self.currentNodes) 599 self.vf.labelByProperty(self.pTatomset, ('name', ), negate=True, topCommand=0, redraw=1) 600 self.pTatomset = AtomSet() 601 #set the PCOM to something else 602 self.vf.setICOM(self.save, topCommand = 0) 603 self.vf.GUI.VIEWER.Redraw() 604 self.form.root.withdraw() 605 self.save = None
606 607
608 - def setNoAmideTors_cb(self, event=None, log=1, redraw=0):
609 self.setNoAmideTors() 610 self.buildCol(self.mol, self.torscount)
611 612
613 - def setNoAmideTors(self, log=0):
614 self.vf.flexDict['noAmides']=self.hasAmide 615 if self.hasAmide: 616 self.hasAmide = 0 617 self.turnOffAmides() 618 self.ifd.entryByName['noAmideBut']['widget'].config(text='amide torsions are not allowed') 619 else: 620 self.hasAmide = 1 621 self.turnOnAmides() 622 self.ifd.entryByName['noAmideBut']['widget'].config(text='amide torsions are allowed')
623 624
625 - def turnOffAmides(self):
626 map(self.turnOffAmide, self.vf.flexDict['flex_residues'])
627 628
629 - def turnOnAmides(self):
630 map(self.turnOnAmide, self.vf.flexDict['flex_residues'])
631 632
633 - def turnOnAmide(self, res):
634 if not hasattr(res, 'amidebonds'): 635 return 636 for item in res.amidebonds: 637 #only turn on the ones which were turned off 638 if item.possibleTors and not item.activeTors: 639 item.activeTors = 1 640 self.torscount = self.torscount + 1
641 642
643 - def turnOffAmide(self, res):
644 if not hasattr(res, 'amidebonds'): 645 return 646 for item in res.amidebonds: 647 #only turn off the ones which were turned on 648 if item.possibleTors and item.activeTors: 649 item.activeTors = 0 650 self.torscount = self.torscount - 1
651 652
653 - def buildCol(self, mol, torscount):
654 #process residues 655 s = 'Number of rotatable bonds ='+str(torscount) + ' / '+str(MAXTORS)+'\n' 656 self.torsStr.set(s) 657 currentbonds=mol.geomContainer.atoms['bonded'].bonds[0] 658 col = [] 659 for b in currentbonds: 660 if b.possibleTors: 661 if b.activeTors: col.append((0,1,0)) 662 else: col.append((1,0,1)) 663 else: 664 col.append((1,0,0)) 665 mol.geomContainer.geoms['bonded'].Set(materials=col, 666 inheritMaterial=False, 667 matBind=viewerConst.PER_PART) 668 self.vf.GUI.VIEWER.Redraw()
669 670
671 - def changeFlexResCt(self,delta):
672 n=self.vf.flexDict['flex_residues_number'] 673 n=n+delta 674 self.vf.flexDict['flex_residues_number']=n 675 msg = 'current %d flexible residues'%n 676 self.vf.GUI.pickLabel.configure(text=msg)
677 678
679 - def checkAromatic_cb(self, event=None):
680 if self.renameAromatic.get(): 681 self.ifd.entryByName['checkAromBut']['widget'].config(text='aromatic carbons named A..') 682 map(self.nameA,self.vf.flexDict['flex_residues']) 683 else: 684 self.ifd.entryByName['checkAromBut']['widget'].config(text='aromatic carbons named C..') 685 map(self.renameC,self.vf.flexDict['flex_residues'])
686 687
688 - def nameA(self, res):
689 print 'changing the names of aromatic carbons is no longer supported' 690 return
691 692
693 - def renameC(self,res):
694 print 'changing the names of aromatic carbons is no longer supported' 695 return
696 697
698 - def __call__(self, bonds, **kw):
699 kw['topCommand'] = 0 700 kw['busyIdle'] = 1 701 kw['log'] = 0 702 #self.setUpDisplay() 703 apply(self.doitWrapper, (bonds,), kw)
704 705
706 - def doit(self, bonds):
707 if not self.currentNodes: 708 msg='No residues currently processed' 709 self.vf.warningMsg(msg) 710 return 'ERROR' 711 for bond in bonds: 712 if not bond.possibleTors: continue 713 atoms = AtomSet([bond.atom1, bond.atom2]) 714 self.vf.ADflex_setBondRotatableFlag(atoms, not bond.activeTors, 715 topCommand = 0, redraw = 1, log =1, setupUndo = 1)
716 717
718 - def stop(self):
719 self.done_cb()
720 721
722 - def getObjects(self,pick):
723 flexMol = self.vf.flexDict['flex_residues'].top.uniq()[0] 724 flexMolGeom = flexMol.geomContainer.geoms['bonded'] 725 for o, val in pick.hits.items(): #loop over geometries 726 primInd = map(lambda x: x[0], val) 727 if o != flexMolGeom: continue 728 else: g = o.mol.geomContainer 729 if g.geomPickToBonds.has_key(o.name): 730 func = g.geomPickToBonds[o.name] 731 if func: return func(o, primInd) 732 else: 733 l = [] 734 bonds = g.atoms[o.name].bonds[0] 735 for i in range(len(primInd)): 736 l.append(bonds[int(primInd[i])]) 737 return BondSet(l)
738 739
740 - def done_cb(self):
741 self.guiUp = 0 742 if self.form: self.form.withdraw() 743 self.vf.colorByAtomType(self.vf.flexDict['flex_residues'], 744 topCommand=0, redraw=1)
745 746
747 - def dismiss(self):
748 self.vf.setICOM(self.save, topCommand=0) 749 self.save = None 750 self.done_cb()
751 752 753 AF_ProcessResiduesGUI = CommandGUI() 754 755 756
757 -class AF_ProcessHingeResidues(SetRotatableBonds, MVBondICOM):
758 """ allows user to process interactively a set of hinge residues in macromolecule whose sidechains are to be flexed in an autodock run""" 759 760
761 - def __init__(self, func=None):
762 SetRotatableBonds.__init__(self) 763 MVBondICOM.__init__(self) 764 self.save = None 765 self.guiUp = 0 766 self.pickLevel = 'parts'
767 768
769 - def onAddCmdToViewer(self):
770 if not hasattr(self.vf, 'flexDict'): 771 self.vf.flexDict = {} 772 if not hasattr(self.vf, 'colorByAtomType'): 773 self.vf.loadCommand('colorCommands', 'colorByAtomType', 'Pmv') 774 if not hasattr(self.vf, 'setICOM'): 775 self.vf.loadCommand('interactiveCommands', 'setICOM', 'Pmv') 776 if self.vf.hasGui and not self.torsStr: 777 self.torsStr = Tkinter.StringVar()
778 779
780 - def setAutoFlexFieldsHinge(self, res, atomOne, atomTwo, atoms):
781 if hasattr(res, 'processed'): 782 print res.full_name(), ' already has autoflexFields' 783 return 784 #PROCESS HINGE RESIDUES 785 #backbone_names = ['CA', 'C','N','O','HN','HN1','HN2', 'HA', 786 backbone_names = ['C','N','O','HN','HN1','HN2', 'HA', 787 'H1','H2','H3','HO', 'H'] 788 #only process the sidechains of atoms which are designated to be moved by hinge 789 #resatoms = res.atoms - AtomSet([atomOne, atomTwo]) 790 resatoms = res.atoms.get(lambda x: x in atoms) 791 sidechain = resatoms.get(lambda x: x.name not in backbone_names) 792 res.sideChain = sidechain 793 bondlist = res.bondlist = sidechain.bonds[0] 794 bondlist.leaf = 0 795 rbs = RotatableBondSelector() 796 rotatables = rbs.select(bondlist) 797 for b in rotatables: 798 b.possibleTors = 1 799 b.activeTors = 1 800 amides = AmideBondSelector().select(bondlist) 801 for b in amides: 802 b.activeTors = 0 803 b.possibleTors = 1 804 guanidiniums = GuanidiniumBondSelector().select(bondlist) 805 for b in guanidiniums: 806 b.activeTors = 0 807 b.possibleTors = 1 808 leaves = LeafBondSelector().select(bondlist) 809 for b in leaves: 810 b.activeTors = 0 811 b.possibleTors = 0 812 res.torscount = len(bondlist.get(lambda x: x.activeTors==1)) 813 #this field is not used in AutoDock4 814 res.torsdof = res.torscount 815 #res.rootlist = AtomSet([resatoms[0]]) ??is this necessary? 816 #res.rootlist = AtomSet([resatoms.get(lambda x: x._uniqIndex == 0)[0]]) 817 res.processed = True
818 819
820 - def changeHingeFlexResCt(self, delta):
821 n = self.vf.flexDict.get('flex_residues_number',0) 822 n = n + delta 823 self.vf.flexDict['flex_residues_number'] = n 824 msg = 'current %d flexible residues'%n 825 self.vf.GUI.pickLabel.configure(text=msg)
826 827
828 - def guiCallback(self):
829 """called INDIRECTLY each time the 'Set Selected Residues' button is pressed""" 830 if not self.vf.flexDict.has_key('hinge_list'): 831 t='set hinge first' 832 self.vf.warningMsg(t) 833 return 'ERROR' 834 h_list = self.vf.flexDict['hinge_list'] 835 if not len(h_list): 836 t='currently hinge list is empty!' 837 self.vf.warningMsg(t) 838 return 'ERROR' 839 if not hasattr(self, 'hinge'): 840 self.hinge_to_process = self.vf.flexDict['hinge_list'][-1] 841 hinge = self.hinge_to_process 842 (atomOne,atomTwo), atoms = hinge 843 self.mol = atoms[0].top 844 #self.mol.allAtoms.bonds[0].possibleTors = 0 845 #self.mol.allAtoms.bonds[0].activeTors = 0 846 if not len(atoms): 847 t='no hinge atoms specified' 848 self.vf.warningMsg(t) 849 return 'ERROR' 850 self.currentNodes = atoms 851 hinge_resSet = atoms.parent.uniq() 852 for res in hinge_resSet: 853 self.setAutoFlexFieldsHinge(res, atomOne, atomTwo, atoms) 854 self.torscount = Numeric.add.reduce(hinge_resSet.torscount) 855 self.changeHingeFlexResCt(len(hinge_resSet)) 856 if not hasattr(self, 'ifdX'): 857 self.torsStr= Tkinter.StringVar() 858 s = 'Number of rotatable bonds ='+str(0)+ ' / '+str(MAXTORS)+'\n' 859 self.torsStr.set(s) 860 self.renameAromatic= Tkinter.IntVar() 861 infoStr = 'Pick or drag-&-pick bonds. \nGreen = rotatable, \nMagenta = non-rotatable, \nRed = unrotatable.\n\n' 862 ifdX = self.ifdX=InputFormDescr(title='Torsion Count') 863 ifdX.append({'name': 'maxTorsLab', 864 'widgetType':Tkinter.Label, 865 'wcfg':{'text':infoStr}, 866 'gridcfg':{'sticky':Tkinter.W + Tkinter.E}}), 867 ifdX.append({'name':'torsEntryLab', 868 'widgetType':Tkinter.Label, 869 'wcfg':{'textvariable':self.torsStr}, 870 'gridcfg':{'sticky':Tkinter.W +Tkinter.E}}), 871 ifdX.append({'name': 'closeBut', 872 'widgetType':Tkinter.Button, 873 'wcfg':{'text':'Close','command':self.closeX_cb}, 874 'gridcfg':{'sticky':Tkinter.W+Tkinter.E, 'columnspan':2}}) 875 self.formX= self.vf.getUserInput(self.ifdX, modal=0, blocking=0) 876 else: 877 if hasattr(self,'formX'): 878 self.formX.root.deiconify() 879 self.save = self.vf.ICmdCaller.commands.value[None] 880 self.vf.setICOM(self, topCommand = 0) 881 self.vf.setIcomLevel( Atom ) 882 #### #need to set up display by torsion activity here 883 #could have preexisting flexible residues... or not 884 self.vf.flexDict.setdefault('torscount', 0) 885 if 'flex_residues' in self.vf.flexDict.keys() and \ 886 len(self.vf.flexDict['flex_residues']): 887 self.vf.flexDict['torscount'] += self.torscount 888 else: 889 self.vf.flexDict['torscount'] = self.torscount 890 self.vf.displayLines(self.currentNodes, only=1, topCommand=0, redraw=1) 891 self.buildCol(self.mol, self.torscount)
892 893
894 - def closeX_cb(self, event=None):
895 dict = self.vf.flexDict 896 self.vf.displayLines(self.currentNodes, only=1) 897 self.vf.colorByAtomType(self.currentNodes) 898 self.vf.GUI.VIEWER.Redraw() 899 self.formX.root.withdraw() 900 self.vf.flexDict.setdefault('torscount', 0) 901 #this is dangerous 902 #!@@! fix this: what if two hinges... or if remove one... or all 903 flex_residues_torscount = 0 904 if hasattr(self.vf.ADflex_setResidues, 'torscount') and \ 905 self.vf.ADflex_setResidues.torscount>0: 906 flex_residues_torscount = self.vf.ADflex_setResidues.torscount 907 self.vf.flexDict['torscount'] = self.torscount + flex_residues_torscount 908 self.vf.setICOM(self.save, topCommand = 0) 909 self.save = None 910 self.dismiss()
911 912
913 - def buildCol(self, mol, torscount):
914 #process hinge 915 s = 'Number of rotatable bonds ='+str(torscount) + ' / '+str(MAXTORS)+'\n' 916 self.torsStr.set(s) 917 currentbonds = mol.geomContainer.atoms['bonded'].bonds[0] 918 col = [] 919 for b in currentbonds: 920 if hasattr(b, 'possibleTors') and b.possibleTors: 921 if hasattr(b, 'activeTors') and b.activeTors: col.append((0,1,0)) 922 else: col.append((1,0,1)) 923 else: 924 col.append((1,0,0)) 925 mol.geomContainer.geoms['bonded'].Set(materials=col, 926 inheritMaterial=False, 927 matBind=viewerConst.PER_PART) 928 self.vf.GUI.VIEWER.Redraw()
929 930
931 - def changeFlexResCt(self, delta):
932 self.vf.flexDict.setdefault('flex_residues_number',0) 933 n = self.vf.flexDict['flex_residues_number'] 934 n = n + delta 935 self.vf.flexDict['flex_residues_number'] = n 936 msg = 'current %d flexible residues'%n 937 self.vf.GUI.pickLabel.configure(text=msg)
938 939
940 - def __call__(self, bonds, **kw):
941 kw['topCommand'] = 0 942 kw['busyIdle'] = 1 943 kw['log'] = 0 944 #kw['flexRes'] = False 945 #self.setUpDisplay() 946 apply(self.doitWrapper, (bonds,), kw)
947 948
949 - def doit(self, bonds, **kw):
950 if not self.currentNodes: 951 msg='No residues currently processed' 952 self.vf.warningMsg(msg) 953 return 'ERROR' 954 for bond in bonds: 955 if not bond.possibleTors: 956 continue 957 atoms = AtomSet([bond.atom1, bond.atom2]) 958 self.vf.ADflex_setBondRotatableFlag(atoms, not bond.activeTors, 959 topCommand = 0, redraw = 1, log =1, setupUndo = 1, 960 flexRes=True)
961 962
963 - def stop(self):
964 self.done_cb()
965 966
967 - def getObjects(self,pick):
968 flexMol = self.mol 969 flexMolGeom = flexMol.geomContainer.geoms['bonded'] 970 for o, val in pick.hits.items(): #loop over geometries 971 primInd = map(lambda x: x[0], val) 972 if o != flexMolGeom: continue 973 else: g = o.mol.geomContainer 974 if g.geomPickToBonds.has_key(o.name): 975 func = g.geomPickToBonds[o.name] 976 if func: return func(o, primInd) 977 else: 978 l = [] 979 bonds = g.atoms[o.name].bonds[0] 980 for i in range(len(primInd)): 981 l.append(bonds[int(primInd[i])]) 982 return BondSet(l)
983 984
985 - def done_cb(self):
986 self.guiUp = 0 987 if self.form: self.form.withdraw() 988 #self.vf.ADflex_setHinge.spheres.visible=False 989 self.vf.GUI.VIEWER.Redraw()
990 991
992 - def dismiss(self):
993 self.vf.setICOM(self.save, topCommand=0) 994 self.save = None 995 self.done_cb()
996 997 AF_ProcessHingeResiduesGUI = CommandGUI() 998 999 1000
1001 -class AF_EditHinge(MVCommand, MVAtomICOM):
1002 """ allows user to remove atoms to be moved from a hinge interactively""" 1003 1004
1005 - def __init__(self, func=None):
1006 MVCommand.__init__(self, func) 1007 MVAtomICOM.__init__(self) 1008 self.save = None 1009 self.mode = None 1010 self.atomList = AtomSet([])
1011 #self.undoAtList = AtomSet([]) 1012 1013
1014 - def onAddCmdToViewer(self):
1015 if not hasattr(self.vf, 'flexDict'): 1016 self.vf.flexDict = {} 1017 if not hasattr(self.vf, 'colorByAtomType'): 1018 self.vf.loadCommand('colorCommands', 'colorByAtomType', 'Pmv') 1019 if not hasattr(self.vf, 'setICOM'): 1020 self.vf.loadCommand('interactiveCommands', 'setICOM', 'Pmv') 1021 if not hasattr(self.vf, 'ADflex_setHinge'): 1022 self.vf.loadCommand('autoflexCommands', 'ADflex_setHinge', 'AutoDockTools') 1023 if self.vf.hasGui: 1024 self.mode = Tkinter.StringVar()
1025 1026
1027 - def continuousUpdate_cb(self, name, oldval, newval):
1028 if newval == 'yes': 1029 self.continuousUpdate = 1 1030 for event in ['<B2-Motion>', '<B3-Motion>', '<Shift-B3-Motion>']: 1031 self.vf.GUI.addCameraCallback(event, self.update_cb) 1032 else: 1033 self.continuousUpdate = 0 1034 for event in ['<B2-Motion>', '<B3-Motion>', '<Shift-B3-Motion>']: 1035 self.vf.GUI.removeCameraCallback(event, self.update_cb)
1036 1037
1038 - def update_cb(self, event=None):
1039 #print "in update_cb" 1040 self.update()
1041 1042
1043 - def update(self, forward=1, event=None):
1044 #print 'in update: self.atomList=', self.atomList 1045 if not len(self.atomList): 1046 print 'Currently no atoms: resetting geoms' 1047 return 1048 for at in self.atomList: 1049 c1 = self.getTransformedCoords(at) 1050 self.vf.ADflex_setHinge.lineVertices.append(tuple(c1)) 1051 self.vf.ADflex_setHinge.update()
1052 1053
1054 - def guiCallback(self):
1055 """ """ 1056 if not hasattr(self,'form'): 1057 ifd = self.ifd = InputFormDescr(title="Edit Atoms to be moved by current Hinge by:") 1058 #ifd.append({'name': 'testLab', 1059 # 'widgetType':Tkinter.Label, 1060 # 'wcfg':{'text':'Mode:'}, 1061 # 'gridcfg':{'columnspan':3,'sticky':'w'}}) 1062 ifd.append({'widgetType':Tkinter.Radiobutton, 1063 'wcfg':{'text':'adding Atoms', 1064 'variable':self.mode, 1065 'value': 'add'}, 1066 'gridcfg':{'sticky':'we'}}) 1067 ifd.append({'widgetType':Tkinter.Radiobutton, 1068 'wcfg':{'text':'removing Atoms', 1069 'variable':self.mode, 1070 'value': 'remove'}, 1071 'gridcfg':{'row':-1,'sticky':'we'}}) 1072 #ifd.append({'widgetType':Tkinter.Button, 1073 # 'wcfg':{'text':'Close', 'command':self.close_cb}, 1074 # 'gridcfg':{'sticky':'we', 'columnspan':2}}) 1075 self.form = self.vf.getUserInput(ifd, modal=0, blocking=0) 1076 self.form.root.protocol('WM_DELETE_WINDOW',self.close_cb) 1077 else: 1078 self.form.root.deiconify() 1079 self.save = self.vf.ICmdCaller.commands.value[None] 1080 self.vf.setICOM(self)
1081 1082
1083 - def close_cb(self, event=None):
1084 #at this point, just cleanup 1085 self.stop() 1086 self.form.withdraw() 1087 self.vf.GUI.VIEWER.Redraw() 1088 self.mode.set("") 1089 #update hinge_atoms and non_hinge_atoms here? 1090 flexDict = self.vf.flexDict 1091 all = 'all_hinge_atoms' 1092 opp = 'non_hinge_atoms' 1093 #print 'before call to getAllHingeAtoms, ha=', len(flexDict[all]), 1094 #print 'nha=', len(flexDict[opp]), 1095 flexDict = self.vf.flexDict 1096 flexDict[all], flexDict[opp] = self.vf.ADflex_setHinge.getAllHingeAtoms()
1097 #print '2:after call to getAllHingeAtoms, ha=', len(flexDict.get(all,[])), 1098 #print '2:nha=', len(flexDict.get(opp, [])) 1099 1100 1101
1102 - def doit(self, atoms):
1103 if not hasattr(self.vf, 'flexDict'): 1104 self.warningMsg('no flexDIct!') 1105 return "ERROR" 1106 dict = self.vf.flexDict 1107 if not 'hinge_list' in dict.keys(): 1108 self.warningMsg('no hinge_list in flexDict!') 1109 return "ERROR" 1110 hinges = self.vf.flexDict['hinge_list'] 1111 if not len(hinges): 1112 self.warningMsg('current hinges in hinge_list !') 1113 return "ERROR" 1114 if len(hinges): 1115 current_hinge = hinges[-1] 1116 if not len(current_hinge)==2: 1117 self.warningMsg('last hinge in hinge_list is ill-formed!') 1118 return 'ERROR' 1119 atoms_to_move = current_hinge[1] 1120 if not len(atoms_to_move): 1121 self.warningMsg("no atoms to move in current hinge!") 1122 return "ERROR" 1123 if self.mode.get()=='remove': 1124 new_atoms_to_move = atoms_to_move - atoms 1125 #remember to put these atoms into rigid 1126 else: 1127 new_atoms_to_move = atoms_to_move + atoms 1128 #remember to remove these atoms from rigid 1129 #print 'setting atoms to move to ', new_atoms_to_move 1130 new_ats = new_atoms_to_move.uniq() 1131 self.vf.flexDict['hinge_list'][-1][1] = new_ats 1132 self.vf.ADflex_setHinge.atoms = new_ats 1133 if self.vf.hasGui: 1134 self.vf.ADflex_setHinge.hingeAtoms.Set(vertices = new_ats.coords) 1135 self.vf.ADflex_setHinge.hingeAtoms.visible = 1 1136 self.vf.GUI.VIEWER.Redraw()
1137 1138
1139 - def startICOM(self):
1140 self.vf.setIcomLevel( Atom )
1141 1142
1143 - def dismiss(self):
1144 self.vf.setICOM(self.save, topCommand=0) 1145 self.save = None 1146 self.vf.GUI.VIEWER.Redraw() 1147 self.done_cb()
1148
1149 - def stop(self):
1150 self.dismiss()
1151
1152 - def done_cb(self):
1153 self.guiUp = 0 1154 if self.form: self.form.withdraw()
1155 1156 1157 1158 AF_EditHingeGUI = CommandGUI() 1159 AF_EditHingeGUI.addMenuCommand('AutoToolsBar', menuText['AutoFlexMB'],\ 1160 menuText['Edit Hinge']) 1161 1162 1163 1164
1165 -class AF_SetHinge(MVCommand, MVAtomICOM):
1166 """ allows user to setup a hinge interactively to be flexed in an autodock run""" 1167 1168
1169 - def __init__(self, func=None):
1170 MVCommand.__init__(self, func) 1171 MVAtomICOM.