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

# Source Code for Module nMOLDYN.GUI.PDBSnapshotGeneratorDialog

      1  """This modules implements I{File-->Frame snapshot} dialog.
      2
      3  Classes:
      4      * PDBSnapshotGeneratorDialog: creates I{File-->Frame snapshot} dialog used to
      5        extract a PDB file from one or several trajectory frame(s).
      6  """
      7
      8  # The python distribution modules
      9  import os
     10  import re
     11  import sys
     12  from tempfile import mkdtemp
     13
     14  # The Tcl/Tk modules
     15  from tkFileDialog import askopenfilename
     16  from Tkinter import *
     17
     18  # The ScientificPython modules
     19  from Scientific import N as Num
     20
     21  # The MMTK distribution modules
     22  from MMTK.PDB import PDBOutputFile
     23  from MMTK.Trajectory import Trajectory
     24
     25  # The nMOLDYN modules
     26  from nMOLDYN.Core.Error import Error
     27  from nMOLDYN.Core.Logger import LogMessage
     28  from nMOLDYN.Core.Preferences import PREFERENCES
     29  from nMOLDYN.GUI.Widgets import *
     30
     31 -class PDBSnapshotGeneratorDialog(Toplevel):
     32      """Sets up a dialog used to export one or several trajectory frames into a PDB file.
     33
     34      @note: if a trajectory has been previously loaded in nMOLDYN this will be the one proposed for extraction
     35          by default. Otherwise, the user can still choose a trajectory to visualize from the dialog.
     36      """
     37 -    def __init__(self, parent, title = None, trajectory = None):
     38          """The constructor.
     39
     40          @param parent: the parent widget.
     41
     42          @param title: a string specifying the title of the dialog.
     43          @type title: string
     44          """
     45
     46          Toplevel.__init__(self, parent)
     47
     48          self.transient(parent)
     49
     50          if title:
     51              self.title(title)
     52
     53          self.parent = parent
     54
     55          # If a trajectory has been loaded in nMOLDYN for simulation purposes (e.g. MSD ...) then it is proposed by default for
     56          # visualization.
     57          if isinstance(trajectory, Trajectory):
     58              self.trajectory = trajectory
     59
     60          else:
     61              self.trajectory = None
     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          self.grab_set()
     70
     71          if not self.initial_focus:
     72              self.initial_focus = self
     73
     74          self.protocol("WM_DELETE_WINDOW", self.cancel)
     75
     76          self.resizable(width = NO, height = NO)
     77
     78          self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
     79
     80          self.initial_focus.focus_set()
     81
     82          self.wait_window(self)
     83
     84 -    def body(self, master):
     85          """
     86          Create dialog body. Return widget that should have initial focus.
     87          """
     88
     89          settingsFrame = LabelFrame(master, text = 'Settings', bd = 2, relief = GROOVE)
     90          settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3)
     91          settingsFrame.grid_columnconfigure(0, weight = 1)
     92
     93          # The combo widget for the file browser.
     94          self.fileBrowser = ComboFileBrowser(settingsFrame,\
     95                                              frameLabel = "MMTK trajectory file",\
     96                                              tagName = 'frame_snapshot_mmtk_trajectory_file',\
     97                                              contents = '',\
     98                                              save = False,\
     99                                              command = self.openTrajectory)
    100          self.fileBrowser.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = EW)
    101          self.fileBrowser.grid_columnconfigure(0, weight = 1)
    102          self.fileBrowser.entry.bind('<Return>', self.openTrajectory)
    103
    104          # The combo widget for the first step setting.
    105          self.selectedStepEntry = ComboStringEntry(settingsFrame,\
    106                                                    frameLabel = 'Selected frames',\
    107                                                    tagName = 'frame_snapshot_selected_frames',\
    108                                                    contents = '1')
    109          self.selectedStepEntry.grid(row = 1, column = 0, sticky = EW, padx = 2, pady = 2)
    110          self.selectedStepEntry.grid_columnconfigure(0, weight = 1)
    111
    112          # The PDB output file browser.
    113          self.pdbFileBrowser = ComboFileBrowser(settingsFrame,\
    114                                                 frameLabel = "PDB output file",\
    115                                                 tagName = 'frame_snapshot_pdb_output_file',\
    116                                                 contents = '',\
    117                                                 save = True)
    118          self.pdbFileBrowser.grid(row = 2, column = 0, padx = 2, pady = 2, sticky = EW)
    119          self.pdbFileBrowser.grid_columnconfigure(0, weight = 1)
    120
    121          # If a trajectory has been loaded in nMOLDYN for simulation purposes (e.g. MSD ...) then it is proposed by default for
    122          # visualization.
    123          if self.trajectory is not None:
    124              # The control variables are updated with the informations coming from the loaded trajectory.
    125              self.fileBrowser.setValue(self.trajectory.filename)
    126              self.selectedStepEntry.setValue('1')
    127              self.pdbFileBrowser.setValue(os.path.splitext(self.trajectory.filename)[0] + '_Frame.pdb')
    128          else:
    129              self.pdbFileBrowser.setValue('Frame.pdb')
    130
    131          return None
    132
    133 -    def buttonbox(self):
    134          """
    135          Add standard button box.
    136          """
    137
    138          # The frame that contains the 'Cancel' and 'OK' buttons.
    139          box = LabelFrame(self, text = 'Actions', bd = 2, relief = GROOVE)
    140          box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3)
    141          box.grid_columnconfigure(0, weight = 1)
    142
    143          w = Button(box, text = "Cancel", width=10, command = self.cancel)
    144          w.grid(row = 0, column = 0, sticky = E)
    145          w = Button(box, text = "OK", width=10, command = self.ok, default=ACTIVE)
    146          w.grid(row = 0, column = 1, sticky = E)
    147
    148          self.bind("<Return>", self.ok)
    149          self.bind("<Escape>", self.cancel)
    150
    151      # Standard button semantics.
    152 -    def ok(self, event = None):
    153
    154          if not self.validate():
    155              self.initial_focus.focus_set()
    156              return
    157
    158          self.update_idletasks()
    159
    160          self.apply()
    161
    162 -    def cancel(self, event=None):
    163
    164          # Put focus back to the parent window
    165          self.parent.focus_set()
    166          self.destroy()
    167
    168      # Command hooks
    169 -    def validate(self):
    170
    171          if not self.trajectory:
    172              raise Error('No MMTK trajectory file loaded for extraction.')
    173
    174          if self.trajectory.filename != self.fileBrowser.getValue():
    175              raise Error('Mismatch between the loaded trajectory and the displayed MMTK trajectory file name.\
    176  You should validate that file by pressing Return on its corresponding entry.')
    177
    178          # A frame selection must have been set.
    179          if not self.selectedStepEntry.getValue():
    180              self.selectedFrames = '1'
    181              LogMessage('warning', 'No frame selected. Frame 1 will be extracted by default.', ['gui'])
    182          else:
    183              self.selectedFrames = self.selectedStepEntry.getValue().strip()
    184
    185          try:
    186              self.selectedFrames = eval(self.selectedFrames)
    187              # The entry can be an integer.
    188              if isinstance(self.selectedFrames, int):
    189                  self.selectedFrames = [self.selectedFrames]
    190
    191              # The entry can be a list or a tuple.
    192              elif isinstance(self.selectedFrames, (list,tuple)):
    193                  pass
    194
    195          except:
    196              try:
    197                  temp = []
    198                  self.selectedFrames = [temp.extend(range(int(v[0]),int(v[1])+1,int(v[2]))) for v in re.findall('(\d+):(\d+):(\d+)',self.selectedFrames)]
    199                  self.selectedFrames = temp
    200              except:
    201                  raise Error('Wrong format for frame selection.')
    202
    203          # Check that every selected step is valid.
    204          for s in self.selectedFrames:
    205              if not isinstance(s, int):
    206                  raise Error('Wrong entry for frame selection.')
    207
    208              if (s <= 0) or (s > len(self.trajectory)):
    209                  raise Error('Some selected frame number are not within [1,%d].' % len(self.trajectory))
    210
    211          # A PDB output file name must have been set.
    212          self.pdbFile = self.pdbFileBrowser.getValue()
    213          if not self.pdbFile:
    214              raise Error('Please enter a PDB output file.')
    215
    216          return True
    217
    218 -    def apply(self):
    219
    220          try:
    221              # pid = the pid number for the job
    222              pid = os.getpid()
    223              suffix = '.'.join(['',str(pid),'pdb','nmoldyn'])
    224
    225              # This just creates a unique temporary directory.
    226              dirName = mkdtemp(suffix)
    227
    228              outputFile = open(self.pdbFile,'w')
    229
    230              for f in self.selectedFrames:
    231                  pdbFrame = os.path.join(dirName,''.join(['Frame',str(f),'.pdb']))
    232                  # This MMTK function write a PDB file given a trajectory and a selected frame index.
    233                  PDBOutputFile(pdbFrame).write(self.trajectory.universe, self.trajectory.configuration[f-1])
    234
    235                  pdbFile = open(pdbFrame,'r')
    236                  data = pdbFile.read()
    237                  pdbFile.close()
    238                  os.unlink(pdbFrame)
    239                  outputFile.write('REMARK Frame %d\n' % (f,))
    240                  outputFile.write(data)
    241
    242              outputFile.close()
    243
    244              LogMessage('info', 'Frame extraction successful', ['gui'])
    245
    246          except:
    247              raise Error('Error when extracting PDB frame.')
    248
    249 -    def openTrajectory(self, event = None):
    250          """
    251          Ths method is called when the user clicks on the 'Browse' button of the trajectory visualization dialog.
    252          It opens a file browser. After the file selection some of the dialog widgets are updated with the informations
    253          coming from the loaded trajectory.
    254          """
    255
    256          # Case where the user enters a file name directly in the entry widget without using the browser.
    257          if event is not None:
    258              if event.widget == self.fileBrowser.entry:
    259                  filename = self.fileBrowser.getValue()
    260              else:
    261                  return
    262
    263          else:
    264              # The name of the NetCDF file to load.
    265              filename = askopenfilename(parent = self,\
    266                                         filetypes = [('NetCDF file','*.nc')],\
    267                                         initialdir = PREFERENCES.trajfile_path)
    268
    269          # The file must exist.
    270          if filename:
    271              try:
    272                  # The trajectory is loaded.
    273                  self.trajectory = Trajectory(None, filename, 'r')
    274              except IOError:
    275                  raise Error('Can not read the trajectory.')
    276              else:
    277                  # The control variables are updated with the informations about the loaded trajectory.
    278                  self.fileBrowser.setValue(filename)
    279                  self.selectedStepEntry.setValue('1')
    280
    281          return 'break'
    282