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(