Package MolKit :: Package VisionInterface :: Module MolKitNodes
[hide private]
[frames] | no frames]

Source Code for Module MolKit.VisionInterface.MolKitNodes

   1  ######################################################################### 
   2  # 
   3  # Date: Nov 2001 Authors: Michel Sanner, Daniel Stoffler 
   4  # 
   5  #    sanner@scripps.edu 
   6  #    stoffler@scripps.edu 
   7  # 
   8  #       The Scripps Research Institute (TSRI) 
   9  #       Molecular Graphics Lab 
  10  #       La Jolla, CA 92037, USA 
  11  # 
  12  # Copyright: Michel Sanner, Daniel Stoffler and TSRI 
  13  # 
  14  ######################################################################### 
  15   
  16  import warnings 
  17  import Numeric, string, os 
  18   
  19  from NetworkEditor.items import NetworkNode 
  20  from Vision import UserLibBuild 
  21   
  22  from DejaVu.VisionInterface.GeometryNodes import GeometryNode 
  23   
  24  from MolKit.molecule import Atom, AtomSet, Molecule, MoleculeSet 
  25  from MolKit.protein import Residue, ResidueSet, Chain, ChainSet 
  26  from MolKit.moleculeWriter import MoleculeWriter 
  27  from MolKit.pdbWriter import PdbWriter, PdbqWriter, PdbqsWriter, PdbqtWriter 
  28  from MolKit.pqrWriter import PqrWriter 
  29  from MolKit.pdbParser import PdbParser 
  30  from MolKit.chargeCalculator import GasteigerChargeCalculator, KollmanChargeCalculator 
  31  from MolKit.hydrogenBuilder import HydrogenBuilder, PolarHydrogenBuilder 
  32   
  33  try: 
  34      from mslib import MSMS, _msms 
  35      msmsFound=1 
  36  except ImportError: 
  37      import traceback 
  38      traceback.print_exc() 
  39      msmsFound=0 
  40   
  41   
42 -def importMolKitLib(net):
43 try: 44 from MolKit.VisionInterface.MolKitNodes import molkitlib 45 net.editor.addLibraryInstance( 46 molkitlib, 'MolKit.VisionInterface.MolKitNodes', 'molkitlib') 47 except: 48 import traceback 49 traceback.print_exc() 50 warnings.warn( 51 'Warning! Could not import molitlib from MolKit.VisionInterface')
52 53
54 -def importVizLib(net):
55 try: 56 from DejaVu.VisionInterface.DejaVuNodes import vizlib 57 net.editor.addLibraryInstance( 58 vizlib, 'DejaVu.VisionInterface.DejaVuNodes', 'vizlib') 59 except: 60 import traceback 61 traceback.print_exc() 62 warnings.warn( 63 'Warning! Could not import vizlib from DejaVu/VisionInterface')
64 65
66 -def importSymServLib(net):
67 try: 68 from symserv.VisionInterface.SymservNodes import symlib 69 net.editor.addLibraryInstance( 70 symlib, 'symserv.VisionInterface.SymservNodes', 'symlib') 71 except: 72 import traceback 73 traceback.print_exc() 74 warnings.warn( 75 'Warning! Could not import symlib from symserv/VisionInterface')
76 77 78
79 -class PDB_SYMTRY(NetworkNode):
80 """inputs PDB file, parses SYMTRY records and returns a list of (4x4) 81 matrices.""" 82
83 - def __init__(self, name='PDB_SYMTRY', **kw):
84 kw['name']=name 85 apply( NetworkNode.__init__, (self,), kw) 86 87 code = """def doit(self, mol): 88 if mol: 89 matrices = [] 90 all = lines = mol.data[0].parser.allLines 91 rem290 = filter(lambda x: x[:18]=="REMARK 290 SMTRY", all) 92 for i in range(0, len(rem290), 3): 93 lines = [] 94 mat = Numeric.identity(4).astype('f') 95 for j in range(3): 96 line1 = rem290[i+j] 97 r1 = float(line1[24:33]) 98 r2 = float(line1[34:43]) 99 r3 = float(line1[44:53]) 100 t = float(line1[54:68]) 101 mat[j] = (r1, r2, r3, t) 102 mat[3] = (0., 0., 0., 1.) 103 #matrices.append( Numeric.array( Numeric.transpose( mat) ) ) 104 matrices.append( mat ) 105 106 self.outputData(matrices=matrices)\n""" 107 108 if code: self.setFunction(code) 109 110 ip = self.inputPortsDescr 111 ip.append(datatype='MoleculeSet', name='molecule') 112 113 op = self.outputPortsDescr 114 op.append(datatype='instancemat(0)', name='matrices')
115 116
117 - def beforeAddingToNetwork(self, net):
118 # import molkitlib 119 importSymServLib(net)
120 121 122
123 -class CenterAndRadius(NetworkNode):
124
125 - def __init__(self, name='centerAndRad', **kw):
126 kw['name'] = name 127 apply( NetworkNode.__init__, (self,), kw) 128 129 ip = self.inputPortsDescr 130 ip.append(datatype='MoleculeSet', name='molecules') 131 132 op = self.outputPortsDescr 133 op.append(datatype='None', name='center') 134 op.append(datatype='float', name='radius') 135 136 code = """def doit(self, molecules): 137 import Numeric 138 from math import sqrt 139 centers = [] 140 radii = [] 141 for mol in molecules: 142 c = Numeric.array(mol.chains.residues.atoms.coords) 143 g = Numeric.add.reduce(c) / len(c) 144 centers.append( g ) 145 d = c-[g] 146 radii.append( sqrt(max(Numeric.add.reduce(d*d, 1))) ) 147 148 if len(centers): 149 self.outputData(center=centers, radius=radii) 150 """ 151 if code: self.setFunction(code)
152 153 154
155 -class ReadMolecule(NetworkNode):
156 """based on the MolKit.Read fucntion. Reads any file format recognized 157 by MolKit. This currently includes PDB, PDBQ, PDBQS, MOL2 and PQR. 158 Parse-able keywords can be specified in the param.panel of this node. 159 Input: filename (string) 160 Output: MoleculeSet""" 161
162 - def __init__(self, name='Read Molecule', **kw):
163 kw['name'] = name 164 apply( NetworkNode.__init__, (self,), kw ) 165 166 fileTypes=[('pdb', '*.pdb'),('pdbq', '*.pdbq'),('pdbqs', '*.pdbqs'), 167 ('pdbqt', '*.pdbqt'),('pqr', '*.pqr'),('mol2', '*.mol2'),('all', '*')] 168 169 self.widgetDescr['filename'] = { 170 'class':'NEEntryWithFileBrowser', 'master':'node', 171 'filetypes':fileTypes, 'title':'read molecule', 'width':10, 172 'labelCfg':{'text':'file:'}, 173 } 174 175 ip = self.inputPortsDescr 176 ip.append(datatype='string', name='filename') 177 178 op = self.outputPortsDescr 179 op.append(datatype='MoleculeSet', name='MolSets') 180 181 code = """def doit(self, filename): 182 if filename and len(filename): 183 from MolKit import Read 184 mols = Read(filename) 185 if mols: 186 self.outputData(MolSets=mols)\n""" 187 188 self.setFunction(code)
189
190 - def myCallback(self, event=None):
191 #self.paramPanel.run() 192 pass
193 194
195 -class WritePDB(NetworkNode):
196 """Save as PDB.""" 197
198 - def __init__(self, name='Write PDB', **kw):
199 kw['name'] = name 200 apply( NetworkNode.__init__, (self,), kw ) 201 202 fileTypes=[('pdb', '*.pdb'), ('all', '*')] 203 204 self.widgetDescr['filename'] = { 205 'class':'NEEntryWithFileSaver', 'master':'node', 206 'filetypes':fileTypes, 'title':'save PDB', 'width':10, 207 'labelCfg':{'text':'file:'}, 208 } 209 210 self.inputPortsDescr.append(datatype='list', name='nodes') 211 self.inputPortsDescr.append(datatype='string', name='filename') 212 213 code = """def doit(self, nodes, filename): 214 if filename and len(filename): 215 mol = nodes.top.uniq() 216 assert len(mol)==1 217 218 recType = 'all' # this could be exposed to the user? 219 sort = 1 220 221 if sort: 222 nodes.sort() 223 224 mol[0].write(filename, PdbWriter(), nodes, recType )\n""" 225 226 self.setFunction(code)
227 228
229 -class WriteMolecule(NetworkNode):
230 """Write any file format recognized 231 by MolKit. This currently includes PDB, PDBQ, PDBQS, MOL2 and PQR. 232 Parse-able keywords can be specified in the param.panel of this node. 233 Input: MoleculeSet 234 Input: filename (string)""" 235
236 - def __init__(self, name='Write Molecule', **kw):
237 self.writers = {} 238 self.writers['pdb'] = PdbWriter 239 self.writers['pqr'] = PqrWriter 240 self.writers['pdbq'] = PdbqWriter 241 self.writers['pdbqs'] = PdbqsWriter 242 self.writers['pdbqt'] = PdbqtWriter 243 self.required_attrs = {} 244 self.required_attrs['pdb'] = [] #? 245 self.required_attrs['pqr'] = ['charge', 'radius'] #same as pqrRadius 246 self.required_attrs['pdbq'] = ['charge'] 247 self.required_attrs['pdbqs'] = ['charge', 'AtSolPar', 'AtVol'] 248 self.required_attrs['pdbqt'] = ['charge', 'autodock_element'] 249 250 kw['name'] = name 251 apply( NetworkNode.__init__, (self,), kw ) 252 253 fileTypes=[('pdb', '*.pdb'),('pdbq', '*.pdbq'),('pdbqs', '*.pdbqs'), 254 ('pdbqt', '*.pdbqt'),('pqr', '*.pqr')] 255 256 self.widgetDescr['filename'] = { 257 'class':'NEEntryWithFileBrowser', 'master':'node', 258 'filetypes':fileTypes, 'title':'write molecule', 'width':10, 259 'labelCfg':{'text':'output file:'}, 260 } 261 262 ip = self.inputPortsDescr 263 ip.append(datatype='MoleculeSet', name='mols') 264 ip.append(datatype='string', name='filename') 265 ip.append(datatype='int', required=False, name='sort') 266 ip.append(datatype='list', required=False, name='records') 267 268 op = self.outputPortsDescr 269 op.append(datatype='string', name='filename') 270 271 code = """def doit(self, mols, filename, sort=False, records=['ATOM','HETATM']): 272 if mols and filename and len(filename): 273 ext = filename.split('.')[-1] 274 if not self.writers.has_key(ext): 275 print 'unrecognized outputfile type', ext 276 return 277 writer = self.writers[ext]() 278 #check for required attributes 279 #pqr requires charges, radius 280 #pdbq requires charges 281 #pdbqt requires charges and types 282 #pdbqs requires charges and solvation parameters 283 mol = mols[0] 284 ats = mol.allAtoms 285 for attr in self.required_attrs[ext]: 286 try: 287 getattr(ats, attr) 288 except: 289 print "all atoms do not have required attribute:", attr 290 return 'ERROR' 291 #need support for specifying records (?) 292 #NB: pqrWriter doesnot have same signature: no records parameter 293 try: #should work if ext!='pqr' 294 writer.write(filename, mol.allAtoms, sort=sort, records=records) 295 except: 296 writer.write(filename, mol.allAtoms, sort=sort) 297 self.outputData(filename=filename)\n""" 298 299 self.setFunction(code)
300
301 - def myCallback(self, event=None):
302 #self.paramPanel.run() 303 pass
304 305
306 -class AssignRadii(NetworkNode):
307
308 - def __init__(self, name='Assign Radii', **kw):
309 kw['name'] = name 310 apply( NetworkNode.__init__, (self,), kw ) 311 312 self.widgetDescr['united'] = { 313 'class':'NECheckButton', 'master':'node', 314 'labelCfg':{'text':'united radii'}, 315 } 316 317 ip = self.inputPortsDescr 318 ip.append(datatype='MoleculeSet', name='molecules') 319 ip.append(datatype='int', name='united') 320 321 op = self.outputPortsDescr 322 op.append(datatype='MoleculeSet', name='molecules') 323 op.append(datatype='list', name='radii') 324 325 code = """def doit(self, molecules, united ): 326 rad = [] 327 for mol in molecules: 328 rad.extend(mol.defaultRadii(united=united)) 329 if rad: 330 self.outputData(molecules=molecules, radii=rad) 331 """ 332 333 self.setFunction(code)
334 335
336 -class CalculateGasteigerCharges(NetworkNode):
337
338 - def __init__(self, name='Calculate Gasteiger Charges', **kw):
339 kw['name'] = name 340 apply( NetworkNode.__init__, (self,), kw ) 341 342 ip = self.inputPortsDescr 343 ip.append(datatype='MoleculeSet', name='mols') 344 345 op = self.outputPortsDescr 346 op.append(datatype='MoleculeSet', name='mols') 347 op.append(datatype='float', name='charge_total') 348 349 code = """def doit(self, mols ): 350 calculator = GasteigerChargeCalculator() 351 for mol in mols: 352 calculator.addCharges(mol.allAtoms) 353 import Numeric 354 charge_total = Numeric.add.reduce(mols.allAtoms.charge) 355 self.outputData(mols=mols, charge_total=charge_total) 356 """ 357 358 self.setFunction(code)
359 360
361 -class AddKollmanCharges(NetworkNode):
362
363 - def __init__(self, name='Add Kollman Charges', **kw):
364 kw['name'] = name 365 apply( NetworkNode.__init__, (self,), kw ) 366 367 ip = self.inputPortsDescr 368 ip.append(datatype='MoleculeSet', name='mols') 369 370 op = self.outputPortsDescr 371 op.append(datatype='MoleculeSet', name='mols') 372 op.append(datatype='float', name='charge_total') 373 374 code = """def doit(self, mols ): 375 calculator = KollmanChargeCalculator() 376 for mol in mols: 377 calculator.addCharges(mol.allAtoms) 378 import Numeric 379 charge_total = Numeric.add.reduce(mols.allAtoms.charge) 380 self.outputData(mols=mols, charge_total=charge_total) 381 """ 382 383 self.setFunction(code)
384 385
386 -class AddHydrogens(NetworkNode):
387
388 - def __init__(self, name='Add Hydrogens', **kw):
389 kw['name'] = name 390 apply( NetworkNode.__init__, (self,), kw ) 391 392 ip = self.inputPortsDescr 393 ip.append(datatype='MoleculeSet', name='molecules') 394 395 op = self.outputPortsDescr 396 op.append(datatype='MoleculeSet', name='molecules', balloon='molecules with added hydrogens') 397 op.append(datatype='int', name='new_h_ct', balloon='number of hydrogens added to molecules') 398 399 code = """def doit(self, molecules): 400 h_builder = HydrogenBuilder() 401 for mol in molecules: 402 new_h_ct = h_builder.addHydrogens(mol) 403 self.outputData(molecules=molecules, new_h_ct=new_h_ct) 404 """ 405 406 self.setFunction(code)
407 408
409 -class AddPolarHydrogens(NetworkNode):
410
411 - def __init__(self, name='Add Polar Hydrogens', **kw):
412 kw['name'] = name 413 apply( NetworkNode.__init__, (self,), kw ) 414 415 ip = self.inputPortsDescr 416 ip.append(datatype='MoleculeSet', name='molecules') 417 418 op = self.outputPortsDescr 419 op.append(datatype='MoleculeSet', name='molecules') 420 op.append(datatype='int', name='new_h_ct') 421 422 code = """def doit(self, molecules): 423 h_builder = PolarHydrogenBuilder() 424 for mol in molecules: 425 new_h_ct = h_builder.addHydrogens(mol) 426 self.outputData(molecules=molecules, new_h_ct=new_h_ct ) 427 """ 428 429 self.setFunction(code)
430 431
432 -class ParseCryst1(NetworkNode):
433
434 - def __init__(self, name='ParseCryst1', **kw):
435 kw['name'] = name 436 apply( NetworkNode.__init__, (self,), kw ) 437 438 ip = self.inputPortsDescr 439 ip.append(datatype='MoleculeSet', name='molecules') 440 441 op = self.outputPortsDescr 442 op.append(datatype='MoleculeSet', name='molecules') 443 444 code = """def doit(self, molecules): 445 for mol in molecules: 446 p = mol.parser 447 if not isinstance(p, PdbParser): 448 print 'WARNING molecule %s was not read from a PDB file'%mol.name 449 continue 450 p.parse_PDB_CRYST1( p.getRecords(p.allLines, 'CRYST1') ) 451 452 self.outputData(molecules=molecules) 453 """ 454 455 self.setFunction(code)
456 457
458 -class NodeSelector(NetworkNode):
459 """This node selects subsets of nodes (i.e. Atoms, Residues, Chains, ...) 460 from a list of incomming molecules. 461 First all nodes of the currently selected level are found, then a 462 selection operation is performed on these nodes. 463 Selection can be specified using regular expressions or lambda functions. 464 465 Example: 466 # set the level to Residue and NOTE that the port name changes :) 467 type ^G* to select all residues with names starting with a 'G' 468 type lambda x: x._uniqIndex < 10 to select the 10 first residues 469 """
470 - def setLevel(self, level):
471 if len(self.outputPorts)==0: 472 return # we got here before node is fully created 473 newlevel = self.levels[level][0] 474 if newlevel==self.level: 475 return 476 self.level = newlevel 477 p = self.outputPorts[0] 478 p.setDataType(self.levels[level][1].__name__)
479 480
481 - def __init__(self, name='Select Nodes', **kw):
482 kw['name'] = name 483 apply( NetworkNode.__init__, (self,), kw ) 484 485 #self.readOnly = 1 486 self.levels = {'Atom': (Atom, AtomSet), 487 'Residue': (Residue, ResidueSet), 488 'Chain': (Chain, ChainSet), 489 'Molecule': (Molecule, MoleculeSet) } 490 491 self.level = Atom 492 493 self.widgetDescr['selectionString'] = { 494 'class':'NEEntry', 'master':'node', 'width':14, 495 'labelGridCfg':{'sticky':'w'}, 496 'widgetGridCfg':{'sticky':'w'}, 497 'labelCfg':{'text':'select:'}, 498 } 499 500 self.widgetDescr['nodeType'] = { 501 'class':'NEComboBox', 'master':'node', 502 'choices':self.levels.keys(), 503 'fixedChoices':True, 504 'initialValue':'Atom', 505 'entryfield_entry_width':8, 506 'selectioncommand':self.setLevel, 507 'labelGridCfg':{'sticky':'w'}, 508 'widgetGridCfg':{'sticky':'w'}, 509 'labelCfg':{'text':'level:'}, 510 } 511 512 ip = self.inputPortsDescr 513 ip.append(datatype='TreeNodeSet', name='nodes') 514 ip.append(datatype='string', name='nodeType') 515 ip.append(datatype='string', required=False, name='selectionString') 516 517 op = self.outputPortsDescr 518 op.append(datatype='AtomSet', name='nodes') 519 520 code = """def doit(self, molecules, nodeType, \ 521 selectionString=None): 522 elemType, setType = self.levels[nodeType] 523 result = setType([]) 524 for mol in molecules: 525 selnodes = setType(mol.findType(elemType)) 526 if selectionString: 527 selnodes = selnodes.get(selectionString) 528 result = result + selnodes 529 if len(result): 530 result.sort() 531 self.outputData(nodes=result)\n""" 532 533 self.setFunction(code)
534
535 -class RMSDFromTwoAtomSet(NetworkNode):
536
537 - def __init__(self, name='RMSD', **kw):
538 kw['name'] = name 539 apply( NetworkNode.__init__, (self,), kw ) 540 541 ip = self.inputPortsDescr 542 ip.append(datatype='AtomSet', name='atomSet1') 543 ip.append(datatype='AtomSet', name='atomSet2') 544 545 op = self.outputPortsDescr 546 op.append(datatype='float', name='rmsd') 547 548 from mglutil.math.rmsd import RMSDCalculator 549 self.RMSD = RMSDCalculator() 550 551 code = """def doit(self, atomSet1, atomSet2): 552 if atomSet1 is None or atomSet2 is None: 553 return 554 if len(atomSet1)!=len(atomSet2): 555 return 556 557 # sort the two atomSet 558 needSorting = False 559 for i in range(len(atomSet1)): 560 if atomSet1[i].name != atomSet2[i].name: 561 needSorting = True 562 break 563 564 565 if needSorting: 566 tmp = AtomSet() 567 names = atomSet2.name 568 for atom in atomSet1: 569 try: 570 idx = names.index(atom.name) 571 tmp.append(atomSet2[idx]) 572 except: 573 print atom.name, 'not found in', atomSet2 574 mob = tmp.coords 575 else: 576 mob = atomSet2.coords 577 578 ref = atomSet1.coords 579 self.RMSD.setRefCoords(ref) 580 rmsd = self.RMSD.computeRMSD(mob) 581 582 self.outputData(rmsd=rmsd) 583 584 """ 585 586 self.setFunction(code)
587 588
589 - def beforeAddingToNetwork(self, net):
590 # import vizlib 591 importVizLib(net)
592 593
594 -class AtomsAsCPK(GeometryNode):
595
596 - def __init__(self, name='CPK', **kw):
597 kw['name'] = name 598 apply( GeometryNode.__init__, (self,'CPK'), kw ) 599 600 #self.readOnly = 1 601 602 # from DejaVu.Spheres import Spheres 603 # self.cpk = Spheres('CPK', inheritMaterial=0) 604 605 self.widgetDescr['quality'] = { 606 'class':'NEThumbWheel', 'master':'node', 607 'width':60, 'height':18, 'oneTurn':10, 608 'lockType':1, 'min':3, 'increment':1, 'type':'int', 'wheelPad':2, 609 'initialValue':8, 610 'labelCfg':{'text':'quality:'}, 611 } 612 613 ip = self.inputPortsDescr 614 ip.append(datatype='AtomSet', name='atoms') 615 616 ip.append(datatype='float(0)', required=False, name='radii') 617 #ip.append(datatype='vector', required=False, name='radii') 618 619 ip.append(datatype='colorfloat3or4(0)', required=False, name='colors') 620 ip.append(datatype='int', required=False, name='quality') 621 622 623 # for backward compatibility 624 # this make sure that the first ports in the node are the ones 625 # that use to be there before we introduced the GeometryNode class 626 # (old network were saved with port indices instead of port names) 627 self.rearrangePorts() 628 629 code = """def doit(self, atoms, radii=None, colors=None, quality=None, 630 name=None, geoms=None, instanceMatrices=None, geomOptions=None, parent=None): 631 GeometryNode.doit(self, name, geoms, instanceMatrices, geomOptions, parent) 632 if atoms is None: 633 return 634 try: 635 len(radii) 636 islist = True 637 except TypeError: 638 islist = False 639 if islist: 640 assert len(radii)==len(atoms.coords) 641 if colors is None: 642 colors = ( (0.7, 0.7, 0.7), ) 643 644 645 if self.selectedGeomIndex is not None: 646 g = self.geom() 647 if colors is not None: 648 inheritMaterial = False 649 else: 650 inheritMaterial = None 651 g.Set(vertices=atoms.coords, radii=radii, materials=colors, 652 quality=quality, inheritMaterial=inheritMaterial) 653 self.outputData(CPK=g, allGeometries=self.geoms) 654 else: 655 self.outputData(CPK=None, allGeometries=self.geoms) 656 657 """ 658 self.setFunction(code)
659 660
661 - def appendGeometry(self, name):
662 from DejaVu.Spheres import Spheres 663 self.geoms.append(Spheres(name)) 664 return 1 # num of appended geoms
665 666
667 - def beforeAddingToNetwork(self, net):
668 # import vizlib 669 importVizLib(net)
670 671
672 -class AtomsAsSticks(NetworkNode):
673
674 - def __init__(self, name='Sticks', **kw):
675 kw['name'] = name 676 apply( NetworkNode.__init__, (self,), kw ) 677 678 self.indices = None 679 680 #self.readOnly = 1 681 682 from DejaVu.Cylinders import Cylinders 683 self.sticks = Cylinders('sticks', inheritMaterial=0) 684 685 self.widgetDescr['cradii'] = { 686 'class':'NEThumbWheel', 'master':'node', 687 'width':60, 'height':18, 'wheelPad':2, 'oneTurn':1, 688 'lockType':1, 'min':0, 'increment':.1, 'type':'float', 689 'initialValue':0.25, 690 'labelCfg':{'text':'radius:'}, 691 } 692 693 ip = self.inputPortsDescr 694 ip.append(datatype='AtomSet', name='atoms') 695 ip.append(datatype='colorsRGB', required=False, name='colors') 696 ip.append(datatype='instancemat(0)', required=False, 697 name='instance matrices') 698 ip.append(datatype='float', required=False, name='cradii') 699 700 op = self.outputPortsDescr 701 op.append(datatype='geom', name='sticks') 702 703 code = """def doit(self, atoms, colors=None, instanceMatrices=None, \ 704 cradii=None): 705 if atoms is None: 706 return 707 if colors is None: 708 colors = ( (0.7, 0.7, 0.7), ) 709 710 if instanceMatrices: 711 mat = Numeric.array(instanceMatrices) 712 else: 713 mat = [Numeric.identity(4).astype('f')] 714 715 if cradii is None: 716 cradii = 0.25 717 bonds, atnobnd = atoms.bonds 718 self.indices = map(lambda x: (x.atom1._bndIndex_, 719 x.atom2._bndIndex_), bonds) 720 self.sticks.Set(vertices=atoms.coords, faces=self.indices, 721 radii=cradii, materials=colors) 722 self.sticks.Set(instanceMatrices=mat) 723 724 self.outputData(sticks=self.sticks)\n""" 725 726 self.setFunction(code)
727 728
729 - def beforeAddingToNetwork(self, net):
730 # import vizlib 731 importVizLib(net)
732 733
734 -class SESVertices(NetworkNode):
735 """Extract specific vertices from the SES surface 736 737 Input ports: 738 MSMS: an MSMSobject instance as output by the MSMS calculation node 739 nodes: a TreeNodeSet describing parts of a molecule. This will be 740 expanded to an AtomSet triangles for which at least 'selnum' 741 vertices belong to atoms in this set will be extracted. 742 If ommited, the whole surface is extracted. 743 selnum: number of vertices per triangle that need to belong to atoms 744 in nodes for a triangle to be output. 745 component: MSMS component (i.e. a closed surface) to be extracted. 746 Component 0 is always the external component. 747 ftype: can be any of 'contact', 'reentrant' or 'toric' to select only 748 vertices in this type of faces 749 vtype: can be any of 'inside', 'edge' or 'vertices' to select only 750 vertices inside contact face, on edges or vertices respectively 751 752 OutputPort: 753 vertices: array of X,Y,Z coordinates 754 vnormals: array of nx,ny,nz vertices normal vectors 755 """
756 - def __init__(self, name='gSESVertices', **kw):
757 kw['name'] = name 758 apply( NetworkNode.__init__, (self,), kw ) 759 760 self.widgetDescr['selnum'] = { 761 'class':'NEDial', 'size':50, 762 'oneTurn':3, 'min':1, 'max':3, 'lockBMax': 1, 763 'lockMin': 1, 'type':'int', 764 'initialValue':3, 765 'labelGridCfg':{'sticky':'w'}, 766 'labelCfg':{'text':'nbVert'}, 767 } 768 769 self.widgetDescr['component'] = { 770 'class':'NEDial', 'size':50, 771 'oneTurn':5, 'min':0, 'lockMin':1, 'lockMax':1, 'type':'int', 772 'initialValue':0, 773 'labelGridCfg':{'sticky':'w'}, 774 'labelCfg':{'text':'component'}, 775 } 776 777 self.widgetDescr['ftype'] = { 'class': 'NEComboBox', 778 'initialValue': 'contact', 'fixedChoices': 1, 779 'entryfield_entry_width':12, 780 'choices': ['contact', 'reentrant', 'toric'], 781 'labelGridCfg':{}, 'master': 'node', 'widgetGridCfg': {}, 782 'labelCfg': {'text': 'vtype:'}, 783 } 784 785 self.widgetDescr['vtype'] = { 'class': 'NEComboBox', 786 'initialValue': 'inside', 'fixedChoices': 1, 787 'entryfield_entry_width':12, 788 'choices': ['inside', 'edges', 'vertices'], 789 'labelGridCfg':{}, 'master': 'node', 'widgetGridCfg': {}, 790 'labelCfg': {'text': 'vtype:'}, 791 } 792 793 ip = self.inputPortsDescr 794 ip.append(datatype='MSMSobject', name='MSMS') 795 ip.append(datatype='TreeNodeSet', 796 balloon='Atoms for which triangles are extracted', 797 required=False, name='nodes') 798 ip.append(datatype='int', required=False, name='selnum') 799 ip.append(datatype='int', required=False, name='component') 800 ip.append(datatype='string', required=False, name='ftype') 801 ip.append(datatype='string', required=False, name='vtype') 802 803 op = self.outputPortsDescr 804 op.append(datatype='coordinates3D', name='SAScenters') 805 op.append(datatype='normals3D', name='normals') 806 807 808 code = """def doit(self, msms, nodes=None, selnum=3, component=0, \ 809 ftype='contact', vtype='inside'): 810 vf,vi,f = msms.getTriangles() 811 v = {} 812 n = {} 813 if ftype=='contact': faceTest=1 814 elif ftype=='reentrant': faceTest=2 815 elif ftype=='toric': faceTest=3 816 else: raise(ValueError, 'bad face type') 817 818 for fa in f: 819 if fa[3]==faceTest: 820 for i in range(3): 821 v1 = fa[i] 822 vt = vi[v1][0] 823 # pick vertices based on vtype 824 if (vtype=='inside' and vt>0) or \ 825 (vtype=='edges' and vt<0) or \ 826 (vtype=='vertices' and vt<0): 827 v[v1] = vf[v1][0:3] 828 n[v1] = vf[v1][3:6] 829 self.outputData(SAScenters=v.values()) 830 self.outputData(normals=n.values()) 831 """ 832 833 self.setFunction(code)
834 835
836 - def beforeAddingToNetwork(self, net):
837 # import vizlib 838 importVizLib(net)
839 840 from Pmv.msmsParser import MSMSParser
841 -class ReadMSMS(NetworkNode):
842 """based on the MSMSParser object. Reads an MSMS surface 843 Input: 844 filename (string), filename.vert and filename.face will be read 845 Output: 846 vertices: array of vertices 847 normals: array of normals 848 vprop: array of vertex properties (integer values) 849 tri: array of faces 850 triprop: array of face properties (integers)""" 851
852 - def __init__(self, name='Read MSMS', **kw):
853 kw['name'] = name 854 apply( NetworkNode.__init__, (self,), kw ) 855 856 fileTypes=[('msms', '*.vert')] 857 858 self.widgetDescr['filename'] = { 859 'class':'NEEntryWithFileBrowser', 'master':'node', 860 'filetypes':fileTypes, 'title':'read molecule', 'width':10, 861 'labelCfg':{'text':'file:'}, 862 } 863 864 ip = self.inputPortsDescr 865 ip.append(datatype='string', name='filename') 866 867 op = self.outputPortsDescr 868 op.append(datatype='coordinates3D', name='vertices') 869 op.append(datatype='faceIndices', name='tri') 870 op.append(datatype='normals3D', name='normals') 871 op.append(datatype='int(0,3)', name='vprop') 872 op.append(datatype='int(0,2)', name='triprop') 873 874 code = """def doit(self, filename): 875 if filename and len(filename): 876 msmsParser = MSMSParser() 877 msmsParser.parse(filename, filename[:-4]+'face') 878 self.outputData( 879 vertices=msmsParser.vertices, 880 tri=msmsParser.faces, 881 normals=msmsParser.normals, 882 vprop=msmsParser.vertProp , 883 triprop=msmsParser.facesProp)""" 884 885 self.setFunction(code)
886 887 888 try: 889 bhtreelibFound = True 890 from bhtree import bhtreelib 891
892 - class SurfaceAtoms(NetworkNode):
893 """outputs a list of atoms contributing to the MSMS serface 894 895 Input ports: 896 MSMS: an MSMSobject instance as output by the MSMS calculation node 897 nodes: a TreeNodeSet describing parts of a molecule. This will be 898 expanded to an AtomSet triangles for which at least 'selnum' 899 vertices belong to atoms in this set will be extracted. 900 If ommited, the whole surface is extracted. 901 component: MSMS component (i.e. a closed surface) to be extracted. 902 Component 0 is always the external component. 903 cut0ff: if an atom is less than cutoff away from the surface it will be 904 selected 905 906 OutputPort: 907 surfaceAtoms: AtomSet of atoms close to the surface 908 interiorAtoms: AtomSet of atoms not close to the surface 909 """
910 - def __init__(self, name='SurfaceAtoms', **kw):
911 kw['name'] = name 912 apply( NetworkNode.__init__, (self,), kw ) 913 914 self.widgetDescr['component'] = { 915 'class':'NEDial', 'size':50, 916 'oneTurn':5, 'min':0, 'lockMin':1, 'lockMax':1, 'type':'int', 917 'initialValue':0, 918 'labelGridCfg':{'sticky':'w'}, 919 'labelCfg':{'text':'component'}, 920 } 921 self.widgetDescr['cutoff'] = { 922 'class':'NEDial', 'size':50, 923 'oneTurn':5.0, 'min':0, 'lockMin':1, 'type':'float', 924 'initialValue':0.0, 925 'labelGridCfg':{'sticky':'w'}, 926 'labelCfg':{'text':'cutoff'}, 927 } 928 929 ip = self.inputPortsDescr 930 ip.append(datatype='MSMSobject', name='MSMS') 931 ip.append(datatype='TreeNodeSet', 932 balloon='Atoms for which triangles are extracted', 933 required=False, name='nodes') 934 ip.append(datatype='int', required=False, name='component') 935 ip.append(datatype='float', required=False, name='cutoff') 936 937 op = self.outputPortsDescr 938 op.append(datatype='AtomSet', name='surfaceAtoms') 939 op.append(datatype='AtomSet', name='interiorAtoms') 940 941 942 code = """def doit(self, msms, nodes=None, component=0, cutoff=0.0): 943 vf,vi,f = msms.getTriangles() 944 from mglutil.util.uniq import uniq 945 atInd = uniq(vi[:,1]) 946 atoms = msms.atoms 947 surfats ={} 948 intats = [] 949 950 if cutoff is None: cutoff=0.0 951 952 # find surface atoms 953 for n in atInd: 954 surfats[atoms[n-1]]=n-1 955 956 # find complementary set 957 for a in atoms: 958 if surfats.get(a, None) is None: 959 intats.append(a) 960 961 if cutoff!=0.0: 962 import Numeric 963 points = Numeric.array(vf[:,:3], 'f') 964 ids = Numeric.arrayrange(len(points)).astype('i') 965 result = Numeric.zeros( (len(points),) ).astype('i') 966 bht = bhtreelib.TBHTree( points, ids, 10, 10, 9999.0 ) 967 for a in intats: 968 nb = bht.ClosePoints( tuple(a.coords), cutoff, result) 969 if nb: 970 print 'atom' , a, 'is close' 971 surfats[a] = True 972 intats.remove(a) 973 974 self.outputData(surfaceAtoms=AtomSet(surfats.keys())) 975 self.outputData(interiorAtoms=AtomSet(intats)) 976 """ 977 978 self.setFunction(code)
979 980 except: 981 bhtreelibFound = False 982 983
984 -class AtomsAsMSMS(NetworkNode):
985 """Compute solvent excluded surface using the MSMS library. 986 987 Input ports: 988 atoms: a set of atoms for which to compute a surface 989 radii: optional atomic radii. If they are ommited, we tri to get them 990 from the atoms 991 seedAtoms: a list of up to 3 atoms that are used to position the rolling 992 probe initially. Can be used to compute cavity surfaces. 993 density: floating point value describing the number of vertices per 994 angstrom square used for triangulating the surface 995 probe_radius: floating point value decribing the radius of the rolling 996 probe sphere. 997 allComp: Boolean value triggering the computation of all components 998 999 OutputPort: 1000 MSMS: outputs an MSMSObject 1001 1002 The set of atoms used to calculate the surface are stored in the atoms 1003 attribute of the MSMSobject. By default, the probe_radius and the 1004 density parameters are bound to dials and allComp is bound to a check- 1005 button widget located in the parameter panel. 1006 """
1007 - def __init__(self, name='MSMS', **kw):
1008 kw['name'] = name 1009 apply( NetworkNode.