1 """This modules implements I{Analysis-->selected analysis} dialog.
2
3 Classes:
4 * AnalysisDialog: creates I{Analysis-->selected analysis} dialog used to setup and/orrun
5 an analysis.
6 """
7
8
9 import os
10 import sys
11
12
13 from Tkinter import *
14 from tkMessageBox import askyesno
15
16
17 from MMTK.Trajectory import Trajectory
18
19
20 import nMOLDYN
21 from nMOLDYN.Analysis.Template import *
22 from nMOLDYN.Core.Error import Error
23 from nMOLDYN.Core.Logger import LogMessage
24 from nMOLDYN.Core.Preferences import PREFERENCES
25 from nMOLDYN.GUI.PlotNetCDFVariableDialog import PlotNetCDFVariableDialog
26 from nMOLDYN.GUI.PyroServerDialog import PyroServerDialog
27 from nMOLDYN.GUI.SelectionDialog import SelectionDialog
28 from nMOLDYN.GUI.Widgets import *
29
31 """Builds the dialog for nMOLDYN analysis.
32 """
33
34 - def __init__(self, parent, analysis, trajectory):
35 """The constructor.
36
37 @param parent: the parent widget.
38
39 @param analysis: the analysis to setup.
40 @type analysis: a class object of one of the nMOLDYN.Analysis subclasses.
41
42 @param trajectory: the loaded trajectory.
43 @type trajectory: instance of MMTK.Trajectory.Trajectory class
44 """
45
46 Toplevel.__init__(self, parent)
47 self.transient(parent)
48
49 self.parent = parent
50 self.analysis = analysis
51 self.actualAnalysis = None
52 if isinstance(trajectory, Trajectory):
53 self.trajectory = trajectory
54
55 else:
56 return
57
58 self.title(self.analysis.__name__)
59
60 statusFrame = LabelFrame(self, text = 'Job status', relief = GROOVE, bd = 2)
61 self.statusBar = StatusBar(statusFrame)
62
63 body = Frame(self)
64 self.initial_focus = self.body(body)
65 body.grid(row = 0, column = 0, sticky = EW)
66
67 self.buttonbox()
68
69 statusFrame.grid(row = 2, padx = 3, pady = 3, sticky = EW)
70 statusFrame.grid_columnconfigure(0, weight = 1)
71
72 self.statusBar.grid(row = 0, column = 0)
73
74 self.grab_set()
75
76 if not self.initial_focus:
77 self.initial_focus = self
78
79 self.protocol("WM_DELETE_WINDOW", self.cancel)
80
81 self.resizable(width = NO, height = NO)
82
83 self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
84
85 self.initial_focus.focus_set()
86
87 self.wait_window(self)
88
89 - def body(self, master):
90 """Create dialog body. Return widget that should have initial focus.
91 """
92
93
94 widgetsFrame = LabelFrame(master, text = 'Setup', bd = 2, relief = GROOVE)
95 widgetsFrame.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = EW)
96 widgetsFrame.grid_columnconfigure(0, weight = 1)
97
98 self.widgets = {}
99
100 for widget in self.analysis.inputParametersNames:
101 widget = widget.lower()
102
103 if widget == 'armodelorder':
104 self.widgets[widget] = ComboIntegerEntry(widgetsFrame,\
105 frameLabel = "Model order", \
106 tagName = 'model_order',\
107 contents = 50)
108
109 elif widget == 'atomorder':
110 self.widgets[widget] = ComboStringEntry(widgetsFrame, \
111 frameLabel = "Atom order",\
112 tagName = 'atom_order',\
113 contents = "no")
114
115 elif widget == 'bond':
116 self.widgets[widget] = ComboButton(widgetsFrame,\
117 frameLabel = "Bond selection",\
118 tagName = 'bond_selection',\
119 contents = "Select",\
120 withEntry = 'all',\
121 command = lambda : SelectionDialog(self, 'bond', self.trajectory.universe.nmoldyncontents))
122
123 elif widget == 'deuteration':
124 self.widgets[widget] = ComboButton(widgetsFrame,\
125 frameLabel = "Deuteration selection",\
126 tagName = 'deuteration_selection',\
127 contents = "Select",\
128 withEntry = 'no',\
129 command = lambda : SelectionDialog(self, 'deuteration', self.trajectory.universe.nmoldyncontents))
130
131 elif widget == 'differentiation':
132 if 'velocities' in self.trajectory.variables():
133 diffOrder = (0,1,2,3,4,5)
134 else:
135 diffOrder = (1,2,3,4,5)
136 self.widgets[widget] = ComboSpinbox(widgetsFrame,\
137 frameLabel = "Differentiation order",\
138 tagName = 'differentiation_order',\
139 contents = diffOrder)
140
141 elif widget == 'fftwindow':
142 self.widgets[widget] = ComboFloatEntry(widgetsFrame,\
143 frameLabel = "FFT window (% of trajectory length)",\
144 tagName = 'fft_window',\
145 contents = 10.0)
146
147 elif widget == 'filter':
148 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
149 frameLabel = "Pass-Band filter (in tHz)",\
150 tagName = 'pass_band_filer',\
151 contents = "0.0:1000.0")
152
153 elif widget == 'group':
154 self.widgets[widget] = ComboButton(widgetsFrame,\
155 frameLabel = "Group selection",\
156 tagName = 'group_selection',\
157 contents = "Select",\
158 withEntry = 'all',\
159 command = lambda : SelectionDialog(self, 'group', self.trajectory.universe.nmoldyncontents))
160
161 elif widget == 'normalize':
162 self.widgets[widget] = ComboCheckbutton(widgetsFrame,\
163 frameLabel = "Normalize",\
164 tagName = 'normalize',\
165 onvalue = "yes",\
166 offvalue = "no")
167
168 elif widget == 'phivalues':
169 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
170 frameLabel = "Phi values (in deg)",\
171 tagName = 'phi_values',\
172 contents = "-180.0:180.0:10.0")
173
174 elif widget == 'projection':
175 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
176 frameLabel = "Project displacement on",\
177 tagName = 'project_displacement_on',\
178 contents = "no")
179
180 elif widget == 'pyroserver':
181 self.widgets[widget] = ComboButton(widgetsFrame,\
182 frameLabel = "Pyro server",\
183 tagName = 'pyro_server',\
184 contents = "Select",\
185 withEntry = 'monoprocessor',\
186 command = lambda : PyroServerDialog(self))
187
188 elif widget == 'qshellvalues':
189 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
190 frameLabel = "Q values (in nm-1)",\
191 tagName = 'qshell_values',\
192 contents = "0.0:100.0:1.0")
193
194 elif widget == 'qshellwidth':
195 self.widgets[widget] = ComboFloatEntry(widgetsFrame,\
196 frameLabel = "Q shell width (in nm-1)",\
197 tagName = 'qshell_width',\
198 contents = 1.0)
199
200 elif widget == 'qvectorsdirection':
201 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
202 frameLabel = "Q vectors direction",\
203 tagName = 'qvectors_direction',\
204 contents = "no")
205
206 elif widget == 'qvectorsgenerator':
207 self.widgets[widget] = ComboRadiobutton(widgetsFrame,\
208 frameLabel = "Q vectors generator",\
209 tagName = 'qvectors_generator',\
210 contents = ["3D isotropic", "2D isotropic", "anisotropic"],\
211 layout = (1,3))
212
213 elif widget == 'qvectorspershell':
214 self.widgets[widget] = ComboIntegerEntry(widgetsFrame,\
215 frameLabel = "Q vectors per shell",\
216 tagName= 'qvectors_per_shell',\
217 contents = 50)
218
219 elif widget == 'referencedirection':
220 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
221 frameLabel = "Reference direction",\
222 tagName = 'reference_direction',\
223 contents = "0.0,0.0,1.0")
224
225 elif widget == 'referenceframe':
226 self.widgets[widget] = ComboIntegerEntry(widgetsFrame,\
227 frameLabel = "Reference frame",\
228 tagName= 'reference_frame',\
229 contents = 1)
230
231 elif widget == 'removetranslation':
232 self.widgets[widget] = ComboCheckbutton(widgetsFrame,\
233 frameLabel = "Remove translation",\
234 tagName = 'remove_translation',\
235 onvalue = "yes",\
236 offvalue = "no")
237
238 elif widget == 'rvalues':
239 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
240 frameLabel = "Distances (in nm)",\
241 tagName = 'distances',\
242 contents = "0.0:1.0:0.1")
243
244 elif widget == 'stepwiserbt':
245 self.widgets[widget] = ComboCheckbutton(widgetsFrame,\
246 frameLabel = "Stepwise RBT",\
247 tagName = 'stepwise_rbt',\
248 onvalue = "yes",\
249 offvalue = "no")
250
251 elif widget == 'storerbtdetails':
252 self.widgets[widget] = ComboCheckbutton(widgetsFrame,\
253 frameLabel = "Store RBT details",\
254 tagName = 'store_rbt_details',\
255 onvalue = "yes",\
256 offvalue = "no")
257
258 elif widget == 'subset':
259 self.widgets[widget] = ComboButton(widgetsFrame,\
260 frameLabel = "Subset selection",\
261 tagName = 'subset_selection',\
262 contents = "Select",\
263 withEntry = 'all',\
264 command = lambda : SelectionDialog(self, 'subset', self.trajectory.universe.nmoldyncontents))
265
266 elif widget == 'temperature':
267 self.widgets[widget] = ComboFloatEntry(widgetsFrame,\
268 frameLabel = "Temperature (in K)",\
269 tagName = 'temperature',\
270 contents = 1.0)
271
272 elif widget == 'triplet':
273 self.widgets[widget] = ComboButton(widgetsFrame,\
274 frameLabel = "Triplet selection",\
275 tagName = 'triplet_selection',\
276 contents = "Select",\
277 withEntry = 'all',\
278 command = lambda : SelectionDialog(self, 'triplet', self.trajectory.universe.nmoldyncontents))
279
280 elif widget == 'thetavalues':
281 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
282 frameLabel = "Theta values (in deg)",\
283 tagName = 'theta_values',\
284 contents = "0.0:180.0:10.0")
285
286 elif widget == 'timeinfo':
287 timeInfo = '%d:%d:%d' % (1, len(self.trajectory), 1)
288 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
289 frameLabel = "Frame selection",\
290 tagName = 'frame_selection',\
291 contents = timeInfo)
292
293 elif widget == 'trajectory':
294 self.widgets[widget] = ComboLabel(widgetsFrame,\
295 frameLabel = "Trajectory file",\
296 tagName = 'tajectory_file',\
297 contents = self.trajectory.filename)
298
299 elif widget == 'weights':
300 self.widgets[widget] = ComboRadiobutton(widgetsFrame,\
301 frameLabel = "Weights",\
302 tagName = 'weights',\
303 contents = ["equal", "mass", "coherent", "incoherent", "atomicNumber"],\
304 layout = (2,3))
305
306 elif widget == 'wignerindexes':
307 self.widgets[widget] = ComboStringEntry(widgetsFrame,\
308 frameLabel = "Wigner indexes",\
309 tagName = 'wigner_indexes',\
310 contents = "0,0,0")
311
312
313 else:
314
315 baseName = widget.upper() + '_' + os.path.basename(self.trajectory.filename)
316 try:
317 outputFilename = os.path.join(PREFERENCES.outputfile_path,baseName)
318 except TypeError:
319 outputFilename = baseName
320 self.widgets[widget] = ComboFileBrowser(widgetsFrame,\
321 frameLabel = "%s output file" % widget.upper(),\
322 tagName= "%s_output_file" % widget.lower(),\
323 contents = outputFilename,\
324 save = True,\
325 filetypes = [("NetCDF file", ".nc"),])
326
327
328 setattr(self.widgets[widget],'tagName','%s_%s' % (self.analysis.shortName.lower(),self.widgets[widget].tagName.lower()))
329
330
331 self.widgets[widget].grid(column = 0, sticky = EW, padx = 2, pady = 2)
332 self.widgets[widget].grid_columnconfigure(0, weight = 1)
333
334 if hasattr(self.analysis, 'default'):
335 for k, v in self.analysis.default.items():
336 k = k.lower()
337 if k == 'weights':
338 self.widgets[k].setValue(v)
339
340 return None
341
373
374
375 - def ok(self, event = None, runMode = 'run'):
376
377 if not self.validate(runMode):
378 self.initial_focus.focus_set()
379 return
380
381 self.update_idletasks()
382
383 self.apply(runMode)
384
385 - def cancel(self, event=None):
386
387
388 self.parent.focus_set()
389 self.destroy()
390
391
393
394 try:
395
396 self.parameters = {'version' : nMOLDYN.__version__}
397
398 for widgetName, widget in self.widgets.items():
399 self.parameters[widgetName] = widget.getValue()
400
401 except:
402 LogMessage('warning','Bad input for %s. Please try again.' % widgetName,['gui'])
403 return False
404
405 return True
406
407 - def apply(self, runMode):
408
409 try:
410
411 for w in self.winfo_children():
412 self.widgetsState(w, DISABLED)
413
414 if runMode == 'estimate':
415 self.estimateAnalysis()
416
417 elif runMode == 'save':
418 self.saveAnalysis()
419
420 elif runMode == 'run':
421 self.runAnalysis()
422
423 elif runMode == 'saveandrun':
424 self.saveAndRunAnalysis()
425
426 else:
427 raise
428 except:
429
430 pass
431
432
433 finally:
434 for w in self.winfo_children():
435 self.widgetsState(w, NORMAL)
436
438 """Estimates the time taken by the analysis directly from the GUI.
439 """
440
441 self.parameters['estimate'] = 'yes'
442 self.actualAnalysis = eval('%s_serial(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
443
444 t = self.actualAnalysis.runAnalysis()
445
446
447 LogMessage('info','\nThe analysis should take:\n %(days)s days %(hours)s hours %(minutes)s minutes %(seconds)s seconds.\n' % t,['gui'])
448
450 """Saves a python script of the analysis that can be run independantly of the GUI.
451 """
452
453
454 pythonScript = asksaveasfilename(filetypes = [("nMOLDYN autostart file", "*.py"), ("nMOLDYN input file", "*.nmi")],\
455 title = "Browse python file",\
456 initialdir = PREFERENCES.outputfile_path)
457
458 if not pythonScript:
459 return
460
461 self.parameters['estimate'] = 'no'
462
463 if not self.parameters.has_key('pyroserver'):
464 self.actualAnalysis = eval('%s_serial(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
465
466 else:
467 if self.parameters['pyroserver'].lower() == 'monoprocessor':
468 self.actualAnalysis = eval('%s_serial(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
469
470 elif self.parameters['pyroserver'][:14].lower() == 'multiprocessor':
471 self.actualAnalysis = eval('%s_parallel(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
472
473 elif self.parameters['pyroserver'][:7].lower() == 'cluster':
474 self.actualAnalysis = eval('%s_parallel(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
475 else:
476 raise Error('The pyro server was not set properly')
477
478 self.actualAnalysis.saveAnalysis(pythonScript)
479
481 """Runs the analysis directly from the GUI.
482 """
483
484 self.parameters['estimate'] = 'no'
485
486 if not self.parameters.has_key('pyroserver'):
487 self.actualAnalysis = eval('%s_serial(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
488
489 else:
490 if self.parameters['pyroserver'].lower() == 'monoprocessor':
491 self.actualAnalysis = eval('%s_serial(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
492
493 elif self.parameters['pyroserver'][:14].lower() == 'multiprocessor':
494 self.actualAnalysis = eval('%s_parallel(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
495
496 elif self.parameters['pyroserver'][:7].lower() == 'cluster':
497 self.actualAnalysis = eval('%s_parallel(parameters = self.parameters, statusBar = self.statusBar)' % self.analysis.__name__)
498 else:
499 raise Error('The pyro server was not set properly')
500
501 t = self.actualAnalysis.runAnalysis()
502 self.parent.info.insert(contents = '\n\n\nPERFORMED ANALYSIS:\n\n')
503 self.parent.info.insert(contents = self.actualAnalysis.information)
504
505 message = 'Analysis run successfully in \n %(days)s days %(hours)s hours %(minutes)s minutes %(seconds)s seconds.\n\n' % t
506 if self.actualAnalysis.toPlot is None:
507
508 LogMessage('info',message,['gui'])
509 else:
510 message += 'Do you want to plot the results right now ?'
511 q = askyesno(title = 'Question', message = message)
512 if q:
513 PlotNetCDFVariableDialog(self, **self.actualAnalysis.toPlot)
514
516 """
517 This method is called when the user presses the 'Save and Run' button of an analysis dialog.
518 It saves a python script of the analysis and run the analysis directly from the GUI.
519 """
520
521 self.saveAnalysis()
522 self.runAnalysis()
523
539