Package Pmv :: Module msmsCommands
[hide private]
[frames] | no frames]

Source Code for Module Pmv.msmsCommands

   1  ############################################################################# 
   2  # 
   3  # Author: Michel F. SANNER 
   4  # 
   5  # Copyright: M. Sanner TSRI 2000 
   6  # 
   7  ############################################################################# 
   8   
   9  # 
  10  # $Header: /opt/cvs/python/packages/share1.5/Pmv/msmsCommands.py,v 1.116.2.1 2007/07/25 20:19:02 vareille Exp $ 
  11  #  
  12  # $Id: msmsCommands.py,v 1.116.2.1 2007/07/25 20:19:02 vareille Exp $ 
  13  # 
  14   
  15  import types, os 
  16  import Tkinter, Pmw 
  17  from math import sqrt 
  18   
  19  from MolKit.tree import TreeNode, TreeNodeSet 
  20  from MolKit.molecule import Molecule, Atom 
  21  from MolKit.protein import Residue 
  22   
  23  from ViewerFramework.VFCommand import CommandGUI 
  24  ##  from ViewerFramework.gui import InputFormDescr 
  25  from mglutil.gui.InputForm.Tk.gui import InputFormDescr 
  26   
  27  from mglutil.gui.BasicWidgets.Tk.customizedWidgets import ListChooser, \ 
  28       ExtendedSliderWidget, SaveButton, LoadButton 
  29  from mglutil.gui.BasicWidgets.Tk.thumbwheel import ThumbWheel      
  30  from mglutil.gui.BasicWidgets.Tk.Dial import Dial 
  31   
  32  from DejaVu.IndexedPolygons import IndexedPolygons 
  33   
  34  from Pmv.displayCommands import DisplayCommand 
  35  from Pmv.mvCommand import MVCommand, MVAtomICOM 
  36  from Pmv.msmsParser import MSMSParser 
  37  from Pmv.guiTools import AugmentedMoleculeChooser 
  38   
  39  import Pmv 
  40  if hasattr( Pmv, 'numOfSelectedVerticesToSelectTriangle') is False: 
  41      Pmv.numOfSelectedVerticesToSelectTriangle = 1 
  42   
  43      print "LALALALA" 
  44      Pmv.vf.userpref.add('sharpColorBoundariesForMsms', 'yes', ('yes','no'), 
  45                    doc="""specifie color boundaries for msms surface (blur or sharp)""", 
  46                   ) 
  47   
  48   
49 -class ReadMSMS(MVCommand):
50 """Command reads .face and .vert file, creates the msms surface and links it to the selection if can\n 51 Package : Pmv\n 52 Module : msmsCommands\n 53 Class : ReadMSMS\n 54 Command name : readMSMS\n 55 \nSynopsis :\n 56 None--->mv.readMSMS(vertFilename,faceFilename,molName=None)\n 57 \nRequired Arguments :\n 58 vertFilename---name of the .vert file\n 59 faceFilename---name of the .face file\n 60 """ 61
62 - def __init__(self, func=None):
63 MVCommand.__init__(self, func) 64 self.msmsFromFile = {}
65 66 ### 67 ### WIDGETS CALLBACK FUNCTIONS 68 ### 69
70 - def onAddObjectToViewer(self, obj):
71 if self.cmdForms.has_key('readMSMS'): 72 ebn = self.cmdForms['readMSMS'].descr.entryByName 73 w = ebn['molName']['widget'] 74 molNames = list(w.get()) 75 molNames.append(obj.name) 76 w.clear() 77 w.setlist(molNames)
78 79 # Need to ask for a .vert file, a .face file and a molecule if want 80 # to bind a molecule to the surface 81 82 83
84 - def setEntry_cb(self, filename):
85 import os 86 file, ext = os.path.splitext(filename) 87 ebn = self.cmdForms['readMSMS'].descr.entryByName 88 vertEntry = ebn['vertfile']['widget'] 89 faceEntry = ebn['facefile']['widget'] 90 if ext == '.vert': 91 vertEntry.setentry(filename) 92 ffilename = '%s.face'%file 93 if os.path.exists(ffilename): 94 faceEntry.setentry(ffilename) 95 elif ext == '.face': 96 faceEntry.setentry(filename) 97 vfilename = '%s.vert'%file 98 if os.path.exists(vfilename): 99 vertEntry.setentry(vfilename) 100 else: return
101 #entry.setentry(filename) 102 103
104 - def buildFormDescr(self, formName):
105 if formName == 'readMSMS': 106 idf = InputFormDescr(title="READ MSMS") 107 idf.append({'name':'vertfile', 108 'required':1, 109 'widgetType':Pmw.EntryField, 110 'tooltip':"Please type in the path to the .vert file \ 111 you wish to parse or click on the BROWSE button to open a file browser", 112 'wcfg':{'labelpos':'w', 113 'label_text':"Vertices Filename", 114 }, 115 'gridcfg':{'sticky':'w'}}) 116 117 idf.append({'widgetType':LoadButton, 118 'name':'browseVert', 119 'wcfg':{'buttonType':Tkinter.Button, 120 'title':'Load file describing msms vertices.', 121 'types':[('MSMS Vert','*.vert')], 122 'callback':self.setEntry_cb, 123 'widgetwcfg':{'text':'BROWSE'}}, 124 'gridcfg':{'row':-1, 'sticky':'we'}}) 125 idf.append({'name':'facefile', 126 'required':1, 127 'tooltip':"Please type in the path to the .face file \ 128 you wish to parse or click on the BROWSE button to open a file browser", 129 'widgetType':Pmw.EntryField, 130 'wcfg':{'labelpos':'w', 131 'label_text':"Faces Filename", 132 }, 133 'gridcfg':{'sticky':'w'}}) 134 135 idf.append({'widgetType':LoadButton, 136 'name':'browseVert', 137 'wcfg':{'buttonType':Tkinter.Button, 138 'title':'Load file describing msms faces.', 139 'types':[('MSMS Face','*.face')], 140 'callback':self.setEntry_cb, 141 'widgetwcfg':{'text':'BROWSE'}}, 142 'gridcfg':{'row':-1, 'sticky':'we'}}) 143 144 molNames = ['None',] 145 mols = self.vf.getSelection().top 146 if mols: 147 mols = mols.top.uniq() 148 molNames = molNames + mols.name 149 150 idf.append({'name':'molName', 151 'widgetType':Pmw.ScrolledListBox, 152 'tooltip':'Select a molecule to bind to the geometry \ 153 representing this msms surface', 154 'defaultValue':molNames[0], 155 'wcfg':{'label_text':'Molecule Name: ', 156 'labelpos':'nw', 157 'items':molNames, 158 'listbox_selectmode':'single', 159 'listbox_exportselection':0, 160 'usehullsize': 1, 161 'hull_width':100,'hull_height':150, 162 'listbox_height':5, 163 }, 164 'gridcfg':{'sticky': 'we'}}) 165 166 return idf
167
168 - def guiCallback(self):
169 val = self.showForm('readMSMS') 170 if not val: return 171 vertFilename = val['vertfile'] 172 kw={'redraw':1} 173 faceFilename = val['facefile'] 174 if val['molName'][0] == 'None': 175 kw['molName'] = None 176 else: 177 kw['molName'] = val['molName'][0] 178 179 apply(self.doitWrapper, (vertFilename, faceFilename), kw)
180 181
182 - def doit(self, vertFilename, faceFilename, molName=None):
183 184 vertFName = os.path.split(vertFilename)[1] 185 faceFName = os.path.split(faceFilename)[1] 186 vertName = os.path.splitext(vertFName)[0] 187 faceName = os.path.splitext(faceFName)[0] 188 assert vertName == faceName 189 msmsParser = MSMSParser() 190 self.msmsFromFile[vertName] = msmsParser 191 msmsParser.parse(vertFilename, faceFilename) 192 self.surf = IndexedPolygons(vertName+'_msms', visible=1, 193 pickableVertices=1, protected=True,) 194 if self.vf.userpref['sharpColorBoundariesForMsms']['value'] == 'blur': 195 self.surf.Set(inheritSharpColorBoundaries=False, sharpColorBoundaries=False, ) 196 #self.surf.RenderMode(GL.GL_FILL, face=GL.GL_FRONT, redo=0) 197 #self.surf.Set(frontPolyMode=GL.GL_FILL, redo=0) 198 self.surf.Set(vertices=msmsParser.vertices, faces=msmsParser.faces, 199 vnormals=msmsParser.normals, tagModified=False) 200 self.vf.GUI.VIEWER.AddObject(self.surf) 201 if not molName is None: 202 self.vf.bindGeomToMolecularFragment(self.surf, molName, 203 topCommand=0)
204
205 - def __call__(self, vertFilename, faceFilename, molName=None, **kw):
206 """None--->mv.readMSMS(vertFilename,faceFilename,molName=None, **kw) 207 """ 208 kw['molName'] = molName 209 kw['redraw'] = 1 210 apply(self.doitWrapper, (vertFilename, faceFilename), kw)
211 212 ReadMSMSGUI = CommandGUI() 213 ReadMSMSGUI.addMenuCommand('menuRoot', 'Compute', 'Read Molecular Surface', 214 cascadeName='Molecular Surface') 215
216 -class SaveMSMS(MVCommand):
217 """The SaveMSMS commands allows the user to save a chosen MSMS surface (tri-angulated solvant excluded surface) resulting from a calculation.\n 218 Package : Pmv\n 219 Module : msmsCommands\n 220 Class : SaveMSMS\n 221 Command name : saveMSMS\n 222 \nDescription:\n 223 Two files will be created, one for 224 vertices (.vert) and one for faces (.face). 225 If the component number is 0, files called filename.vert and filename.face 226 are created. 227 For other components, the component number is inserted in the file name, 228 for example for the component number 3 the files are called 229 filename_3.vert and filename_3.face. 230 231 The face file contains three header lines followed by one triangle per 232 line. The first header line provides a comment and the filename of the 233 sphere set. 234 The second header line holds comments about the content of the third line. 235 The third header line provides the number of triangles, the number of 236 spheres in the set, the triangulation density and the probe sphere radius. 237 The first three numbers are (1 based) vertex indices. The next field 238 can be: 1 for a triangle in a toric reentrant face, 2 for a triangle in 239 a spheric reentrant face and 3 for a triangle in a contact face. 240 The last number on the line is the (1 based) face number in the 241 analytical description of the solvent excluded surface. These values 242 are written in the following format ''%6d %6d %6d %2d %6d''. 243 244 The vertex file contains three header lines (similar to the header 245 in the .face file) followed by one vertex per line and provides the 246 coordinates (x,y,z) and the normals (nx,ny,nz) followed by the number of 247 the face (in the analytical description of the solvent excluded surface) 248 to which the vertex belongs. 249 The vertices of the analytical surface have a value 0 in that field and 250 the vertices lying on edges of this surface have nega tive values. 251 The next field holds the (1 based) index of the closest sphere. 252 The next field is 1 for vertices which belong to toric reentrant faces 253 (including vertices of the analytical surface), 2 for vertices inside 254 reentrant faces and 3 for vertices inside contact faces. 255 Finally, if atom names were present in the input file, the name of the 256 closest atom is written for each vertex. These values are written in 257 the following format 258 ''%9.3f %9.3f %9.3f %9.3f %9.3f %9.3f %7d %7d %2d %s''.\n 259 260 \nSynopsis:\n 261 None <- saveMSMS(filename, mol, surfacename, withHeader=1, component=0, 262 format='MS_TSES_ASCII', **kw)\n 263 filename : name of the output file\n 264 mol : molecule associated with the surface\n 265 surfacename : name of the surface to save\n 266 withHeader : flag to either write the headers or not\n 267 component : specifies which component of the surface to write out\n 268 format : specifies in which format to save the surface. 269 It can be one of the following ,\n 270 'MS_TSES_ASCII' Triangulated surface in ASCII format\n 271 'MS_ASES_ASCII' Analytical surface in ASCII format. This is 272 actually a discrete representation of the analytical model.\n 273 'MS_TSES_ASCII_AVS' Triangulated surface in ASCII with 274 AVS header\n 275 'MS_ASES_ASCII_AVS' Analytical surface in ASCII format 276 with AVS header\n 277 278 """ 279
280 - def onAddCmdToViewer(self):
281 self.formats = ['MS_TSES_ASCII', 282 'MS_ASES_ASCII', 283 'MS_TSES_ASCII_AVS', 284 'MS_ASES_ASCII_AVS' 285 ]
286 # MS_TSES_ASCII : Triangulated surface in ASCII format 287 # MS_ASES_ASCII : Analytical surface in ASCII format, which is 288 # a discrete representation of the analytical model 289 # MS_TSES_ASCII_AVS : Triangulated surface in ASCII with AVS header 290 # MS_ASES_ASCII_AVS : Analytical surface in ASCII format with AVS 291 # header 292 293 ### ################################################################## 294 ### CALLBACK FUNCTIONS 295 ### ################################################################## 296
297 - def setDial_cb(self, value):
298 if not self.cmdForms.has_key('saveMSMS'): return 299 # need to get the right surface.... 300 molName, srfName = value.split('/') 301 mol = filter(lambda x: x.name == molName, self.vf.Mols)[0] 302 srf = mol.geomContainer.msms[srfName][0] 303 maxComponent = srf.rsr.nb-1 304 dW = self.cmdForms['saveMSMS'].descr.entryByName['component']['widget'] 305 dW.configure(max=maxComponent)
306
307 - def setEntry_cb(self, filename):
308 import os 309 file = os.path.splitext(filename)[0] 310 ebn = self.cmdForms['saveMSMS'].descr.entryByName 311 entry = ebn['filename']['widget'] 312 entry.setentry(file)
313 314 ### ################################################################# 315
316 - def buildFormDescr(self, formName):
317 if formName=='saveMSMS': 318 molSrf = [] 319 for mol in self.vf.Mols: 320 if not hasattr(mol.geomContainer, 'msms') \ 321 or not mol.geomContainer.msms.keys(): 322 continue 323 for surf in mol.geomContainer.msms.keys(): 324 molSrf.append(mol.name +'/'+surf) 325 if not molSrf: return 326 idf = InputFormDescr(title="Save MSMS") 327 # Surface to wrire out 328 idf.append({'name':'molsrf', 329 'widgetType':Pmw.ComboBox, 330 'tooltip':"Please select the surface to save", 331 'wcfg':{'label_text':'Molecular Surfaces:', 332 'labelpos':'nw', 333 'scrolledlist_items':molSrf, 334 'selectioncommand':self.setDial_cb, 335 'history':0}, 336 'defaultValue':molSrf[0], 337 'gridcfg':{'sticky':'we', 'columnspan':2}}) 338 # Component to write 339 idf.append({'name':'component', 340 'widgetType':Dial, 341 'wcfg':{'labCfg':{'side':'left','text':'component'}, 342 'type':'int','min':0,'size':50, 343 'max':0,'increment':1, 344 'showLabel':1,'lockMin':1, 345 'lockBMin':1,'lockBMax':1, 346 'lockMax':1,'lockPrecision':1, 347 'lockShowLabel':1, 'lockValue':1, 348 'lockType':1, 'lockContinuous':1, 349 'lockOneTurn':1, 350 }, 351 'gridcfg':{'columnspan':2}}) 352 # Format to use 353 tooltip="""Please select one of the following format:\n 354 MS_TSES_ASCII: Triangulated surface in ASCII format 355 MS_ASES_ASCII: Analytical surface in ASCII format, which is a discrete 356 representation of the analytical model. 357 MS_TSES_ASCII_AVS: Triangulated surface in ASCII with AVS header 358 MS_ASES_ASCII_AVS: Analytical surface in ASCII format with AVS header 359 """ 360 idf.append({'name':'format', 361 'widgetType':Pmw.ComboBox, 362 'tooltip':tooltip, 363 'defaultValue':self.formats[0], 364 'wcfg':{'label_text':'Format:', 365 'labelpos':'nw', 366 'scrolledlist_items':self.formats}, 367 'gridcfg':{'sticky':'we', 'columnspan':2}}) 368 369 # Whether or not to write header. 370 idf.append({'name':'withHeader', 371 'widgetType':Tkinter.Checkbutton, 372 'wcfg':{'text':'Write Header:', 373 'variable':Tkinter.IntVar()}, 374 'gridcfg':{'sticky':'we'} 375 }) 376 377 # File to create 378 idf.append({'name':'filename', 379 'widgetType':Pmw.EntryField, 380 'tooltip':'Enter the filename, a filename.face \ 381 and filename.vert will be created.', 382 'wcfg':{'label_text':'Filename:', 383 'labelpos':'w'}, 384 'gridcfg':{'sticky':'we'}, 385 }) 386 387 idf.append({'widgetType':SaveButton, 388 'name':'filebrowse', 389 'wcfg':{'buttonType':Tkinter.Button, 390 'title':'Save In File ...', 391 'types':[('MSMS Face','*.face'), 392 ('MSMS Vert', '*.vert')], 393 'callback':self.setEntry_cb, 394 'widgetwcfg':{'text':'BROWSE'}}, 395 'gridcfg':{'row':-1, 'sticky':'we'}}) 396 397 return idf
398
399 - def guiCallback(self):
400 # 1- the surface to save 401 if self.cmdForms.has_key('saveMSMS'): 402 w = self.cmdForms['saveMSMS'].descr.entryByName['molsrf']['widget'] 403 for mol in self.vf.Mols: 404 if not hasattr(mol.geomContainer, 'msms') or \ 405 not mol.geomContainer.msms.keys(): 406 continue 407 molsrf = [] 408 for surf in mol.geomContainer.msms.keys(): 409 molsrf.append(mol.name +'/'+surf) 410 w.setlist(molsrf) 411 412 val = self.showForm('saveMSMS', force=1) 413 kw = {} 414 if not val: return 415 if val.has_key('filename'): 416 filename = val['filename'] 417 kw['format'] = val['format'][0] 418 kw['component'] = val['component'] 419 kw['withHeader'] = val['withHeader'] 420 molsrf = val['molsrf'][0] 421 molname, surfName = molsrf.split('/') 422 apply(self.doitWrapper, (filename, molname, surfName), kw)
423 424
425 - def doit(self, filename, molName, surfName, withHeader=True, component=0, 426 format="MS_TSES_ASCII"):
427 mol = self.vf.getMolFromName(molName) 428 if mol is None: return 429 gc = mol.geomContainer 430 if not gc.msms.has_key(surfName): return 431 msmsSurf = gc.msms[surfName][0] 432 msmsAtms = gc.msms[surfName] 433 from mslib import msms 434 if not format in self.formats: 435 format = "MS_TSES_ASCII" 436 format = getattr(msms, format) 437 if component is None : component = 0 438 elif not component in range( msmsSurf.rsr.nb ): 439 self.warningMsg("%s is an invalid component"%component) 440 return 441 msmsSurf.write_triangulation(filename, no_header=not withHeader, 442 component=component, format=format)
443 444
445 - def __call__(self, filename, molName, surfName, withHeader=True, 446 component=None, format="MS_TSES_ASCII", **kw):
447 """None <--- mv.saveMSMS(filename, mol, surface, withHeader=True,component=None, format='MS_TSES_ASCII', **kw)\n 448 \nRequired Arguments:\n 449 filename --- path to the output file without an extension two files will be created filename.face and a filename.vert\n 450 mol --- Protein associated to the surface\n 451 surface --- surface name\n 452 453 \nOptional Arguments:\n 454 withHeader --- True Boolean flag to specify whether or not to write the headers in the .face and the .vert files\n 455 component --- msms component to save by default None\n 456 format --- format in which the surface will be saved. It can be,\n 457 MS_TSES_ASCII: Triangulated surface in ASCII format.\n 458 MS_ASES_ASCII: Analytical surface in ASCII format.This is a discrete representation of the analytical model.MS_TSES_ASCII_AVS: Triangulated surface in ASCII with AVS header\n 459 MS_ASES_ASCII_AVS: Analytical surface in ASCII format with AVS header\n 460 461 """ 462 if not molName or not filename or not surfName: return 463 kw['withHeader'] = withHeader 464 kw['component'] = component 465 kw['format'] = format 466 apply(self.doitWrapper, (filename, molName, surfName), kw)
467 468 469 SaveMSMSGUI = CommandGUI() 470 SaveMSMSGUI.addMenuCommand('menuRoot', 'Compute', 'Save Molecular Surface', 471 cascadeName='Molecular Surface') 472
473 -class ComputeMSMS(MVCommand, MVAtomICOM):
474 """The computeMSMS command will compute a triangulated solvent excluded surface for the current selection.\n 475 Package : Pmv\n 476 Module : msmsCommands\n 477 Class : ComputeMSMS\n 478 Command name : computeMSMS\n 479 \nSynopsis :\n 480 None <--- mv.computeMSMS(nodes, surfName=None, pRadius=1.5, 481 density=1.0, perMol=True, 482 display=1)\n 483 \nRequired Arguments :\n 484 nodes --- current selection\n 485 \nOptional Arguments:\n 486 surfName --- name of the surfname which will be used as the key in 487 mol.geomContainer.msms dictionary. If the surfName is 488 already a key of the msms dictionary the surface is 489 recreated. By default mol.name-MSMS\n 490 pRadius --- probe radius (1.5)\n 491 density --- triangle density to represent the surface. (1.0)\n 492 perMol --- when this flag is True a surface is computed for each molecule 493 having at least one node in the current selection 494 else the surface is computed for the current selection. 495 (True)\n 496 display --- flag when set to 1 the displayMSMS will be executed to 497 display the new msms surface.\n 498 499 """ 500 501 ### 502 ###COMMAND METHODS 503 ###
504 - def __init__(self, func=None):
505 MVCommand.__init__(self) 506 MVAtomICOM.__init__(self) 507 self.flag = self.flag | self.objArgOnly
508
509 - def checkDependencies(self):
510 import mslib
511 512
513 - def onAddCmdToViewer(self):
514 if not self.vf.commands.has_key('assignAtomsRadii'): 515 self.vf.loadCommand('editCommands', ['assignAtomsRadii',], 516 topCommand=0)
517
518 - def onAddObjectToViewer(self, obj):
519 """ 520 """ 521 if not self.vf.hasGui: return 522 geomC = obj.geomContainer 523 geomC.nbSurf = 0 524 geomC.msms = {} 525 geomC.msmsAtoms = {} # AtomSets used for surfaces 526 geomC.msmsCurrentDisplay = {} # Dictionary whose keys are 'surfaceNames'
527 # and whose values are strings 528 # to be used to undo either 'displayMSMS' 529 # or 'displayBuriedTriangles', restoring 530 # the geometry 'surfaceName' to its 531 # previous state. This dictionary is 532 # necessary because these two different commands 533 # can effect changes to the same geometry, 534 # thus making the undo dependent on the 535 # command sequence.... 536 # 1. displayMSMS followed by displayMSMS is 537 # simplest to undo: invoke the second displayMSMS 538 # cmd with negate flag on 539 # 2. displayMSMS followed by displayBuriedTriangles 540 # requires displayMSMS with 541 # geomContainer.atoms['surfaceName'] 542 # 3. displayBuriedTriangles followed by displayMSMS 543 # AND 544 # 4. displayBuriedTriangles followed by displayBuriedTriangles 545 # requires geom.Set(faces=currentFaces) 546 # NOTE: correctly updating msmsCurrentDisplay needs testing 547
548 - def atomPropToVertices(self, geom, atoms, propName, propIndex=None):
549 """Function called to map atomic properties to the vertices of the 550 geometry""" 551 if len(atoms)==0: return None 552 553 geomC = geom.mol.geomContainer 554 surfName = geom.userName 555 surf = geomC.msms[surfName][0] 556 surfNum = geomC.msms[surfName][1] 557 # array of colors of all atoms for the msms. 558 prop = [] 559 if propIndex is not None: 560 for a in geomC.msmsAtoms[surfName].data: 561 d = getattr(a, propName) 562 prop.append( d[surfName] ) 563 else: 564 for a in geomC.msmsAtoms[surfName].data: 565 prop.append( getattr(a, propName) ) 566 # find indices of atoms with surface displayed 567 atomIndices = [] 568 indName = '__surfIndex%d__'%surfNum 569 for a in atoms.data: 570 atomIndices.append(getattr(a, indName)) 571 # get the indices of closest atoms 572 dum1, vi, dum2 = surf.getTriangles(atomIndices, keepOriginalIndices=1) 573 # get lookup col using closest atom indicies 574 mappedProp = Numeric.take(prop, vi[:, 1]-1).astype('f') 575 if hasattr(geom,'apbs_colors'): 576 colors = [] 577 for i in range(len(geom.apbs_dum1)): 578 ch = geom.apbs_dum1[i] == dum1[0] 579 if not 0 in ch: 580 tmp_prop = mappedProp[0] 581 mappedProp = mappedProp[1:] 582 dum1 = dum1[1:] 583 if tmp_prop == [1.5,1.5,1.5]: 584 colors.append(geom.apbs_colors[i][:3]) 585 else: 586 colors.append(tmp_prop) 587 if not dum1: 588 break 589 mappedProp = colors 590 return mappedProp
591 592
593 - def pickedVerticesToBonds(self, geom, parts, vertex):
594 return None
595 596
597 - def pickedVerticesToAtoms(self, geom, vertInd):
598 """Function called to convert picked vertices into atoms""" 599 600 # this function gets called when a picking or drag select event has 601 # happened. It gets called with a geometry and the list of vertex 602 # indices of that geometry that have been selected. 603 # This function is in charge of turning these indices into an AtomSet 604 605 surfName = geom.userName 606 geomC = geom.mol.geomContainer 607 surfNum = geomC.msms[surfName][1] 608 indName = '__surfIndex%d__'%surfNum 609 610 #FIXME: building atomindices is done in DisplayMSMS 611 # should re-use it 612 mol = geom.mol 613 atomindices = [] 614 indName = '__surfIndex%d__'%surfNum 615 al = mol.geomContainer.atoms[surfName] 616 for a in al: 617 atomindices.append(getattr(a, indName)) 618 619 surf = geomC.msms[surfName][0] 620 dum1, vi, dum2 = surf.getTriangles(atomindices, keepOriginalIndices=1) 621 622 l = [] 623 allAt = geomC.msmsAtoms[surfName] 624 for i in vertInd: 625 l.append(allAt[vi[i][1]-1]) 626 return AtomSet( AtomSet( l ) )
627 628
629 - def __call__(self, nodes, surfName='MSMS-MOL', pRadius=1.5, 630 density=3.0, perMol=True, display=True, hdset='None', 631 hdensity=6.0, **kw):
632 """None <- mv.computeMSMS(nodes, surfName='MSMSMOL', pRadius=1.5,density=1.0,perMol=True, display=1)\n 633 \nRequired Arguments :\n 634 nodes --- atomic fragment (string or objects)\n 635 \nOptional Arguments :\n 636 surfName --- name of the surfname which will be used as the key in 637 mol.geomContainer.msms dictionary. If the surfName is 638 already a key of the msms dictionary the surface is 639 recomputed. (default MSMS-MOL)\n 640 pRadius --- probe radius (1.5)\n 641 density --- triangle density to represent the surface. (1.0)\n 642 perMol --- when this flag is True a surface is computed for each 643 molecule having at least one node in the current selection 644 else the surface is computed for the current selection. 645 (True)\n 646 display --- flag when set to 1 the displayMSMS will be executed with 647 the surfName else not.\n 648 hdset --- Atom set (or name) for which high density triangualtion will 649 be generated 650 hdensity --- vertex density for high density 651 """ 652 nodes=self.vf.expandNodes(nodes) 653 kw['surfName'] = surfName 654 kw['pRadius'] = pRadius 655 kw['density'] = density 656 kw['perMol'] = perMol 657 kw['display'] = display 658 kw['hdset'] = hdset 659 kw['hdensity'] = hdensity 660 if type(nodes) is StringType: 661 self.nodeLogString = "'" + nodes +"'" 662 apply(self.doitWrapper, (nodes,), kw)
663 664
665 - def fixValues(self, val):
666 if val['hdset'] is None: 667 return val 668 if val['hdset'] == 'None': 669 val['hdset'] = None 670 return val 671 hdsetName = val['hdset'][0] 672 if hdsetName=='None' or hdsetName=='': 673 val['hdset'] = None 674 return val
675 676
677 - def guiCallback(self):
678 if self.cmdForms.has_key('default'): 679 self.updateCBB() 680 val = self.showForm('default') 681 if not val: return 682 if type(val['surfName']) is types.TupleType: 683 surfName = val['surfName'][0] 684 else: 685 surfName = val['surfName'] 686 687 val = self.fixValues(val) 688 del val['surfName'] 689 690 apply(self.doitWrapper, (self.vf.getSelection(), surfName), val)
691 692
693 - def doit(self, nodes, surfName='MSMS-MOL', pRadius=1.5, density=1.0, 694 perMol=True, display=True, hdset=None, hdensity=6.0):
695 """Required Arguments:\n 696 nodes --- current selection\n 697 surfName --- name of the surfname which will be used as the key in 698 mol.geomContainer.msms dictionary.\n 699 \nOptional Arguments: \n 700 pRadius --- probe radius (1.5)\n 701 density --- triangle density to represent the surface. (1.0)\n 702 perMol --- when this flag is True a surface is computed for each 703 molecule having at least one node in the current selection 704 else the surface is computed for the current selection. 705 (True)\n 706 display --- flag when set to True the displayMSMS will be executed with 707 the surfName else not.\n 708 hdset --- Atom set for which high density triangualtion 709 will be generated 710 hdensity --- vertex density for high density 711 """ 712 713 from mslib import MSMS 714 if nodes is None or not nodes: 715 return 716 # Check the validity of the input 717 if not type(density) in [types.IntType, types.FloatType] or \ 718 density < 0: return 'ERROR' 719 if not type(pRadius) in [types.IntType, types.FloatType] or \ 720 pRadius <0: return 'ERROR' 721 722 if hdset=='None': 723 hdset=None 724 if hdset: 725 if self.vf.sets.has_key(hdset[0]): 726 hdset = self.vf.sets[hdset[0]].findType(Atom) 727 else: 728 self.warningMsg("set %s not found"%hdset) 729 for a in hdset: 730 a.highDensity = True 731 732 # get the set of molecules and the set of atoms per molecule in the 733 # current selection 734 if perMol: 735 molecules = nodes.top.uniq() 736 atmSets = map(lambda x: x.allAtoms, molecules) 737 else: 738 molecules, atmSets = self.vf.getNodesByMolecule(nodes, Atom) 739 740 for mol, atms in map(None, molecules, atmSets): 741 if not surfName: 742 surfName = mol.name + '-MSMS' 743 geomC = mol.geomContainer 744 745 if not geomC.msms.has_key(surfName): 746 # Create a new geometry 747 # be stored. 748 g = IndexedPolygons(surfName, pickableVertices=1, protected=True,) 749 if self.vf.userpref['sharpColorBoundariesForMsms']['value'] == 'blur': 750 g.Set(inheritSharpColorBoundaries=False, sharpColorBoundaries=False,) 751 g.userName = surfName 752 geomC.addGeom(g) 753 self.managedGeometries.append(g) 754 geomC.geomPickToAtoms[surfName] = self.pickedVerticesToAtoms 755 geomC.geomPickToBonds[surfName] = None 756 # This needs to be replaced by string to not have a direct 757 # dependency between PMV and OPENGL... 758 #g.RenderMode(GL.GL_FILL, face=GL.GL_FRONT, redo=0) 759 #g.Set(frontPolyMode=GL.GL_FILL, redo=0) 760 # g.RenderMode('GL_FILL', face='GL_FRONT', redo=0) 761 geomC.atomPropToVertices[surfName] = self.atomPropToVertices 762 # Create the key for this msms for each a.colors dictionary. 763 for a in mol.allAtoms: 764 a.colors[surfName] = (1.,1.,1.) 765 a.opacities[surfName] = 1.0 766 # Created a new geometry needs to update the form if exists. 767 if self.cmdForms.has_key('default'): 768 self.updateForm(surfName) 769 770 # update the existing geometry 771 geomC.msmsAtoms[surfName]=atms[:] 772 geomC.atoms[surfName] = AtomSet([]) #atms 773 774 i=0 # atom indices are 1-based in msms 775 indName = '__surfIndex%d__'%geomC.nbSurf 776 hd = [] 777 surf = [] 778 for a in atms: 779 setattr(a, indName, i) 780 i = i + 1 781 surf.append(1) 782 if hasattr(a, 'highDensity'): 783 hd.append(1) 784 else: 785 hd.append(0) 786 787 # get atm radii if necessary 788 try: 789 atmRadii = atms.radius 790 except: 791 atmRadii = self.vf.assignAtomsRadii(mol, united=0, 792 topCommand=0) 793 atmRadii = atms.radius 794 795 # build an MSMS object and compute the surface 796 srf = MSMS(coords=atms.coords, radii=atmRadii, surfflags=surf, 797 hdflags=hd ) 798 srf.compute(probe_radius=pRadius, density=density, 799 hdensity=hdensity) 800 801 # save a pointer to the MSMS object 802 mol.geomContainer.msms[surfName] = (srf, geomC.nbSurf) 803 # Increment the nbSurf counter 804 geomC.nbSurf += 1 805 806 if hdset: 807 for a in hdset: 808 del a.highDensity 809 810 if display: 811 if not self.vf.commands.has_key('displayMSMS'): 812 self.vf.loadCommand("msmsCommands", ['displayMSMS',], 813 topCommand=0) 814 if nodes.stringRepr is not None: 815 geomC.msmsCurrentDisplay[surfName] = \ 816 "self.displayMSMS('%s', surfName=['%s'], negate=0, only=0, nbVert=%d, topCommand=0)" %(nodes.stringRepr, surfName, Pmv.numOfSelectedVerticesToSelectTriangle) 817 else: 818 geomC.msmsCurrentDisplay[surfName] = \ 819 "self.displayMSMS('%s', surfName=['%s'], negate=0, only=0, nbVert=%d, topCommand=0)" %(nodes.full_name(), surfName, Pmv.numOfSelectedVerticesToSelectTriangle) 820 821 self.vf.displayMSMS(nodes, surfName=[surfName,], negate=0, only=1, 822 nbVert=Pmv.numOfSelectedVerticesToSelectTriangle, log=0)
823 824
825 - def buildFormDescr(self, formName='default'):
826 if formName == 'default': 827 idf = InputFormDescr(title ="MSMS Parameters Panel:") 828 mols = self.vf.getSelection().top.uniq() 829 sNames = [] 830 for mol in mols: 831 sNames += mol.geomContainer.msms.keys() 832 833 defaultValues = self.getLastUsedValues() 834 835 if not sNames: 836 sNames = ['MSMS-MOL'] 837 idf.append({'widgetType':Pmw.ComboBox, 838 'name':'surfName', 839 'required':1, 840 'tooltip': "Please type-in a new name or chose \ 841 one from the list below\n '_' are not accepted.", 842 'wcfg':{'labelpos':'nw', 843 'label_text':'Surface Name: ', 844 'entryfield_validate':self.entryValidate, 845 'entryfield_value':'MSMS-MOL', 846 'scrolledlist_items':[], 847 }, 848 'gridcfg':{'sticky':'we'}}) 849 else: 850 idf.append({'widgetType':Pmw.ComboBox, 851 'name':'surfName', 852 'required':1, 853 'tooltip': "Please type-in a new name or chose \ 854 one from the list below\n '_' are not accepted.", 855 'defaultValue': defaultValues['surfName'], 856 'wcfg':{'labelpos':'nw', 857 'label_text':'Surface Name: ', 858 'entryfield_validate':self.entryValidate, 859 'scrolledlist_items':sNames, 860 }, 861 'gridcfg':{'sticky':'we'}}) 862 863 names = ['None']+self.vf.sets.keys() 864 names.sort() 865 idf.append({'widgetType':Pmw.ComboBox, 866 'name':'hdset', 867 'required':0, 868 'tooltip': """Choose a set defining the part of the surface 869 that should be triangualte at high density""", 870 'defaultValue': str(defaultValues['hdset']), 871 'wcfg':{'labelpos':'nw', 872 'label_text':'High density surface set: ', 873 'scrolledlist_items':names, 874 }, 875 'gridcfg':{'sticky':'we'}}) 876 idf.append({'name':'perMol', 877 'tooltip':"""When checked surfaces will be computed using all atoms (seelcted or not) of 878 each molecule. If unchecked, the unselected atoms are ignored during the 879 calculation.""", 880 'widgetType':Tkinter.Checkbutton, 881 'defaultValue': defaultValues['perMol'], 882 'wcfg':{'text':'Per Molecule', 883 'variable':Tkinter.IntVar(), 884 'command':self.perMol_cb}, 885 'gridcfg':{'sticky':'we'} 886 }) 887 888 idf.append({'name':'saveSel', 889 'widgetType':Tkinter.Button, 890 'tooltip':"""This button allows the user to save the current selection as a set. 891 The name of the msms surface will be used as the name of the set""", 892 'wcfg':{'text':'Save Current Selection As Set', 893 'state':'disabled', 894 'command':self.saveSel_cb}, 895 'gridcfg':{'sticky':'we'}}) 896 897 idf.append({'name':'pRadius', 898 'widgetType':ThumbWheel, 899 'tooltip': 900 """Right click on the widget to type a value manually""", 901 'gridcfg':{'sticky':'we'}, 902 'wcfg':{'value':1.5, 'oneTurn':2, 903 'type':'float', 904 'value': defaultValues['pRadius'], 905 'increment':0.1, 906 'precision':1, 907 'continuous':False, 908 'wheelPad':2,'width':145,'height':18, 909 'labCfg':{'text':'Probe Radius'}, 910 } 911 }) 912 913 idf.append({'name':'density', 914 'widgetType':ThumbWheel, 915 'tooltip':"""Vertex density use for triangulating the surface. 916 Right click on the widget to type a value manually""", 917 'gridcfg':{'sticky':'we'}, 918 'wcfg':{'oneTurn':2, 919 'type':'float', 920 'value': defaultValues['density'], 921 'increment':0.1, 922 'precision':1, 923 'continuous':False, 924 'wheelPad':2,'width':145,'height':18, 925 'labCfg':{'text':'Density '}, 926 } 927 }) 928 929 idf.append({'name':'hdensity', 930 'widgetType':ThumbWheel, 931 'tooltip':"""Vertex density use for triangulating the high density part of the surface. 932 Right click on the widget to type a value manually""", 933 934 'gridcfg':{'sticky':'we'}, 935 'wcfg':{'oneTurn':2, 936 'type':'float', 937 'value': defaultValues['hdensity'], 938 'increment':0.1, 939 'precision':1, 940 'continuous':False, 941 'wheelPad':2,'width':145,'height':18, 942 'labCfg':{'text':'High Density '}, 943 } 944 }) 945 946 947 return idf
948 949 ### 950 ### HELPER METHODS 951 ###
952 - def setTexCoords(self, mol, values):
953 srf = mol.geomContainer.msms 954 lookup = mol.geomContainer.texCoordsLookup["msms"] 955 g = mol.geomContainer.geoms['msms'] 956 if g.texture: 957 g.texture.auto=0 958 if srf: 959 vf, vi, f = srf.getTriangles() 960 values.shape = (-1,1) 961 assert len(values)==len(vf) 962 i = 0 963 for v in vf: 964 lookup[str(v[0])+str(v[1])+str(v[2])] = values[i] 965 i = i + 1 966 self.updateTexCoords(mol)
967 968
969 - def updateTexCoords(self, mol):
970 lookup = mol.geomContainer.texCoordsLookup["msms"] 971 g = mol.geomContainer.geoms['msms'] 972 tx = map(lambda v, l=lookup: l[str(v[0])+str(v[1])+str(v[2])], 973 g.vertexSet.vertices.array) 974 tx = Numeric.array(tx) 975 tx.shape = (-1,1) 976 g.Set( textureCoords=tx, tagModified=False )
977 978 979
980 - def updateForm(self, surfName):
981 ebn = self.cmdForms['default'].descr.entryByName 982 w = ebn['surfName']['widget'] 983 allitems = w.get() 984 if not surfName in allitems: 985 w.insert('end',surfName)
986 987 ### 988 ### GUI CALLBACKS 989 ###
990 - def entryValidate(self, text):
991 """ 992 Method to validate the name of the msms surface. This name 993 will be used by other command to build Pmw widget so it can't 994 contain an '_'. 995 """ 996 if '_' in text: 997 return Pmw.ERROR 998 else: 999 return Pmw.OK
1000 1001
1002 - def updateCBB(self):
1003 defaultValues = self.getLastUsedValues() 1004 ebn = self.cmdForms['default'].descr.entryByName 1005 cbb = ebn['surfName']['widget'] 1006 typein = cbb.get() 1007 sel = cbb.getcurselection() 1008 if typein in sel: return 1009 sNames = [] 1010 mols = self.vf.getSelection().top.uniq() 1011 for mol in mols: 1012 sNames += mol.geomContainer.msms.keys() 1013 if not typein in sNames: 1014 return 1015 else: 1016 cbb.setlist(sNames) 1017 cbb.selectitem(typein) 1018 1019 names = ['None']+self.vf.sets.keys() 1020 names.sort() 1021 cbb = ebn['hdset']['widget'] 1022 cbb.setlist(names) 1023 if defaultValues['hdset'] is not None: 1024 cbb.selectitem(str(defaultValues['hdset'][0])) #str(None)->"None"
1025
1026 - def perMol_cb(self, event=None):
1027 if not self.cmdForms.has_key('default'): 1028 return 1029 ebn = self.cmdForms['default'].descr.entryByName 1030 perMol = ebn['perMol']['wcfg']['variable'].get() 1031 saveBut = ebn['saveSel']['widget'] 1032 if perMol: 1033 saveBut.configure(state='disabled') 1034 ebn['saveSel']['wcfg']['state']='disabled' 1035 else: 1036 saveBut.configure(state='normal') 1037 ebn['saveSel']['wcfg']['state']='normal'
1038 1039
1040 - def saveSel_cb(self, event=None):
1041 self.cmdForms['default'].releaseFocus() 1042 name=self.vf.saveSet.guiCallback() 1043 self.cmdForms['default'].grabFocus() 1044 cbb = self.cmdForms['default'].descr.entryByName['surfName']['widget'] 1045 cbb.setentry(name)
1046 1047 ComputeMSMSGUI = CommandGUI() 1048 ComputeMSMSGUI.addMenuCommand('menuRoot', 'Compute','Compute Molecular Surface', 1049 cascadeName='Molecular Surface') 1050 1051 1052 from ViewerFramework.VF import DeleteAtomsEvent, AddAtomsEvent, EditAtomsEvent 1053
1054 -class DisplayMSMS(DisplayCommand):
1055 """The displayMSMS command allows the user to display/undisplay or display only the given MSMS surface corresponding to the current selection.\n 1056 Package : Pmv\n 1057 Module : msmsCommands\n 1058 Class : DisplayMSMS\n 1059 Command name : displayMSMS\n 1060 \nRequired Arguments:\n 1061 nodes --- TreeNodeSet holding the current selection\n 1062 \nOptional Arguments:\n 1063 only --- flag when set to 1 only the current selection will be 1064 displayed\n 1065 negate --- flag when set to 1 undisplay the current selection\n 1066 surfName --- name of the selection, default = 'all'\n 1067 nbVert --- Nb of vertices per triangle needed to select a triangle.\n 1068 1069 """ 1070
1071 - def onAddCmdToViewer(self):
1072 #self.vf.registerListener(DeleteAtomsEvent, self.updateGeom) 1073 self.vf.registerListener(EditAtomsEvent, self.handleEditEvent)
1074 #self.vf.registerListener(AddAtomsEvent, self.updateGeom) 1075 1076
1077 - def handleEditEvent(self, event):
1078 from mslib import msms 1079 1080 # build list of optional command arguments 1081 doitoptions = self.lastUsedValues['default'] 1082 doitoptions['redraw']=1 1083 doitoptions['topCommand']=0 1084 1085 molecules, atomSets = self.vf.getNodesByMolecule(event.objects, Atom) 1086 for mol, atoms in zip(molecules, atomSets): 1087 1088 geomC = mol.geomContainer 1089 1090 # loop over all surfaces 1091 for name in geomC.msms.keys(): 1092 g = geomC.geoms[name] 1093 1094 # get the atom indices 1095 surfc = geomC.msms[name][0] 1096 surfNum = geomC.msms[name][1] 1097 indName = '__surfIndex%d__'%surfNum 1098 atomindices = [] 1099 coords = [] 1100 for a in atoms: 1101 atomindices.append(a.__dict__[indName]) 1102 coords.append( a.coords+[a.radius] ) 1103 1104 msms.MS_reset_atom_update_flag(surfc) 1105 i = msms.MS_updateSpheres(surfc, len(atoms), atomindices, 1106 coords) 1107 rs = surfc.rsr.fst 1108 # this would only be needed once initially 1109 msms.MS_tagCloseProbes(surfc, rs, 15.0) 1110 mode = 0 1111 density = surfc.density 1112 updateNum = 1 1113 i =msms.MS_update_surface(surfc, rs, mode, density, updateNum) 1114 if i==msms.MS_ERR: 1115 print "ERROR while updating RS %d %s\n"%(updateNum, "Error")#msms.MS_err_msg) MS_err_msg not exposed 1116 return 1117 #msms.MS_update_SES_area(surfc, rs.ses) 1118 vf, vi, f = surfc.getTriangles() 1119 col = mol.geomContainer.getGeomColor(name) 1120 1121 g.Set( vertices=vf[:,:3], vnormals=vf[:,3:6], 1122 faces=f[:,:3], materials=col, visible=1, 1123 tagModified=False )
1124 1125 1126
1127 - def setupUndoBefore(self, nodes, surfName='all', negate=False, only=False, nbVert=1):
1128 molecules, atomSets = self.vf.getNodesByMolecule(nodes, Atom) 1129 for mol, atoms in map(None, molecules, atomSets): 1130 geomC = mol.geomContainer 1131 surfNames = geomC.msms.keys() 1132 if surfName == 'all': 1133 names = surfNames 1134 elif not type(surfName) in [types.ListType, types.TupleType]: 1135 if not surfName in surfNames: 1136 continue 1137 else: 1138 names = [surfName,] 1139 else: 1140 names = surfName 1141 for n in names: 1142 # undo depends on whether current msms geometry resulted from 1143 # displayMSMS OR from displayBuriedTriangles 1144 # for each molecule, this is tracked in dictionary stored as 1145 # molecule.geomContainer.msmsCurrentDisplay[surfName] 1146 #possibly surface was previously computed but never displayed 1147 lastCmd = geomC.msmsCurrentDisplay.get(n, "") 1148 if lastCmd=="" or lastCmd.find('displayMSMS')>-1: 1149 #no previous geometry OR the geometry resulted from displayMSMS 1150 not_negate = not negate 1151 if not geomC.atoms.has_key(n): 1152 continue 1153 ats = geomC.atoms[n] 1154 if not len(ats): 1155 continue 1156 #FIX THIS SHOULD IT REALLY BE NOT-NEGATE??? 1157 old_atoms_name = self.vf.undo.saveUndoArg(ats) 1158 undoCmd = "self.displayMSMS(%s, surfName=['%s'], negate=%d, only=%d, nbVert=%d, topCommand=0)" %(old_atoms_name, n, not_negate, only, nbVert) 1159 #undoCmd = "self.displayMSMS('%s', surfName=['%s'], negate=%d, only=%d, nbVert=%d, topCommand=0)" %(old_atoms_name, n, not_negate, only, nbVert) 1160 self.vf.undo.addEntry((undoCmd), (self.name)) 1161 elif lastCmd.find('displayBuried')>-1: 1162 #the geometry resulted from displayBuriedTriangles 1163 #get a handle to the IndexedPolygon geometry 1164 g = geomC.geoms[n] 1165 #save the current verts 1166 old_vertices_name = self.vf.undo.saveUndoArg(g.getVertices()) 1167 #save the current faces 1168 old_faces_name = self.vf.undo.saveUndoArg(g.getFaces()) 1169 #save the current vnormals 1170 old_vnormals_name = self.vf.undo.saveUndoArg(g.getVNormals()) 1171 #save the current front_colors 1172 front_colors = g.materials[GL.GL_FRONT].getState() 1173 old_front_name = self.vf.undo.saveUndoArg(front_colors) 1174 #save the current back_colors 1175 back_colors = g.materials[GL.GL_BACK].getState() 1176 old_back_name = self.vf.undo.saveUndoArg(back_colors) 1177 undoCmd = "from opengltk.OpenGL import GL;g = self.expandNodes('%s')[0].geomContainer.geoms['%s'];g.Set(vertices=%s, faces=%s, vnormals=%s);apply(g.materials[GL.GL_FRONT].Set, (), %s);apply(g.materials[GL.GL_BACK].Set, (), %s)" %(mol.name, n, old_vertices_name, old_faces_name, old_vnormals_name, old_front_name, old_back_name) 1178 geomC.msmsCurrentDisplay[n] = undoCmd 1179 self.vf.undo.addEntry((undoCmd), (self.name))
1180 1181 1182
1183 - def doit(self, nodes, surfName='all', negate=False, only=False, nbVert=Pmv.numOfSelectedVerticesToSelectTriangle):
1184 #print "DisplayMSMS.doit", 1185 molecules, atomSets = self.vf.getNodesByMolecule(nodes, Atom) 1186 for mol, atoms in map(None, molecules, atomSets): 1187 geomC = mol.geomContainer 1188 surfNames = geomC.msms.keys() 1189 if surfName == 'all': 1190 names = surfNames 1191 1192 elif not type(surfName) in [types.ListType, types.TupleType]: 1193 if not surfName in surfNames: 1194 return 1195 else: 1196 names = [surfName,] 1197 else: 1198 names = surfName 1199 1200 for sName in names: 1201 # Make sure that the surface exists for this molecule. 1202 if not sName in surfNames: continue 1203 # first get the atoms for this molecule in set of atoms used 1204 # for that surface 1205 allAtms = geomC.msmsAtoms[sName] 1206 atm = allAtms.inter(atoms) 1207 1208 # get the set of atoms with surface displayed 1209 lSet = geomC.atoms[sName] 1210 1211 ##if negate, remove current atms from displayed set 1212 if negate: lSet = lSet - atm 1213 1214 ##if only, replace displayed set with current atms 1215 else: 1216 if only: lSet = atm 1217 else: lSet = atm.union(lSet) 1218 1219 if lSet is None: 1220 print "skipping ", sName 1221 continue 1222 1223 geomC.atoms[sName]=lSet 1224 1225 # get the msms surface object for that molecule 1226 srf = geomC.msms[sName][0] 1227 1228 # get the atom indices 1229 surfNum = geomC.msms[sName][1] 1230 indName = '__surfIndex%d__'%surfNum 1231 atomindices = [] 1232 for a in lSet: 1233 atomindices.append(getattr(a, indName)) 1234 1235 g = geomC.geoms[sName] 1236 if lSet.stringRepr is not None: 1237 geomC.msmsCurrentDisplay[sName] = "self.displayMSMS('%s', surfName=['%s'], negate=%d, only=%d, nbVert=%d, topCommand=0)" %(lSet.stringRepr, sName, negate, only, nbVert) 1238 else: 1239 geomC.msmsCurrentDisplay[sName] = "self.displayMSMS('%s', surfName=['%s'], negate=%d, only=%d, nbVert=%d, topCommand=0)" %(lSet.full_name(), sName, negate, only, nbVert) 1240 if len(atomindices) == 0: 1241 g.Set(visible=0, tagModified=False) 1242 else: 1243 # get the triangles corresponding to these atoms 1244 vf, vi, f = srf.getTriangles(atomindices, selnum=nbVert, keepOriginalIndices=1) 1245 col = mol.geomContainer.getGeomColor(sName) 1246 g.Set( vertices=vf[:,:3], vnormals=vf[:,3:6], 1247 faces=f[:,:3], materials=col, visible=1, 1248 tagModified=False ) 1249 1250 if g.transparent: 1251 opac = mol.geomContainer.getGeomOpacity(sName) 1252 g.Set( opacity=opac, redo=0, tagModified=False) 1253 1254 # update texture coordinate if needed 1255 if g.texture and g.texture.enabled and g.texture.auto==0: 1256 mol.geomContainer.updateTexCoords[sName](mol) 1257 1258 # highlight selection 1259 vi = self.vf.GUI.VIEWER 1260 selMols, selAtms = self.vf.getNodesByMolecule(self.vf.selection, Atom) 1261 for oneMol, atoms in map(None, selMols, selAtms): 1262 if mol is oneMol: 1263 lAtomSet = mol.geomContainer.msmsAtoms[sName] 1264 if len(lAtomSet) > 0: 1265 lAtomSetDict = dict(zip(lAtomSet, range(len(lAtomSet)))) 1266 lAtomIndices = [] 1267 for i in range(len(atoms)): 1268 lIndex = lAtomSetDict.get(atoms[i], None) 1269 if lIndex is not None: 1270 lAtomIndices.append(lIndex) 1271 lSrfMsms = mol.geomContainer.msms[sName][0] 1272 lvf, lvint, lTri = lSrfMsms.getTriangles(lAtomIndices, selnum=nbVert, 1273 keepOriginalIndices=1) 1274 highlight = [-1] * len(g.vertexSet.vertices) 1275 for lThreeIndices in lTri: 1276 highlight[int(lThreeIndices[0])] = lThreeIndices[0] 1277 highlight[int(lThreeIndices[1])] = lThreeIndices[1] 1278 highlight[int(lThreeIndices[2])] = lThreeIndices[2] 1279 g.Set(highlight=highlight) 1280 break
1281 1282
1283 - def buildFormDescr(self, formName='default'):
1284 if formName == 'default': 1285 idf = DisplayCommand.buildFormDescr(self, formName) 1286 surfNames = self.getSurfNames() 1287 idf.append({'name':'surfName', 1288 'widgetType':Pmw.ScrolledListBox, 1289 'tooltip':'surface to be display/undisplayed', 1290 'wcfg':{'label_text':'Surface: ', 1291 'labelpos':'nw', 1292 'items':surfNames, 1293 'listbox_selectmode':'extended', 1294 'usehullsize': 1, 1295 'hull_width':100,'hull_height':150, 1296 'listbox_height':5, 1297 }, 1298 'gridcfg':{'sticky': 'we'}}) 1299 idf.append({'name':'nbVert', 1300 'widgetType':Pmw.ComboBox, 1301 'tooltip':'number of vertices in a triangle that \ 1302 have to belong\nto a selected atom, for that face to be shown', 1303 'defaultValue':'1', 1304 'wcfg':{'label_text':'nb. Vert Per face: ', 1305 'labelpos':'w', 1306 'scrolledlist_items': ['1', '2', '3']}, 1307 'gridcfg':{'sticky': 'we'}}) 1308 1309 return idf
1310 1311
1312 - def getSurfNames(self):
1313 mols = self.vf.getSelection().top.uniq() 1314 surfNames = [] 1315 for mol in mols: 1316 for name in mol.geomContainer.msms.keys(): 1317 if not name in surfNames: 1318 surfNames.append(name) 1319 return surfNames
1320 1321
1322 - def guiCallback(self):
1323 # Update the comboBox with the name of the surfaces 1324 if self.cmdForms.has_key('default'): 1325 surfNames = self.getSurfNames() 1326 ebn = self.cmdForms['default'].descr.entryByName 1327 w = ebn['surfName']['widget'] 1328 w.clear() 1329 w.setlist(surfNames) 1330 1331 val = DisplayCommand.getFormValues(self) 1332 if val: 1333 val['nbVert'] = int(val['nbVert'][0]) 1334 apply( self.doitWrapper, (self.vf.getSelection(),), val)
1335 1336
1337 - def __call__(self, nodes, only=False, negate=False, surfName='all', 1338 nbVert=1, **kw):
1339 """None <--- displayMSMS(nodes, only=False, negate=False, name='all', **kw)\n 1340 \nRequired Arguments:\n 1341 nodes --- TreeNodeSet holding the current selection\n 1342 \nOptional Arguments:\n 1343 only --- Boolean flag when set to True only the current selection will be displayed (default=False)\n 1344 negate --- Boolean flag when set to True undisplay the current selection (default=False)\n 1345 surfName --- name of the selection, default = 'all'\n 1346 nbVert --- Nb of vertices per triangle needed to select a triangle\n 1347 """ 1348 if not kw.has_key('redraw'): kw['redraw'] = 1 1349 kw['only'] = only 1350 kw['negate'] = negate 1351 kw['nbVert'] = nbVert 1352 kw['redraw'] = 1 1353 if type(nodes) is types.StringType: 1354 self.nodeLogString = "'"+nodes+"'" 1355 nodes = self.vf.expandNodes(nodes) 1356 if surfName is None: kw['surfName'] = 'all' 1357 else: 1358 kw['surfName'] = surfName 1359 apply( self.doitWrapper, (nodes,), kw )
1360 1361 DisplayMSMSGUI = CommandGUI() 1362 DisplayMSMSGUI.addMenuCommand('menuRoot', 'Display', 'Molecular Surface') 1363 1364 1365 1366 from types import StringType 1367
1368 -class UndisplayMSMS(DisplayCommand):
1369 """The undisplayMSMS command allows the user to undisplay displayedMSMS\n 1370 Package : Pmv\n 1371 Module : msmsCommands\n 1372 Class : UndisplayMSMS\n 1373 Command name : undisplayMSMS\n 1374 \nRequired Arguments:\n 1375 nodes --- TreeNodeSet holding the current selection\n. 1376 """ 1377
1378 - def onAddCmdToViewer(self):
1379 if not self.vf.hasGui: return 1380 if not self.vf.commands.has_key('displayMSMS'): 1381 self.vf.loadCommand('msmsCommands', ['displayMSMS'], 'Pmv', 1382 topCommand=0)
1383
1384 - def __call__(self, nodes, **kw):
1385 """None <- undisplayMSMS(nodes, **kw)\n 1386 nodes ---TreeNodeSet holding the current selection 1387 (mv.getSelection())""" 1388 kw['negate']= 1 1389 kw['redraw']=1 1390 if type(nodes) is StringType: 1391 self.nodeLogString = "'" + nodes +"'" 1392 apply(self.vf.displayMSMS, (nodes,),kw)
1393 1394 1395
1396 -class ComputeMSMSApprox(ComputeMSMS):
1397 """Computes an approximative molecular surface for a selected set of atoms by molecule.\n 1398 Package : Pmv\n 1399 Module : msmsCommands\n 1400 Class : ComputeMSMSApprox\n 1401 Command name : computeMSMSApprox\n 1402 \nDescription:\n 1403 This approximation is done by replacing each residue by a sphere. The center of the sphere is geometric center of the atoms in the residue. The radius is set to include all atoms.\n 1404 \nSynopsis:\n 1405 None<---mv.computeMSMSapprox(nodes,surfName='MSMSMOL',pRadius=1.5,density=1.0,nbSphPerRes=1, perMol=True, display=1)\n 1406 \nRequired Arguments :\n 1407 nodes --- current selection\n 1408 \nOptional Arguments:\n 1409 surfName --- name of the surfname which will be used as the key in 1410 mol.geomContainer.msms dictionary. If the surfName is 1411 already a key of the msms dictionary the surface is 1412 recreated. By default MSMS-MOL\n 1413 pRadius --- probe radius (1.5)\n 1414 density --- triangle density to represent the surface. (1.0)\n 1415 perMol --- when this flag is True a surface is computed for each molecule 1416 having at least one node in the current selection 1417 else the surface is computed for the current selection. 1418 (True)\n 1419 display --- flag when set to 1 the displayMSMS will be executed to 1420 display the new msms surface.\n 1421 1422 nbSphPerRes --- number of approximating spheres per residue,default=1, possible values 1 or 2\n 1423 1424 """ 1425
1426 - def computeResidueSpheres(self, residues, nbSphPerRes=1):
1427 """Compute the geometric centers and the radii of the spheres that 1428 will cover each residue""" 1429 centers = [] # list of centers of approximating spheres 1430 radii = [] # list of radii of approximating spheres 1431 atoms = [] # list of representative atoms for approximating spheres 1432 1433 def getSphere(atoms): 1434 """get the center and radius of the sphere for a set of atoms""" 1435 coords = atoms.coords 1436 g = Numeric.sum(coords)/len(atoms) 1437 dist = Numeric.subtract(coords, g) 1438 dist = Numeric.sum(dist*dist, 1) 1439 maxd = max(dist) 1440 atom = atoms[list(dist).index(maxd)] 1441 return atoms[0], list( g ), sqrt(maxd)+atom.radius
1442 1443 def getBBatoms(residue): 1444 bbat = [] 1445 scat = [] 1446 for a in residue.atoms: 1447 name = a.name.split("@")[0] 1448 if name=='N' or name=='C' or name=='CA' or name=='O' \ 1449 or name=='HN' or name=='HA': 1450 bbat.append(a) 1451 else: 1452 scat.append(a) 1453 return AtomSet(bbat), AtomSet(scat)
1454 1455 if nbSphPerRes==2: 1456 for r in residues: 1457 if r.type=='GLY' or r.type=='ALA' or r.type=='PRO': 1458 a, c, r = getSphere(r.atoms) 1459 radii.append( r ) 1460 centers.append( c ) 1461 atoms.append( a ) 1462 else: 1463 bbatoms, scatoms = getBBatoms(r) 1464 if len(bbatoms): 1465 a, c, r = getSphere( bbatoms ) 1466 radii.append( r ) 1467 centers.append( c ) 1468 atoms.append( a ) 1469 1470 if len(scatoms): 1471 a, c, r = getSphere( scatoms ) 1472 radii.append( r ) 1473 centers.append( c ) 1474 atoms.append( a ) 1475 else: 1476 for r in residues: 1477 a, c, r = getSphere(r.atoms) 1478 radii.append( r ) 1479 centers.append( c ) 1480 atoms.append( a ) 1481 1482 return AtomSet(atoms), centers, radii 1483 1484
1485 - def doit(self, nodes, surfName='MSMS-MOL', pRadius=1.5, density=1.0, 1486 perMol=True, display=True, nbSphPerRes=1):
1487 from mslib import MSMS 1488 1489 if perMol: 1490 molecules = nodes.top.uniq() 1491 resSets = map(lambda x: x.chains.residues, molecules) 1492 else: 1493 molecules, resSets = self.vf.getNodesByMolecule(nodes, Residue) 1494 1495 for mol, res in map(None, molecules, resSets): 1496 1497 # get radii if necessary 1498 try: 1499 res.atoms.radius 1500 except: 1501 #if not hasattr(res[0].atoms[0], 'radius'): 1502 mol.defaultRadii() 1503 1504 # get the centers and radii used for MSMS calculation 1505 atm, centers, radii = self.computeResidueSpheres(res,nbSphPerRes) 1506 1507 geomC = mol.geomContainer 1508 if surfName is None: 1509 surfName = 'msmsApprox%d'%geomC.nbSurf 1510 1511 if surfName in geomC.atoms.keys(): 1512 # Update the old geom and all. 1513 geomC.msmsAtoms[surfName] = atm 1514 geomC.atoms[surfName] = atm 1515 g = geomC.geoms[surfName] 1516 else: 1517 # Create a new geom and all 1518 geomC.msmsAtoms[surfName] = atm # all atoms used to compute 1519 g = IndexedPolygons(surfName, pickableVertices=1, protected=True,) 1520 if self.vf.userpref['sharpColorBoundariesForMsms']['value'] == 'blur': 1521 g.Set(inheritSharpColorBoundaries=False, sharpColorBoundaries=False,) 1522 g.userName = surfName 1523 geomC.addGeom(g) 1524 self.managedGeometries.append(g) 1525 geomC.geomPickToAtoms[surfName] = self.pickedVerticesToAtoms 1526 geomC.geomPickToBonds[surfName] = None 1527 #g.Set(frontPolyMode='fill', redo=0) 1528 geomC.atomPropToVertices[surfName] = self.atomPropToVertices 1529 1530 # Create the key for this msms for each a.colors dictionary. 1531 for a in mol.allAtoms: 1532 a.colors[surfName] = (1.,1.,1.) 1533 a.opacities[surfName] = 1.0 1534 1535 i=0 # atom indices are 1-based 1536 indName = '__surfIndex%d__'%geomC.nbSurf 1537 for a in atm.data: 1538 a.__dict__[indName] = i 1539 i = i + 1 1540 1541 # build an MSMS object and compute the surface 1542 srf = MSMS( coords=centers, radii=radii ) 1543 srf.compute( probe_radius=pRadius, density=density ) 1544 1545 # save a pointer to the MSMS object 1546 mol.geomContainer.msms[surfName] = ( srf, geomC.nbSurf ) 1547 geomC.nbSurf = geomC.nbSurf + 1 1548 1549 # get the triangles and update the geometry of the surface for 1550 # that molecule 1551 vf,vi,f = srf.getTriangles() 1552 g = mol.geomContainer.geoms[surfName] 1553 1554 col = geomC.getGeomColor(surfName) 1555 g.Set( vertices=vf[:,:3], vnormals=vf[:,3:6], faces=f[:,:3], 1556 materials=col, tagModified=False ) 1557 if display: 1558 if not self.vf.commands.has_key('displayMSMS'): 1559 self.vf.loadCommand("msmsCommands", ['displayMSMS',], 1560 topCommand=0) 1561 self.vf.displayMSMS(atm, surfName=[surfName,],negate=0, only=0, 1562 nbVert=1, topCommand=0)
1563 1564
1565 - def __call__(self, nodes, surfName='MSMS-MOL', pRadius=1.5, density=1.0, 1566 nbSphPerRes=1, perMol=True, display=True, **kw):
1567 """None<---mv.computeMSMSapprox(nodes,surfName='MSMSMOL',pRadius=1.5,density=1.0,nbSphPerRes=1, perMol=True, display=1)\n 1568 \nRequired Arguments:\n 1569 nodes --- current selection\n 1570 \nOptional arguments:\n 1571 surfName --- name of the surfname which will be used as the key in mol.geomContainer.msms dictionary. If the surfName is already a key of the msms dictionary the surface is recomputed. (default MSMS-MOL)\n 1572 pRadius --- probe radius (1.5)\n 1573 density --- triangle density to represent the surface. (1.0)\n 1574 nbSphPerRes --- number of approximating spheres per residue,default=1, possible values 1 or 2\n 1575 perMol --- when this flag is True a surface is computed for each molecule having at least one node in the current selection else the surface is computed for the current selection.(True)\n 1576 display --- flag when set to 1 the displayMSMS will be executed with the surfName else not.\n 1577 """ 1578 if not kw.has_key('redraw'): kw['redraw'] = 1 1579 kw['pRadius'] = pRadius 1580 kw['density'] = density 1581 kw['surfName'] = surfName 1582 kw['nbSphPerRes'] = nbSphPerRes 1583 kw['perMol'] = perMol 1584 kw['display'] = display 1585 if type(nodes) is types.StringType: 1586 self.nodeLogString = "'"+nodes+"'" 1587 nodes = self.vf.expandNodes(nodes) 1588 apply( self.doitWrapper, (nodes,), kw)
1589 1590
1591 - def guiCallback(self):
1592 val = self.showForm() 1593 if not val: return 1594 if type(val['surfName']) is types.TupleType: 1595 val['surfName'] = val['surfName'][0] 1596 val['redraw'] = 1 1597 apply( self.doitWrapper, (self.vf.getSelection(),), val)
1598 1599 ComputeMSMSApproxGUI = CommandGUI() 1600 ComputeMSMSApproxGUI.addMenuCommand('menuRoot', 'Compute', 'Molecular Surface Approx', 1601 cascadeName='Molecular Surface') 1602 1603 1604 1605 from MolKit.molecule import Atom, AtomSet, Molecule, MoleculeSet 1606 from opengltk.OpenGL import GL 1607 import Numeric 1608
1609 -class MsmsNPR(MVCommand):
1610 """This command sets colors of MSMS surface to make it look NPR\n 1611 Package : Pmv\n 1612 Module : msmsCommands\n 1613 Class : MsmsNPR\n 1614 Command name : msmsNPR\n 1615 \nSynopsis:\n 1616 None <- msmsNPR(nodes) 1617 \nRequired Arguments :\n 1618 nodes --- current selection\n 1619 """ 1620 1621
1622 - def checkDependencies(self):
1623 import mslib
1624 1625
1626 - def setColors(self, mol):
1627 if not hasattr(mol.geomContainer, 'msms'): #surface not computed 1628 return 1629 g = mol.geomContainer 1630 geom = g.geoms['msms'] 1631 vf, vi, fa = g.msms.getTriangles() 1632 # FIXME won't work with instance matrices 1633 mat = geom.GetMatrix()[ :3, :3 ] 1634 nt = Numeric.matrixmultiply( vf[:, 3:6], Numeric.transpose(mat) ) 1635 norm = Numeric.sqrt( Numeric.add.reduce(nt*nt, 1)) 1636 ci = nt[ : , 2] / norm 1637 from DejaVu import colorTool 1638 cmap = Numeric.ones( (255,4), 'f' ) 1639 self.width=60 1640 self.vf.GUI.VIEWER.cameras[0].Set(color=(1.,1.,1.), tagModified=False) 1641 for i in range(self.width): 1642 v = i/self.width 1643 cmap[127-i] = (v,v,v,1.) 1644 cmap[127+i] = (v,v,v,1.) 1645 outlineCol = colorTool.Map(ci, cmap) 1646 origCol = geom.materials[1028].prop[0] 1647 if len(origCol)==1: 1648 origCol = Numeric.array( [list(origCol)]*len(outlineCol) ) 1649 #geom.materials[1028].prop[4] = Numeric.array([128.]) 1650 col = Numeric.array(outlineCol*origCol) 1651 #geom.materials[1028].prop[3] = col 1652 geom.materials[1028].prop[0] = col 1653 ## geom.Set(materials = col) 1654 ## from opengltk.OpenGL import GL 1655 ## geom.frontPolyMode = GL.GL_FILL 1656 geom.normals = None 1657 geom.RedoDisplayList()
1658 1659
1660 - def doit(self, nodes):
1661 from mslib import MSMS 1662 if not nodes: return 1663 molecules = nodes.top.uniq() 1664 for mol in molecules: 1665 self.setColors(mol)
1666
1667 - def __call__(self, nodes, **kw):
1668 """None <--- msmsNPR(nodes, **kw)\n 1669 \nRequired Arguments :\n 1670 nodes: TreeNodeSet holding the current selection\n""" 1671 if type(nodes) is types.StringType: 1672 self.nodeLogString = "'"+nodes+"'" 1673 kw['redraw']=True 1674 apply( self.doitWrapper, (nodes,), kw )
1675
1676 - def guiCallback(self):
1677 self.doitWrapper(self.vf.getSelection(), redraw=True)
1678 1679 msmsNPRGuiDescr = {'widgetType':'Menu', 'menuBarName':'menuRoot', 1680 'menuButtonName':'Compute', 1681 'menuEntryLabel':'NPR MSMS For Selection'} 1682 1683 MsmsNPRGUI = CommandGUI() 1684 MsmsNPRGUI.addMenuCommand('menuRoot', 'Compute', 'NPR MSMS For Selection', 1685 cascadeName = 'Molecular Surface') 1686 1687 1688
1689 -class IdentifyBuriedVertices(MVCommand):
1690 """This command enables finding out and tagging the vertices of a Solvent excluded surface that are buried by a set of atoms.\n 1691 Package : Pmv\n 1692 Module : msmsCommands\n 1693 Class :IdentifyBuriedVertices\n 1694 Command name :identifyBuriedVertices\n 1695 \nDescription:\n 1696 After running this command the vertices that are buried are tagged in 1697 the MSMS data structure with the buried flag (which is return by the 1698 ses.getTriangles() method. Each vertex of the triangulated ses also 1699 has a member called sesArea and sasArea that hold the surface area 1700 corresponding to each vertex of the triagulation.\n 1701 \nSynopsis:\n 1702 areas <- identifyBuriedVertices(surfaceName, surfaceMol, nodes)\n 1703 \nRequired Arguments:\n 1704 surfaceName --- name of an MSMS surface computed using MSMS\n 1705 surfaceMol --- molecule for which the surface 'surfaceName' has been computed\n 1706 nodes --- string or objects that expand into a set of atoms\n 1707 """ 1708
1709 - def checkDependencies(self):
1710 """make sure the mslib package is available""" 1711 import mslib
1712 1713
1714 - def doit(self, surfaceName, surfaceMol, nodes):
1715 """ 1716 \nsurfaceName---name of an MSMS surface computed using MSMS 1717 \nsurfaceMol---molecule for which the surface 'surfaceName' has been 1718 computed 1719 \nnodes---string or objects that expand into a set of atoms which may bury 1720 parts of the MSMS surface 1721 1722 \nReturn---a dictionary with 2 keys: 'ses' and 'sas'. The values are 1723 either lists of buried surface areas for all components considered. 1724 """ 1725 1726 # get the molecule surfaceMol 1727 surfaceMol = self.vf.expandNodes(surfaceMol) 1728 assert len(surfaceMol)==1 1729 1730 surfaceMol = surfaceMol[0] 1731 assert isinstance(surfaceMol, Molecule) 1732 1733 # get the msms surface object 1734 geomC = surfaceMol.geomContainer 1735 srf = geomC.msms[surfaceName][0] 1736 1737 # get the atoms that might bury parts on that surface 1738 nodes = self.vf.expandNodes(nodes) 1739 nodes = nodes.findType( Atom ) 1740 1741 # make sure they all have radii 1742 try: 1743 rad = nodes.radius 1744 except AttributeError: 1745 molecules = nodes.top.uniq() 1746 for mol in molecules: 1747 mol.defaultRadii() 1748 rad = nodes.radius 1749 1750 # identify buried vertices in all components 1751 srf.buriedVertices( nodes.coords, rad ) 1752 1753 # compute buried surface areas for all components and assign values 1754 # to triangulation vertices 1755 areas = srf.buriedSurfaceArea() 1756 return areas
1757 1758
1759 - def selectMolecule_cb(self, event=None):
1760 1761 moleculeName = self.ifd.entryByName['Molecule List']['widget'].get()[0] 1762 mol = self.vf.expandNodes(moleculeName)[0] 1763 geomC = mol.geomContainer 1764 w = self.ifd.entryByName['Surface List']['widget'] 1765 w.clear() 1766 for n in geomC.msms.keys(): 1767 w.insert('end', n, None)
1768 1769
1770 - def OK_cb(self, event=None):
1771 """call back for OK button""" 1772 self.ifd.form.OK_cb(event)
1773
1774 - def buildFormDescr(self, formName):
1775 if formName == 'buriedSurf': 1776 ifd = self.ifd = InputFormDescr(title='Compute Buried surface') 1777 entries = map(lambda x: (x, None), self.vf.Mols.name) 1778 1779 ifd.append({'name': 'Molecule List', 1780 'widgetType':ListChooser, 1781 'wcfg':{ 'title':'Choose a molecule (double click)', 1782 'entries': entries, 1783 'lbwcfg':{'exportselection':0, 1784 'width':25,'height':10}, 1785 'command':self.selectMolecule_cb, 1786 'commandEvent':"<Double-Button-1>" 1787 }, 1788 'gridcfg':{'sticky':Tkinter.E+Tkinter.W} 1789 }) 1790 1791 ifd.append({'name': 'Surface List', 1792 'widgetType':ListChooser, 1793 'wcfg':{ 1794 'title':'Choose a surface', 1795 'entries': [], 1796 'lbwcfg':{'exportselection':0,'width':25,'height':10}, 1797 'command': self.OK_cb, 1798 'commandEvent':"<Double-Button-1>" 1799 }, 1800 'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'row':0, 1801 'column':1} 1802 }) 1803 return ifd
1804
1805 - def guiCallback(self, event=None):
1806 1807 nodes = self.vf.getSelection() 1808 if len(nodes)==0: 1809 self.warningMsg('You should first select the atoms that will bury parts of a surface') 1810 return 1811 1812 val = self.showForm('buriedSurf') 1813 if len(val): 1814 molName = val['Molecule List'] 1815 surfName = val['Surface List'] 1816 if len(molName) and len(surfName): 1817 area = self.doitWrapper(surfName[0], molName[0], nodes) 1818 self.vf.message(str(area))
1819 1820
1821 - def __call__(self, surfaceName, surfaceMol, nodes, **kw):
1822 """areas <- identifyBuriedVertices(surfaceName, surfaceMol, nodes, 1823 **kw)\n 1824 Compute the area of the SES and SAS surface buried by a set of atoms\n 1825 \nArguments:\n 1826 surfaceName--- name of an MSMS surface computed using MSMS\n 1827 surfaceMol--- molecule for which the surface 'surfaceName' has been computed\n 1828 nodes--- string or objects that expand into a set of atoms\n 1829 Return---a dictionary with 2 keys: 'ses' and 'sas'. The values are either 1830 lists of buried surface areas for all components considered.\n 1831 """ 1832 return apply( self.doitWrapper, (surfaceName, surfaceMol, nodes), kw )
1833 1834 1835 identifyBuriedVerticesGuiDescr = {'widgetType':'Menu', 1836 'menuBarName':'menuRoot', 1837 'menuButtonName':'Compute', 1838 'menuEntryLabel':'Compute Buried Surface'} 1839 1840 IdentifyBuriedVerticesGUI = CommandGUI() 1841 IdentifyBuriedVerticesGUI.addMenuCommand('menuRoot', 'Compute', 1842 'Compute Buried Surface', 1843 cascadeName='Molecular Surface') 1844 1845
1846 -class DisplayBuriedTriangles(DisplayCommand):
1847 """This Command display/Undisplay buried SES as computed with BuriedSurface command.\n 1848 Package : Pmv\n 1849 Module : msmsCommands\n 1850 Class : DisplayBuriedTriangles\n 1851 Command name : displayBuriedTriangles\n 1852 \nSynopsis :\n 1853 None <--- displayBuriedTriangles(nodes, surfaceName, negate=0)\n 1854 \nRequired Arguments:\n 1855 nodes --- set of nodes for which the buried vertices of the surface 'surfaceName' are to be 1856 displayed. (string, TreeNode or TreeNodeSet)\n 1857 surfaceName --- name of an MSMS surface computed using msms. (string)\n 1858 \nOptional Arguments:\n 1859 cut---specifies how many vertices has to be buried (or not) for a triangle to be displayed.(1, 2 or 3)\n 1860 negate---specifies whether we want to display buried or exposed triangles\n 1861 """ 1862
1863 - def __init__(self, func=None):
1864 1865 DisplayCommand.__init__(self, func) 1866 self.flag = self.flag ^ self.objArgOnly
1867
1868 - def checkDependencies(self):
1869 """make sure the mslib package is available""" 1870 import mslib
1871 1872
1873 - def setupUndoBefore(self, nodes, surfaceName, cut=1, negate=False, only=False, redraw=1):
1874 # The undo of this display command depends on which displayMSMS cmd 1875 # was used previously and results in displaying what faces were displayed previously 1876 nodes = self.vf.expandNodes(nodes) 1877 molecules, atomSets = self.vf.getNodesByMolecule(nodes, Atom) 1878 for mol, atoms in map(None, molecules, atomSets): 1879 geomC = mol.geomContainer 1880 surfNames = geomC.msms.keys() 1881 if surfaceName == 'all': 1882 names = surfNames 1883 elif not type(surfaceName) in [types.ListType, types.TupleType]: 1884 if not surfaceName in surfNames: 1885 continue 1886 else: 1887 names = [surfaceName,] 1888 else: 1889 names = [] 1890 #only get the surfaces which are in geomC.msms.keys() 1891 for n in surfaceName: 1892 if n in surfNames: 1893 names.append(n) 1894 #names = surfaceName 1895 for n in names: 1896 # undo depends on whether current msms geometry resulted from 1897 # displayMSMS OR from displayBuriedTriangles 1898 # for each molecule, this is tracked in dictionary stored as 1899 # molecule.geomContainer.msmsCurrentDisplay[surfaceName] 1900 lastCmd = geomC.msmsCurrentDisplay.get(n, "") 1901 if lastCmd=="" or lastCmd.find('displayMSMS')>-1: 1902 #the geometry resulted from displayMSMS 1903 ats = geomC.atoms[n] 1904 old_nodes_name = self.vf.undo.saveUndoArg(ats) 1905 undoCmd = "self.displayMSMS(%s, surfName=['%s'], negate=%d, only=%d, nbVert=%d, topCommand=0)" %(old_nodes_name, n, negate, only, cut) 1906 self.vf.undo.addEntry((undoCmd), (self.name)) 1907 else: 1908 #the geometry resulted from displayBuriedTriangles 1909 #get a handle to the IndexedPolygon geometry 1910 g = geomC.geoms[n] 1911 #save the current verts 1912 old_vertices_name = self.vf.undo.saveUndoArg(Numeric.array(g.getVertices())) 1913 #save the current faces 1914 old_faces_name = self.vf.undo.saveUndoArg(Numeric.array(g.getFaces())) 1915 #save the current vnormals 1916 old_vnormals_name = self.vf.undo.saveUndoArg(Numeric.array(g.getVNormals())) 1917 #save the current front_colors 1918 front_colors = g.materials[GL.GL_FRONT].getState() 1919 old_front_name = self.vf.undo.saveUndoArg(front_colors) 1920 #save the current back_colors 1921 back_colors = g.materials[GL.GL_BACK].getState() 1922 old_back_name = self.vf.undo.saveUndoArg(back_colors) 1923 undoCmd = "from opengltk.OpenGL import GL;g = self.expandNodes('%s')[0].geomContainer.geoms['%s'];g.Set(vertices=%s, faces=%s, vnormals=%s);apply(g.materials[GL.GL_FRONT].Set, (), %s);apply(g.materials[GL.GL_BACK].Set, (), %s)" %(mol.name, n, old_vertices_name, old_faces_name, old_vnormals_name, old_front_name, old_back_name) 1924 #undoCmd = "self.expandNodes('%s')[0].geomContainer.geoms['%s'].Set(vertices=%s, faces=%s, vnormals=%s)" %(mol.name, n, old_vertices_name, old_faces_name, old_vnormals_name) 1925 geomC.msmsCurrentDisplay[n] = undoCmd 1926 self.vf.undo.addEntry((undoCmd), (self.name))
1927 1928 1929
1930 - def doit(self, nodes, surfaceName, cut=1, negate=False, only=False, **kw):
1931 """ 1932 nodes--- nodes for which the buried surface is to be displayed. 1933 surfaceName--- name of an MSMS surface computed using MSMS. 1934 cut-- triangles with this number of buried vertices will be displayed 1935 """ 1936 1937 molecules, atomSets = self.vf.getNodesByMolecule(nodes, Atom) 1938 for mol, atoms in map(None, molecules, atomSets): 1939 geomC = mol.geomContainer 1940 surfNames = geomC.msms.keys() 1941 if not type(surfaceName) in [types.ListType, types.TupleType]: 1942 if not surfaceName in surfNames: 1943 continue 1944 #return 1945 else: 1946 names = [surfaceName,] 1947 else: 1948 names = surfaceName 1949 1950 for sName in names: 1951 # Make sure that the surface exists for this molecule. 1952 if not sName in surfNames: continue 1953 # first get the atoms for this molecule in set of atoms used 1954 # for that surface 1955 allAtms = geomC.msmsAtoms[sName] 1956 atm = allAtms.inter(atoms) 1957 1958 # get the set of atoms with surface displayed 1959 set = geomC.atoms[sName] 1960 1961 ##if negate, remove current atms from displayed set 1962 if negate: set = set - atm 1963 1964 #if only, replace displayed set with current atms 1965 else: 1966 if only: set = atm 1967 else: set = atm.union(set) 1968 1969 geomC.atoms[sName] = set 1970 surfNum = geomC.msms[surfaceName][1] 1971 indName = '__surfIndex%d__'%surfNum 1972 atomindices = [] 1973 #for a in atoms: 1974 for a in set: 1975 atomindices.append(getattr(a, indName)) 1976 1977 # get the msms surface object for that molecule 1978 srf = geomC.msms[sName][0] 1979 g = geomC.geoms[sName] 1980 from opengltk.OpenGL import GL 1981 g.Set(culling=GL.GL_NONE) 1982 if len(atomindices) == 0: 1983 g.Set(visible=0, tagModified=False) 1984 else: 1985 # get the triangles corresponding to these atoms 1986 vf, vi, f = srf.getBuriedSurfaceTriangles(atomindices, selnum=cut, negate=negate) 1987 col = mol.geomContainer.getGeomColor(sName) 1988 g.Set( vertices=vf[:,:3], vnormals=vf[:,3:6], 1989 faces=f[:,:3], materials=col,