Package nMOLDYN :: Package GUI :: Module MainDialog
[hide private]
[frames] | no frames]

Source Code for Module nMOLDYN.GUI.MainDialog

  1  """This is where the main window of nMOLDYN is defined. 
  2   
  3  Classes: 
  4      * MainDialog: The class that defines the nMOLDYN GUI main window and its associated actions. 
  5  """ 
  6   
  7  # The python distribution modules. 
  8  import inspect 
  9  import os 
 10  import re 
 11  import subprocess 
 12  import sys 
 13  import webbrowser 
 14   
 15  from tkMessageBox import askyesno 
 16   
 17  # The ScientificPython modules. 
 18  from Scientific import N 
 19  from Scientific.IO.NetCDF import NetCDFFile, _NetCDFFile 
 20   
 21  # The MMTK distribution modules. 
 22  from MMTK.Trajectory import Trajectory, trajectoryInfo, TrajectorySet 
 23   
 24  from Tkinter import * 
 25  from tkFileDialog import askopenfilename 
 26   
 27  # The nMOLDYN modules. 
 28  from nMOLDYN.Analysis.Analysis import setUniverseContents 
 29  from nMOLDYN.Analysis.Dynamics import * 
 30  from nMOLDYN.Analysis.NMR import * 
 31  from nMOLDYN.Analysis.Scattering import * 
 32  from nMOLDYN.Analysis.Structure import * 
 33  from nMOLDYN.Core.Error import Error 
 34  from nMOLDYN.Core.Logger import LogMessage 
 35  from nMOLDYN.Core.Preferences import PREFERENCES 
 36   
 37  from nMOLDYN.GUI.AnalysisDialog import AnalysisDialog 
 38  from nMOLDYN.GUI.AnimationDialog import AnimationDialog 
 39  from nMOLDYN.GUI.AnalysisBenchmarkDialog import AnalysisBenchmarkDialog 
 40  from nMOLDYN.GUI.ASCIIToNetCDFConversionDialog import ASCIIToNetCDFConversionDialog 
 41  from nMOLDYN.GUI.PreferencesDialog import PreferencesDialog 
 42  from nMOLDYN.GUI.GeneralInformationsDialog import GeneralInformationsDialog 
 43  from nMOLDYN.GUI.NetCDFToASCIIConversionDialog import NetCDFToASCIIConversionDialog 
 44  from nMOLDYN.GUI.PDBSnapshotGeneratorDialog import PDBSnapshotGeneratorDialog 
 45  from nMOLDYN.GUI.PlotNetCDFVariableDialog import PlotNetCDFVariableDialog 
 46  from nMOLDYN.GUI.TrajectoryConversionDialog import * 
 47  from nMOLDYN.GUI.ViewEffectiveModeDialog import ViewEffectiveModeDialog 
 48  from nMOLDYN.GUI.Widgets import ComboText 
 49   
 50  # Package path 
 51  nmoldyn_package_path = os.path.dirname(os.path.split(__file__)[0]) 
 52   
 53  from Tkinter import * 
 54   
55 -class MainDialog(Tk):
56 """ 57 This is the base class for the nMoldyn GUI. It launches the main window of nMoldyn from which 58 different menus can be accessed. 59 """ 60
61 - def __init__(self, netcdf_filename = None):
62 """ 63 The constructor. Displays the main window. 64 65 @param netcdf_filename: a string specifying a NetCDF file, nMOLDYN should be started with. 66 @rtype: string 67 """ 68 69 Tk.__init__(self) 70 71 self.option_add('*Dialog.msg.wrapLength', '30i') 72 73 if netcdf_filename is not None: 74 netcdf_filename = os.path.abspath(netcdf_filename) 75 if os.path.exists(netcdf_filename): 76 self.netcdf_filename = netcdf_filename 77 else: 78 self.netcdf_filename = None 79 LogMessage('warning', 'The NetCDF input file %s does not exist.' % netcdf_filename, ['console']) 80 81 else: 82 self.netcdf_filename = None 83 84 self.netcdf = None 85 86 self.initial_focus = self.body(self) 87 88 self.grab_set() 89 90 self.protocol("WM_DELETE_WINDOW", self.cancel) 91 92 # Tcl/Tk specificities for MacOS platform. 93 if sys.platform == 'darwin': 94 try: 95 self.tk.call('package', 'require', 'tile') 96 self.tk.call('namespace', 'import', '-force', 'ttk::*') 97 self.tk.call('tile::setTheme', 'aqua') 98 except TclError: 99 pass 100 101 self.resizable(width = NO, height = NO) 102 103 self.title('nMOLDYN') 104 105 self.geometry("+20+20") 106 107 self.focus_set() 108 109 # Wait 1s before checking for missing program. 110 self.after(1000, self.checkConfiguration) 111 112 self.wait_window(self)
113
114 - def body(self, master):
115 116 mainMenu = Menu(master) 117 118 if sys.platform == 'darwin': 119 accel = 'Cmd-' 120 bindKey = 'Command-' 121 else: 122 accel = 'Ctrl-' 123 bindKey = 'Control-' 124 125 # #################### 126 # The 'File' Menu. 127 # #################### 128 self.fileMenu = Menu(mainMenu, tearoff = 0) 129 130 # Opens a netcdf file. 131 self.fileMenu.add_command(label = 'Load NetCDF file', command = self.loadNetCDF, accelerator = accel + 'O') 132 master.bind('<%s>' % (bindKey+'o',), self.loadNetCDF) 133 134 self.fileMenu.add_separator() 135 136 conversionMenu = Menu(self.fileMenu, tearoff = 0) 137 self.fileMenu.add_cascade(label = 'Trajectory conversion', menu = conversionMenu) 138 conversionMenu.add_command(label = 'Amber NetCDF to MMTK', command = lambda : AmberNetCDFConverterDialog(master)) 139 conversionMenu.add_command(label = 'CHARMM/X-PLOR to MMTK', command = lambda : CHARMMConverterDialog(master)) 140 conversionMenu.add_command(label = 'DL_POLY to MMTK', command = lambda : DL_POLYConverterDialog(master)) 141 142 materialsStudioMenu = Menu(conversionMenu, tearoff = 0) 143 conversionMenu.add_cascade(label = 'MaterialsStudio', menu = materialsStudioMenu) 144 materialsStudioMenu.add_command(label = 'Discover to MMTK', command = lambda : MaterialsStudioConverterDialog(master, 'Discover')) 145 materialsStudioMenu.add_command(label = 'Forcite to MMTK', command = lambda : MaterialsStudioConverterDialog(master, 'Forcite')) 146 147 conversionMenu.add_command(label = 'NAMD to MMTK', command = lambda : NAMDConverterDialog(master)) 148 conversionMenu.add_command(label = 'VASP to MMTK', command = lambda : VASPConverterDialog(master)) 149 150 # Opens a dialog to extract a selected frame from a given trajectory into a PDB file. 151 self.fileMenu.add_command(label = 'Frame snapshot', command = self.extractTrajectoryFrame, accelerator = accel + 'R') 152 master.bind('<%s>' % (bindKey+'r',), self.extractTrajectoryFrame) 153 154 self.fileMenu.add_separator() 155 156 # Opens the NetCDF to ASCII file conversion dialog. 157 self.fileMenu.add_command(label = 'Convert NetCDF to ASCII', command = self.convertNetCDFToASCII, accelerator = accel + 'U') 158 master.bind('<%s>' % (bindKey+'u',), self.convertNetCDFToASCII) 159 160 # Opens the NetCDF to ASCII file conversion dialog. 161 self.fileMenu.add_command(label = 'Convert ASCII to NetCDF', command = self.convertASCIIToNetCDF, accelerator = accel + 'I') 162 master.bind('<%s>' % (bindKey+'i',), self.convertASCIIToNetCDF) 163 164 self.fileMenu.add_separator() 165 166 # This open the configuration file editor used to set up some of the nMOLDYN environment variables. 167 self.fileMenu.add_command(label = 'Preferences', command = self.setPreferences, accelerator = accel + 'E') 168 master.bind('<%s>' % (bindKey+'e',), self.setPreferences) 169 170 self.fileMenu.add_separator() 171 172 # Close the nMOLDYN apllication. 173 self.fileMenu.add_command(label = 'Quit', command = self.cancel, accelerator = accel + 'Q') 174 master.bind('<%s>' % (bindKey+'q',), self.cancel) 175 176 # This submenu is popped up when clicking on 'File' item of the main menu. 177 mainMenu.add_cascade(label = "File", menu = self.fileMenu) 178 179 # ##################### 180 # The 'Analysis' Menu. 181 # ##################### 182 self.analysisMenu = Menu(mainMenu, tearoff = 0) 183 184 # ######################################### 185 # The 'Analysis->Dynamics' Menu. 186 # ######################################### 187 dynamicsMenu = Menu(self.analysisMenu, tearoff = 0) 188 # The contents of the 'Dynamics' submenu. 189 self.analysisMenu.add_cascade(label = 'Dynamics', menu = dynamicsMenu) 190 191 # The Mean-Square Displacement entry. 192 dynamicsMenu.add_command(label = 'Mean-Square Displacement', 193 command = lambda : self.analysisDialog(MeanSquareDisplacement)) 194 # The Root Mean Square Deviation entry. 195 dynamicsMenu.add_command(label = 'Root Mean-Square Deviation', 196 command = lambda : self.analysisDialog(RootMeanSquareDeviation)) 197 # The Gyration Radius entry. 198 dynamicsMenu.add_command(label = 'Radius Of Gyration', 199 command = lambda : self.analysisDialog(RadiusOfGyration)) 200 201 dynamicsMenu.add_command(label = 'Angular Correlation', 202 command = lambda : self.analysisDialog(AngularCorrelation)) 203 204 dynamicsMenu.add_command(label = 'Velocity AutoCorrelation Function', 205 command = lambda : self.analysisDialog(CartesianVelocityAutoCorrelationFunction)) 206 207 dynamicsMenu.add_command(label = 'Density Of States', 208 command = lambda : self.analysisDialog(CartesianDensityOfStates)) 209 210 dynamicsMenu.add_separator() 211 212 dynamicsMenu.add_command(label = 'Pass-Band Filtered Trajectory', 213 command = lambda : self.analysisDialog(PassBandFilteredTrajectory)) 214 dynamicsMenu.add_command(label = 'Global Motion Filtered Trajectory', 215 command = lambda : self.analysisDialog(GlobalMotionFilteredTrajectory)) 216 217 # The Rigid-Body Trajectory Analysis entry. 218 dynamicsMenu.add_command(label = 'Rigid-Body Trajectory', 219 command = lambda : self.analysisDialog(RigidBodyTrajectory)) 220 221 # The Center Of Mass Trajectory Analysis entry. 222 dynamicsMenu.add_command(label = 'Center Of Mass Trajectory', 223 command = lambda : self.analysisDialog(CenterOfMassTrajectory)) 224 225 dynamicsMenu.add_separator() 226 227 # The AutoRegressive Analysis entry. 228 dynamicsMenu.add_command(label = 'Auto-Regressive Analysis', 229 command = lambda : self.analysisDialog(AutoRegressiveAnalysis)) 230 231 dynamicsMenu.add_separator() 232 233 # The Quasi-Harmonic Analysis entry. 234 dynamicsMenu.add_command(label = 'Quasi-Harmonic Analysis', 235 command = lambda : self.analysisDialog(QuasiHarmonicAnalysis)) 236 237 dynamicsMenu.add_separator() 238 239 # The Reorientational Correlation Function Analysis entry. 240 dynamicsMenu.add_command(label = 'Reorientational Correlation Function', 241 command = lambda : self.analysisDialog(ReorientationalCorrelationFunction)) 242 243 # The Angular Velocity Autocorrelation Function. 244 dynamicsMenu.add_command(label = 'Angular Velocity AutoCorrelation Function', 245 command = lambda : self.analysisDialog(AngularVelocityAutoCorrelationFunction)) 246 247 248 # The Angular Density Of States. 249 dynamicsMenu.add_command(label = 'Angular Density Of States', 250 command = lambda : self.analysisDialog(AngularDensityOfStates)) 251 252 # ######################################### 253 # The 'Analysis->Scattering' Menu. 254 # ######################################### 255 scatteringMenu = Menu(self.analysisMenu, tearoff = 0) 256 # The contents of the 'Scattering' submenu. 257 self.analysisMenu.add_cascade(label = 'Scattering', menu = scatteringMenu) 258 259 # The Coherent Structure Factor Analysis entry. 260 scatteringMenu.add_command(label = 'Dynamic Coherent Structure Factor', 261 command = lambda : self.analysisDialog(DynamicCoherentStructureFactor)) 262 263 # The Coherent Structure Factor Analysis (AR Model) entry. 264 scatteringMenu.add_command(label = 'Dynamic Coherent Structure Factor (AR Model)', 265 command = lambda : self.analysisDialog(DynamicCoherentStructureFactorAR)) 266 267 scatteringMenu.add_separator() 268 269 # The Incoherent Structure Factor Analysis entry. 270 scatteringMenu.add_command(label = 'Dynamic Incoherent Structure Factor', 271 command = lambda : self.analysisDialog(DynamicIncoherentStructureFactor)) 272 273 # The Incoherent Structure Factor (AR Model) Analysis entry. 274 scatteringMenu.add_command(label = 'Dynamic Incoherent Structure Factor (AR Model)', 275 command = lambda : self.analysisDialog(DynamicIncoherentStructureFactorAR)) 276 277 # The Incoherent Structure Factor (Gaussian approximation) Analysis entry. 278 scatteringMenu.add_command(label = 'Dynamic Incoherent Structure Factor (Gaussian Approximation)', 279 command = lambda : self.analysisDialog(DynamicIncoherentStructureFactorGaussian)) 280 281 scatteringMenu.add_separator() 282 283 # The Elastic Incoherent Structure Factor Analysis entry. 284 scatteringMenu.add_command(label = 'Elastic Incoherent Structure Factor', 285 command = lambda : self.analysisDialog(ElasticIncoherentStructureFactor)) 286 287 scatteringMenu.add_separator() 288 289 # The Static Incoherent Structure Factor Analysis entry. 290 scatteringMenu.add_command(label = 'Static Coherent Structure Factor', 291 command = lambda : self.analysisDialog(StaticCoherentStructureFactor)) 292 293 # The Static Coherent Structure Factor Analysis entry. 294 scatteringMenu.add_command(label = 'Smoothed Static Coherent Structure Factor', 295 command = lambda : self.analysisDialog(SmoothedStaticCoherentStructureFactor)) 296 297 # ######################################### 298 # The 'Analysis->Structure' Menu. 299 # ######################################### 300 structureMenu = Menu(self.analysisMenu, tearoff = 0) 301 # The contents of the 'Structure' submenu. 302 self.analysisMenu.add_cascade(label = 'Structure', menu = structureMenu) 303 304 # The Pair Distribution Function Analysis entry. 305 structureMenu.add_command(label = 'Pair Distribution Function', 306 command = lambda : self.analysisDialog(PairDistributionFunction)) 307 308 # The Coordination Number Analysis entry. 309 structureMenu.add_command(label = 'Coordination Number', 310 command = lambda : self.analysisDialog(CoordinationNumber)) 311 312 # The Coordination Number Analysis entry. 313 structureMenu.add_command(label = 'Spatial Density', 314 command = lambda : self.analysisDialog(SpatialDensity)) 315 316 structureMenu.add_separator() 317 318 # The Screw fit Analysis entry. 319 structureMenu.add_command(label = 'ScrewFit Analysis', 320 command = lambda : self.analysisDialog(ScrewFitAnalysis)) 321 322 # ######################################### 323 # The 'Analysis->NMR' Menu. 324 # ######################################### 325 nmrMenu = Menu(self.analysisMenu, tearoff = 0) 326 # The contents of the 'NMR' submenu. 327 self.analysisMenu.add_cascade(label = 'NMR', menu = nmrMenu) 328 329 # The P2 Order Parameter Analysis entry. 330 nmrMenu.add_command(label = 'Order Parameter', command = lambda : self.analysisDialog(OrderParameter)) 331 332 # The S2 Order Parameter Analysis entry. 333 nmrMenu.add_command(label = 'Order Parameter (Contact Model)', command = lambda : self.analysisDialog(OrderParameterContactModel)) 334 335 # This submenu is popped up when clicking on |Analysis| item of the main menu. 336 mainMenu.add_cascade(label = "Analysis", menu = self.analysisMenu) 337 338 self.analysisMenu.entryconfig(0, state = DISABLED) 339 self.analysisMenu.entryconfig(1, state = DISABLED) 340 self.analysisMenu.entryconfig(2, state = DISABLED) 341 self.analysisMenu.entryconfig(3, state = DISABLED) 342 343 # ##################### 344 # The 'View' Menu. 345 # ##################### 346 self.viewMenu = Menu(mainMenu, tearoff = 0) 347 348 # The 'Plot' entry. Launches the plot dialog for NetCDF file plotting. 349 self.viewMenu.add_command(label = 'Plot', command = self.plotNetCDF, accelerator = accel + 'L') 350 master.bind('<%s>' % (bindKey+'l',), self.plotNetCDF) 351 352 # The 'Animation' entry. Launches the Animation dialog. 353 self.viewMenu.add_command(label = 'Animation', command = self.animateTrajectory, accelerator = accel + 'M') 354 master.bind('<%s>' % (bindKey+'m',), self.animateTrajectory) 355 356 # The 'View Effective mode'. Launches the effective mode viewer dialog. 357 self.viewMenu.add_command(label = 'Effective mode', command = self.viewEffectiveMode, accelerator = accel + 'K') 358 master.bind('<%s>' % (bindKey+'k',), self.viewEffectiveMode) 359 360 # This submenu is popped up when clicking on |View| item of the main menu. 361 mainMenu.add_cascade(label = "View", menu = self.viewMenu) 362 363 # ##################### 364 # The 'Help' Menu. 365 # ##################### 366 self.helpMenu = Menu(mainMenu, tearoff = 0) 367 368 # This is the item 'nMOLDYN users guide'. Clicking on itopen the nMOLDYN users guide pdf file. 369 self.helpMenu.add_command(label = "Documentation", command = self.displayDocumentation, accelerator = accel + 'H') 370 master.bind('<%s>' % (bindKey+'h',), self.displayDocumentation) 371 372 # This is the item 'nMOLDYN mailig list'. 373 self.helpMenu.add_command(label = "Mailing List", command = self.displayMailingList) 374 375 # This is the item 'Technical notes'. Clicking on it opens the nMOLDYN API html files. 376 self.helpMenu.add_command(label = 'API', command = self.displayAPI, accelerator = accel + 'T') 377 master.bind('<%s>' % (bindKey+'t',), self.displayAPI) 378 379 self.helpMenu.add_separator() 380 381 # This is the item 'Check job status'. Launches a toplevel window where the march 382 # of the running jobs is displayed. 383 # self.helpMenu.add_command(label = 'Trace analysis', command = self.traceAnalysis, accelerator = accel + 'J') 384 # master.bind('<%s>' % (bindKey+'j',), self.traceAnalysis) 385 386 # This is the item 'nMOLDYN benchmark'. Launches a toplevel window where the user can perform some analysis 387 # benchmarks. 388 self.helpMenu.add_command(label = 'Analysis benchmark', command = self.analysisBenchmark) 389 390 self.helpMenu.add_separator() 391 392 # This is the item 'About nMOLDYN'. 393 # Clicking on it pops up a toplevel window containing some general informations about nMOLDYN. 394 self.helpMenu.add_command(label = 'About nMOLDYN', command = self.aboutNMOLDYN, accelerator = accel + 'B') 395 master.bind('<%s>' % (bindKey+'b',), self.aboutNMOLDYN) 396 397 # This submenu is popped up when clicking on |Help| item of the main menu. 398 mainMenu.add_cascade(label = "Help", menu = self.helpMenu) 399 400 # Displays the menu 401 master.config(menu = mainMenu) 402 403 mainPanel = Frame(master) 404 mainPanel.grid(row = 0, column = 0) 405 406 # Display of an image of a neutron on the left side of the main window. 407 self.neutronGIF = PhotoImage(file = os.path.join(nmoldyn_package_path, 'GUI', 'Images', 'Neutron.gif')) 408 409 leftFrame = Frame(mainPanel) 410 leftFrame.grid(row = 0, column = 0) 411 Label(leftFrame, image = self.neutronGIF).grid(row = 0) 412 Label(leftFrame, image = self.neutronGIF).grid(row = 1) 413 Label(leftFrame, image = self.neutronGIF).grid(row = 2) 414 Label(leftFrame, image = self.neutronGIF).grid(row = 3) 415 Label(leftFrame, image = self.neutronGIF).grid(row = 4) 416 417 self.info = ComboText(mainPanel) 418 self.info.config({'width' : 500, 'relief' : SUNKEN}) 419 self.info.text.config({'wrap' : WORD, 'width' : 80}) 420 self.info.grid(row = 0, column = 1, sticky = "NSEW") 421 422 self.info.text.tag_config('12', font = ('Courier', 12)) 423 self.info.text.tag_config('12B', font = ('Courier', 12, 'bold')) 424 self.info.text.tag_config('r12B', foreground = 'red', font = ('Courier', 12, 'bold')) 425 self.info.text.tag_config('12I', font = ('Courier', 12, 'normal', 'italic')) 426 427 # Display of an image of a protein on the left side of the main window. 428 self.proteinGIF = PhotoImage(file = os.path.join(nmoldyn_package_path, 'GUI', 'Images', 'Protein.gif')) 429 rightFrame = Frame(mainPanel) 430 rightFrame.grid(row = 0, column = 2) 431 Label(rightFrame, image = self.proteinGIF).grid(row = 0) 432 Label(rightFrame, image = self.proteinGIF).grid(row = 1) 433 Label(rightFrame, image = self.proteinGIF).grid(row = 2) 434 Label(rightFrame, image = self.proteinGIF).grid(row = 3) 435 Label(rightFrame, image = self.proteinGIF).grid(row = 4) 436 437 mainPanel.grid_rowconfigure(0, weight = 1) 438 self.info.grid_rowconfigure(0, weight = 1) 439 self.info.text.grid_rowconfigure(0, weight = 1) 440 441 if self.netcdf_filename is not None: 442 self.loadNetCDF(filename = self.netcdf_filename) 443 444 return None
445
446 - def cancel(self, event = None):
447 self.destroy() 448 sys.exit(0)
449
450 - def loadNetCDF(self, event = None, filename = None):
451 """ 452 This method is launched when the user clicks on the |Load NetCDF| of the |File| menu. 453 It loads the NetCDF file and displays its main informations in the information window. 454 """ 455 456 if filename is None: 457 # A file dialog box is opened for browsing the 'nc' or 'ncs' files. 458 # A 'ncs' file is a text file with the names of several 'nc' files. 459 filename = askopenfilename(filetypes = [("NetCDF trajectory file", "*.nc"),], title = "Open NetCDF", 460 initialdir = PREFERENCES.trajfile_path) 461 462 # Do nothing if no trajectory has been selected. 463 if not filename: 464 return 465 466 # The information window is cleaned up. 467 self.info.cleanup() 468 469 # The information window is cleaned up. 470 self.info.cleanup() 471 472 # The extension of the loaded file. 473 ext = os.path.splitext(filename)[1] 474 475 try: 476 if ext == '.ncs': 477 # Open the ncs file as a trajectory set. 478 try: 479 # The trajectory set is opened for reading and its contents sent to |trajSet| list. 480 trajSetFile = open(filename, 'r') 481 trajSet = [t.strip() for t in trajSetFile.readlines()] 482 trajSetFile.close() 483 484 # Load the whole trajectory set. 485 self.netcdf = TrajectorySet(None, trajSet) 486 487 # A new MMTK TrajectorySet class attribute is created in the case of a MMTK trajectory object coming from a trajectory set. 488 setattr(self.netcdf, 'filename', trajSet[0]) 489 self.netcdf_filename = os.path.abspath(trajSet[0]) 490 491 except IOError: 492 raise 493 494 else: 495 # First try to load the file as a trajectory. 496 try: 497 # Load the input trajectory. 498 self.netcdf_filename = os.path.abspath(filename) 499 self.netcdf = Trajectory(None, filename, 'r') 500 501 except: 502 try: 503 self.netcdf_filename = os.path.abspath(filename) 504 self.netcdf = NetCDFFile(filename, 'r') 505 except: 506 raise 507 508 except: 509 self.netcdf_filename = None 510 self.netcdf = None 511 # The information window is cleaned up. 512 self.info.cleanup() 513 raise Error('The file %s is not a valid NetCDF file.' % filename) 514 515 if isinstance(self.netcdf,Trajectory): 516 517 # Detects the occurence of chemical fragments or atoms in the whole universe and indicates whether they are deuterable or not. 518 setUniverseContents(self.netcdf.universe) 519 520 if hasattr(self.netcdf,'time'): 521 if self.netcdf.time[1] == self.netcdf.time[0]: 522 firstStep = 0.0 523 lastStep = float(len(self.netcdf)) 524 timeStep = 1.0 525 LogMessage('warning', 'No or uncorrect times found in the trajectory. Will create an arbitrary \ 526 one from 0 to %d ps.' % lastStep) 527 528 else: 529 timeStep = self.netcdf.time[1] - self.netcdf.time[0] 530 firstStep = self.netcdf.time[0] 531 lastStep = self.netcdf.time[-1] 532 533 else: 534 firstStep = 0.0 535 lastStep = float(len(self.netcdf)) 536 timeStep = 1.0 537 538 self.info.insert(contents = 'FILE TYPE: MMTK NETCDF TRAJECTORY FILE\n\n', tag = '12B') 539 540 # Some trajectory informations are displayed on the information window. 541 self.info.insert(contents = trajectoryInfo(self.netcdf_filename), tag = '12B') 542 self.info.insert(contents = '\n\nMMTK objects found in the universe: ', tag = '12') 543 544 # Write into the info panel the details about the nmoldyn names found in the universe of the loaded trajectory. 545 for k in sorted(self.netcdf.universe.nmoldyncontents.keys()): 546 # Do not consider the '*' nmoldyn name. Not interesting. 547 if k == '*': 548 continue 549 self.info.insert(contents = '\n\t- %d %s (%s)' % (self.netcdf.universe.nmoldyncontents[k]['number'],k, self.netcdf.universe.nmoldyncontents[k]['objectclass']), tag = '12') 550 551 self.info.insert(contents = '\n\nNumber of frames: ', tag = '12') 552 self.info.insert(contents = str(len(self.netcdf)), tag = '12B') 553 self.info.insert(contents = '\nStarting at: ', tag = '12') 554 self.info.insert(contents = str(round(firstStep,3)) +' ps', tag = '12B') 555 self.info.insert(contents = '\nEnding at: ', tag = '12') 556 self.info.insert(contents = str(round(lastStep,3)) +' ps', tag = '12B') 557 self.info.insert(contents = '\nTime step: ', tag = '12') 558 self.info.insert(contents = str(round(timeStep,3)) +' ps', tag = '12B') 559 self.info.insert(contents = '\n\nUniverse size: ', tag = '12') 560 self.info.insert(contents = str(len(self.netcdf.universe.atomList())), tag = '12B') 561 self.info.insert(contents = '\n\nUniverse topology: ', tag = '12') 562 self.info.insert(contents = self.netcdf.universe.__class__.__name__, tag = '12B') 563 564 directBasis = self.netcdf.universe.basisVectors() 565 if directBasis is not None: 566 self.info.insert(contents = '\n\nDirect basis:', tag = '12') 567 self.info.insert(contents = '\n%8s\t%8s\t%8s' % tuple(['i','j','k']), tag = '12I') 568 for directVector in directBasis: 569 self.info.insert(contents = '\n%8.3f\t%8.3f\t%8.3f' % tuple(directVector), tag = '12I') 570 571 reciprocalBasis = self.netcdf.universe.reciprocalBasisVectors() 572 if reciprocalBasis is not None: 573 self.info.insert(contents = '\n\nReciprocal basis:', tag = '12') 574 self.info.insert(contents = '\n%8s\t%8s\t%8s' % tuple(['i','j','k']), tag = '12I') 575 for reciprocalVector in reciprocalBasis: 576 self.info.insert(contents = '\n%8.3f\t%8.3f\t%8.3f' % tuple(reciprocalVector), tag = '12I') 577 578 # These onglets are avaialble only if the NetCDF is a trajectory. 579 self.analysisMenu.entryconfig(0, state = NORMAL) 580 self.analysisMenu.entryconfig(1, state = NORMAL) 581 self.analysisMenu.entryconfig(2, state = NORMAL) 582 self.analysisMenu.entryconfig(3, state = NORMAL) 583 584 elif isinstance(self.netcdf, _NetCDFFile): 585 586 self.analysisMenu.entryconfig(0, state = DISABLED) 587 self.analysisMenu.entryconfig(1, state = DISABLED) 588 self.analysisMenu.entryconfig(2, state = DISABLED) 589 self.analysisMenu.entryconfig(3, state = DISABLED) 590 591 self.info.insert(contents = 'FILE TYPE: NETCDF FILE\n\n', tag = '12B') 592 593 # The list of the NetCDF string attributes that can be visualized to get informations about the loaded NetCDF file. 594 # The list is initialized with the first one that should appear if present in the NetCDF file. 595 netCDFStringAttributes = ['title', 'history', 'comment', 'jobinfo', 'jobinput'] 596 for attr in inspect.getmembers(self.netcdf): 597 if isinstance(attr[1], str) & (attr[0] not in netCDFStringAttributes): 598 netCDFStringAttributes.append(attr[0]) 599 600 self.info.insert(contents = 'Information about NetCDF file:\n', tag = '12B') 601 self.info.insert(contents = '%s.\n\n' % filename, tag = '12') 602 603 # Loop over the netcdf file string attributes that will be displayed for information purpose. 604 for h in netCDFStringAttributes: 605 # Checks that the NetCDF has this attributes. 606 if hasattr(self.netcdf,h): 607 self.info.insert(contents = '%s:\n' % h.capitalize(), tag = '12B') 608 self.info.insert(contents = getattr(self.netcdf,h)+ '\n\n', tag = '12') 609 610 if hasattr(self.netcdf, 'dimensions'): 611 self.info.insert(contents = '\n\nNetCDF dimensions found:', tag = '12B') 612 for d in self.netcdf.dimensions.items(): 613 self.info.insert(contents = '\n\n\t-%s ----> ' % d[0], tag = '12') 614 self.info.insert(contents = '%s' % d[1], tag = 'r12B') 615 616 if hasattr(self.netcdf, 'variables'): 617 self.info.insert(contents = '\n\nNetCDF variables found:', tag = '12B') 618 for v in self.netcdf.variables.items(): 619 self.info.insert(contents = '\n\n\t-%s:' % v[0], tag = '12B') 620 self.info.insert(contents = '\n\t\t+ Dimension(s) ----> ', tag = '12') 621 self.info.insert(contents = str(v[1].shape), tag = 'r12B') 622 if hasattr(v[1], 'typecode'): 623 self.info.insert(contents = '\n\t\t+ Typecode ----> ', tag = '12') 624 self.info.insert(contents = v[1].typecode(), tag = 'r12B') 625 else: 626 self.info.insert(contents = '\n\t\t+ Typecode ----> ', tag = '12') 627 self.info.insert(contents = 'Undefined', tag = 'r12B') 628 629 if hasattr(v[1], 'units'): 630 self.info.insert(contents = '\n\t\t+ Units ----> ', tag = '12') 631 self.info.insert(contents = v[1].units, tag = 'r12B') 632 else: 633 self.info.insert(contents = '\n\t\t+ Units ----> ', tag = '12') 634 self.info.insert(contents = 'Undefined', tag = 'r12B') 635 636 try: 637 if v[1].typecode() == N.Character: 638 continue 639 640 if len(v[1].getValue().shape) > 2: 641 raise 642 643 mini = min(v[1].getValue().ravel()) 644 maxi = max(v[1].getValue().ravel()) 645 646 except: 647 continue 648 649 else: 650 self.info.insert(contents = '\n\t\t+ Range ----> ', tag = '12') 651 self.info.insert(contents = '%.5f to %.5f' % (mini, maxi), tag = 'r12B') 652 653 else: 654 self.netcdf = None
655
656 - def extractTrajectoryFrame(self, event = None):
657 """ 658 This method pops up a dialog from where the user can extract a PDB file from a NetCDF 659 trajectory frame. 660 """ 661 662 PDBSnapshotGeneratorDialog(self, 'PDB frame extraction', self.netcdf)
663
664 - def convertNetCDFToASCII(self, event = None):
665 """ 666 This method pops up a dialog where the user can proceed to a conversion from a file in NetCDF format 667 to ASCII format. 668 """ 669 670 NetCDFToASCIIConversionDialog(self, 'NetCDF to ASCII conversion', self.netcdf)
671
672 - def convertASCIIToNetCDF(self, event = None):
673 """ 674 This method pops up a dialog where the user can proceed to a conversion from a file in ASCII format 675 to NetCDF format. 676 """ 677 678 ASCIIToNetCDFConversionDialog(self, 'ASCII/CDL to NetCDF conversion')
679
680 - def checkConfiguration(self):
681 """ 682 This method checks for missing external programs and display some warning if it found some. 683 """ 684 685 if os.path.exists(PREFERENCES.ncdump_path): 686 self.fileMenu.entryconfig(5, state = NORMAL) 687 688 else: 689 self.fileMenu.entryconfig(5, state = DISABLED) 690 if PREFERENCES.warning_ncdump.lower() == 'yes': 691 q = askyesno(title = 'Warning', message = 'The path to "ncdump" program has not been set.\n\n\ 692 It will not be possible to convert files in NetCDF format to ASCII/CDL format.\n\ 693 You should set that path in the "Preferences"-->"ncdump_path" section.\n\n\ 694 Show this warning next time nMOLDYN starts ?') 695 if q: 696 setattr(PREFERENCES, 'warning_ncdump', 'yes') 697 else: 698 setattr(PREFERENCES, 'warning_ncdump', 'no') 699 700 if os.path.exists(PREFERENCES.ncgen_path): 701 self.fileMenu.entryconfig(6, state = NORMAL) 702 703 else: 704 self.fileMenu.entryconfig(6, state = DISABLED) 705 if PREFERENCES.warning_ncgen.lower() == 'yes': 706 q = askyesno(title = 'Warning', message = 'The path to "ncgen" program has not been set.\n\n\ 707 It will not be possible to convert files in ASCII/CDL fomat to NetCDF format.\n\ 708 You should set that path in the "Preferences"-->"ncgen_path" section.\n\n\ 709 Show this warning next time nMOLDYN starts ?') 710 if q: 711 setattr(PREFERENCES, 'warning_ncgen', 'yes') 712 else: 713 setattr(PREFERENCES, 'warning_ncgen', 'no') 714 715 if (sys.platform[:5] == 'linux') & (PREFERENCES.documentation_style.lower() == 'pdf'): 716 if os.path.exists(PREFERENCES.acroread_path): 717 self.helpMenu.entryconfig(0, state = NORMAL) 718 719 else: 720 self.helpMenu.entryconfig(0, state = DISABLED) 721 if PREFERENCES.warning_acroread.lower() == 'yes': 722 q = askyesno(title = 'Warning', message = 'The path to acrobat reader has not been set.\n\n\ 723 It will not be possible to read the documentation in PDF format.\n\ 724 You should set that path in the "Preferences"-->"acroread_path" section.\n\n\ 725 Show this warning next time nMOLDYN starts ?') 726 if q: 727 setattr(PREFERENCES, 'warning_acroread', 'yes') 728 else: 729 setattr(PREFERENCES, 'warning_acroread', 'no') 730 731 if os.path.exists(PREFERENCES.vmd_path): 732 self.viewMenu.entryconfig(1, state = NORMAL) 733 self.viewMenu.entryconfig(2, state = NORMAL) 734 735 else: 736 self.viewMenu.entryconfig(1, state = DISABLED) 737 self.viewMenu.entryconfig(2, state = DISABLED) 738 if PREFERENCES.warning_vmd.lower() == 'yes': 739 q = askyesno(title = 'Warning', message = 'The path to "vmd" program has not been set.\n\n\ 740 It will not be possible to visualize any trajectory in nMOLDYN.\n\ 741 You should set that path in the "Preferences"-->"vmd_path" section.\n\n\ 742 Show this warning next time nMOLDYN starts ?') 743 if q: 744 setattr(PREFERENCES, 'warning_vmd', 'yes') 745 else: 746 setattr(PREFERENCES, 'warning_vmd', 'no')
747
748 - def setPreferences(self, event = None):
749 """ 750 This method pops up a dialog from where the user can edit the nMOLDYN configuration file. 751 """ 752 753 PreferencesDialog(self, 'Preferences') 754 755 self.checkConfiguration()
756
757 - def analysisDialog(self, analysis):
758 """ 759 """ 760 761 AnalysisDialog(self, analysis, self.netcdf)
762
763 - def plotNetCDF(self, event = None):
764 """ 765 This method pops up a dialog from where the user can display any numeric 2D or 3D NetCDF variables. 766 """ 767 768 PlotNetCDFVariableDialog(self, 'Plot NetCDF', self.netcdf)
769
770 - def animateTrajectory(self, event = None):
771 """ 772 This method pops up a dialog from where the user can animate a trajectory. If a trajectory has been loaded 773 for analysis this will be the default one. Otherwise the user can still browse one from the dialog. 774 The animation requires VMD. 775 """ 776 777 AnimationDialog(self, 'Trajectory animation', self.netcdf)
778
779 - def viewEffectiveMode(self, event = None):
780 """ 781 This method pops up a dialog from where the user can animate an effective mode coming from a QHA 782 analysis. 783 The animation require VMD. 784 """ 785 786 ViewEffectiveModeDialog(self, 'Effective mode viewer')
787
788 - def traceAnalysis(self, event = None):
789 """ 790 This method pops up a dialog from where the user can check the march of the running jobs. 791 The dialog can be updated dynamically by pressing its button 'refresh'. 792 """ 793 794 CheckJobsStatusDialog(self, 'Job progress')
795
796 - def analysisBenchmark(self):
797 """ 798 This method pops up a dialog from where the user can perform some analysis benchmark. The benchmark is 799 done between the current version and a reference version that is the version 2.2.5 the last official release 800 of nMOLDYN. 801 """ 802 803 AnalysisBenchmarkDialog(self, 'Analysis benchmark')
804
805 - def displayDocumentation(self, event = None):
806 """ 807 This methode opens the nMOLDYN pdf users guide. 808 The users guide was written by E. Pellegrini, V. Calandrini, P. Calligari, K. Hinsen and G.R. Kneller. 809 """ 810 811 if PREFERENCES.documentation_style.lower() == 'html': 812 webbrowser.open(os.path.join(nmoldyn_package_path, 'Doc', 'UsersGuide', 'HTML', 'index.html')) 813 814 elif PREFERENCES.documentation_style.lower() == 'pdf': 815 # The name of the users guide pdf file. 816 pdfFile = os.path.join(nmoldyn_package_path, 'Doc', 'UsersGuide', 'PDF', 'nMOLDYN_ug.pdf') 817 818 # Case of Win32 819 if sys.platform == 'win32': 820 os.startfile(pdfFile) 821 822 # Case of MacOS 823 elif sys.platform == 'darwin': 824 subprocess.call(['open', pdfFile]) 825 826 else: 827 828 try: 829 subprocess.call([PREFERENCES.acroread_path, pdfFile]) 830 except: 831 raise Error('Unable to read the file %s\nwith the acrobat reader located in %s.' % (pdfFile, PREFERENCES.acroread_path)) 832 else: 833 raise Error('Unknow documentation format: %s.' % PREFERENCES.documentations_style)
834
835 - def displayMailingList(self):
836 """ 837 This methode opens the nMOLDYN mailing list. 838 """ 839 840 webbrowser.open('http://sourcesup.cru.fr/forum/?group_id=194')
841
842 - def displayAPI(self, event = None):
843 844 if PREFERENCES.documentation_style.lower() == 'html': 845 webbrowser.open(os.path.join(nmoldyn_package_path, 'Doc', 'API', 'HTML', 'index.html')) 846 847 elif PREFERENCES.documentation_style.lower() == 'pdf': 848 # The name of the users guide pdf file. 849 pdfFile = os.path.join(nmoldyn_package_path, 'Doc', 'API', 'PDF', 'api.pdf') 850 851 # Case of Win32 852 if sys.platform == 'win32': 853 os.startfile(pdfFile) 854 855 # Case of MacOS 856 elif sys.platform == 'darwin': 857 subprocess.call(['open', pdfFile]) 858 859 else: 860 861 try: 862 subprocess.call([PREFERENCES.acroread_path, pdfFile]) 863 except: 864 raise Error('Unable to read the file %s\nwith the acrobat reader located in %s.' % (pdfFile, PREFERENCES.acroread_path)) 865 866 else: 867 raise Error('Unknow documentation format: %s.' % PREFERENCES.documentations_style)
868
869 - def aboutNMOLDYN(self, event = None):
870 """ 871 This method displays general informations about the program such as the developper, the main versions ... 872 """ 873 874 GeneralInformationsDialog(self, 'About nMOLDYN')
875