Package gui :: Package analyses :: Module auto_noe
[hide private]
[frames] | no frames]

Source Code for Module gui.analyses.auto_noe

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2009-2010 Michael Bieri                                       # 
  4  # Copyright (C) 2009-2013 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Module containing the base class for the automatic NOE analysis frames.""" 
 25   
 26  # Python module imports. 
 27  from os import sep 
 28  import wx 
 29   
 30  # relax module imports. 
 31  from auto_analyses.noe import NOE_calc 
 32  from data_store import Relax_data_store; ds = Relax_data_store() 
 33  from graphics import ANALYSIS_IMAGE_PATH, IMAGE_PATH, fetch_icon 
 34  from gui.analyses.base import Base_analysis 
 35  from gui.analyses.elements.text_element import Text_ctrl 
 36  from gui.analyses.execute import Execute 
 37  from gui.analyses.results_analysis import color_code_noe 
 38  from gui.base_classes import Container 
 39  from gui.components.spectrum import Spectra_list 
 40  from gui.filedialog import RelaxDirDialog 
 41  from gui.message import error_message, Missing_data 
 42  from gui.string_conv import gui_to_str, str_to_gui 
 43  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 44  from gui.wizards.peak_intensity import Peak_intensity_wizard 
 45  from pipe_control.mol_res_spin import exists_mol_res_spin_data 
 46  from pipe_control.pipes import has_bundle, has_pipe 
 47  from status import Status; status = Status() 
 48   
 49   
50 -class Auto_noe(Base_analysis):
51 """The base class for the noe frames.""" 52 53 # Hardcoded variables. 54 analysis_type = None 55 bitmap = [ANALYSIS_IMAGE_PATH+"noe_200x200.png", 56 IMAGE_PATH+'noe.png'] 57 label = None 58
59 - def __init__(self, parent, id=-1, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=524288, name='scrolledpanel', gui=None, analysis_name=None, pipe_name=None, pipe_bundle=None, uf_exec=[], data_index=None):
60 """Build the automatic NOE analysis GUI frame elements. 61 62 @param parent: The parent wx element. 63 @type parent: wx object 64 @keyword id: The unique ID number. 65 @type id: int 66 @keyword pos: The position. 67 @type pos: wx.Size object 68 @keyword size: The size. 69 @type size: wx.Size object 70 @keyword style: The style. 71 @type style: int 72 @keyword name: The name for the panel. 73 @type name: unicode 74 @keyword gui: The main GUI class. 75 @type gui: gui.relax_gui.Main instance 76 @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook). 77 @type analysis_name: str 78 @keyword pipe_name: The name of the data pipe associated with this analysis. 79 @type pipe_name: str 80 @keyword pipe_bundle: The name of the data pipe bundle associated with this analysis. 81 @type pipe_bundle: str 82 @keyword uf_exec: The list of user function on_execute methods returned from the new analysis wizard. 83 @type uf_exec: list of methods 84 @keyword data_index: The index of the analysis in the relax data store (set to None if no data currently exists). 85 @type data_index: None or int 86 """ 87 88 # Store the GUI main class. 89 self.gui = gui 90 91 # Init. 92 self.init_flag = True 93 94 # New data container. 95 if data_index == None: 96 # First create the data pipe if not already in existence. 97 if not has_pipe(pipe_name): 98 self.gui.interpreter.apply('pipe.create', pipe_name=pipe_name, pipe_type='noe', bundle=pipe_bundle) 99 100 # Create the data pipe bundle if needed. 101 if not has_bundle(pipe_bundle): 102 self.gui.interpreter.apply('pipe.bundle', bundle=pipe_bundle, pipe=pipe_name) 103 104 # Generate a storage container in the relax data store, and alias it for easy access. 105 data_index = ds.relax_gui.analyses.add('NOE') 106 107 # Store the analysis and pipe names. 108 ds.relax_gui.analyses[data_index].analysis_name = analysis_name 109 ds.relax_gui.analyses[data_index].pipe_name = pipe_name 110 ds.relax_gui.analyses[data_index].pipe_bundle = pipe_bundle 111 112 # Initialise the variables. 113 ds.relax_gui.analyses[data_index].frq = '' 114 ds.relax_gui.analyses[data_index].save_dir = self.gui.system_cwd_path 115 116 # Alias the data. 117 self.data = ds.relax_gui.analyses[data_index] 118 self.data_index = data_index 119 120 # Register the method for updating the spin count for the completion of user functions. 121 self.observer_register() 122 123 # Execute the base class method to build the panel. 124 super(Auto_noe, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name)
125 126
127 - def activate(self):
128 """Activate or deactivate certain elements of the analysis in response to the execution lock.""" 129 130 # Flag for enabling or disabling the elements. 131 enable = False 132 if not status.exec_lock.locked(): 133 enable = True 134 135 # Activate or deactivate the elements. 136 wx.CallAfter(self.field_nmr_frq.Enable, enable) 137 wx.CallAfter(self.field_results_dir.Enable, enable) 138 wx.CallAfter(self.spin_systems.Enable, enable) 139 wx.CallAfter(self.peak_intensity.Enable, enable) 140 wx.CallAfter(self.button_exec_relax.Enable, enable)
141 142
143 - def assemble_data(self):
144 """Assemble the data required for the Auto_noe class. 145 146 @return: A container with all the data required for the auto-analysis. 147 @rtype: class instance, list of str 148 """ 149 150 # The data container. 151 data = Container() 152 missing = [] 153 154 # The pipe name and bundle. 155 data.pipe_name = self.data.pipe_name 156 data.pipe_bundle = self.data.pipe_bundle 157 158 # The frequency. 159 frq = gui_to_str(self.field_nmr_frq.GetValue()) 160 if frq == None: 161 missing.append('NMR frequency') 162 163 # Filename. 164 data.file_root = 'noe.%s' % frq 165 166 # Results directory. 167 data.save_dir = self.data.save_dir 168 169 # Check if sequence data is loaded 170 if not exists_mol_res_spin_data(): 171 missing.append("Sequence data") 172 173 # Spectral data. 174 if not hasattr(cdp, 'spectrum_ids') or len(cdp.spectrum_ids) < 2: 175 missing.append("Spectral data") 176 177 # Return the container and list of missing data. 178 return data, missing
179 180
181 - def build_right_box(self):
182 """Construct the right hand box to pack into the main NOE box. 183 184 @return: The right hand box element containing all NOE GUI elements (excluding the bitmap) to pack into the main Rx box. 185 @rtype: wx.BoxSizer instance 186 """ 187 188 # Use a vertical packing of elements. 189 box = wx.BoxSizer(wx.VERTICAL) 190 191 # Add the frame title. 192 self.add_title(box, "Steady-state NOE analysis") 193 194 # Display the data pipe. 195 Text_ctrl(box, self, text="The data pipe bundle:", default=self.data.pipe_bundle, tooltip="This is the data pipe bundle associated with this analysis.", editable=False, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 196 197 # Add the frequency selection GUI element. 198 self.field_nmr_frq = Text_ctrl(box, self, text="NMR frequency label [MHz]:", default=self.data.frq, tooltip="This label is added to the output files. For example if the label is '600', the NOE values will be located in the file 'noe.600.out'.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 199 200 # Add the results directory GUI element. 201 self.field_results_dir = Text_ctrl(box, self, text="Results directory:", icon=fetch_icon('oxygen.actions.document-open-folder', "16x16"), default=self.data.save_dir, tooltip="The directory in which all automatically created files will be saved.", tooltip_button="Select the results directory.", fn=self.results_directory, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 202 203 # Add the spin GUI element. 204 self.add_spin_systems(box, self) 205 206 # Add the peak list selection GUI element, with spacing. 207 box.AddSpacer(40) 208 self.peak_intensity = Spectra_list(gui=self.gui, parent=self, box=box, id=str(self.data_index), fn_add=self.peak_wizard_launch, noe_flag=True) 209 210 # Stretchable spacing (with a minimal space). 211 box.AddSpacer(30) 212 box.AddStretchSpacer() 213 214 # Add the execution GUI element. 215 self.button_exec_relax = self.add_execute_analysis(box, self.execute) 216 217 # Return the box. 218 return box
219 220
221 - def delete(self):
222 """Unregister the spin count from the user functions.""" 223 224 # Unregister the observer methods. 225 self.observer_register(remove=True) 226 227 # Clean up the peak intensity object. 228 self.peak_intensity.delete() 229 230 # Destroy the peak intensity wizard, if it exists. 231 if hasattr(self, 'peak_wizard'): 232 self.peak_wizard.Destroy() 233 del self.peak_wizard 234 235 # Destroy the missing data dialog, if present. 236 if hasattr(self, 'missing_data'): 237 self.missing_data.Destroy() 238 del self.missing_data
239 240
241 - def execute(self, event):
242 """Set up, execute, and process the automatic Rx analysis. 243 244 @param event: The wx event. 245 @type event: wx event 246 """ 247 248 # Flush the GUI interpreter internal queue to make sure all user functions are complete. 249 self.gui.interpreter.flush() 250 251 # relax execution lock. 252 if status.exec_lock.locked(): 253 error_message("relax is currently executing.", "relax execution lock") 254 event.Skip() 255 return 256 257 # User warning to close windows. 258 self.gui.close_windows() 259 260 # Synchronise the frame data to the relax data store. 261 self.sync_ds(upload=True) 262 263 # Assemble all the data needed for the auto-analysis. 264 data, missing = self.assemble_data() 265 266 # Missing data. 267 if len(missing): 268 self.missing_data = Missing_data(missing) 269 return 270 271 # Display the relax controller, and go to the end of the log window. 272 self.gui.show_controller(None) 273 self.gui.controller.log_panel.on_goto_end(None) 274 275 # Start the thread. 276 self.thread = Execute_noe(self.gui, data, self.data_index) 277 self.thread.start() 278 279 # Terminate the event. 280 event.Skip()
281 282
283 - def observer_register(self, remove=False):
284 """Register and unregister methods with the observer objects. 285 286 @keyword remove: If set to True, then the methods will be unregistered. 287 @type remove: False 288 """ 289 290 # Register. 291 if not remove: 292 status.observers.gui_uf.register(self.data.pipe_bundle, self.update_spin_count, method_name='update_spin_count') 293 status.observers.exec_lock.register(self.data.pipe_bundle, self.activate, method_name='activate') 294 295 # Unregister. 296 else: 297 # The model-free methods. 298 status.observers.gui_uf.unregister(self.data.pipe_bundle) 299 status.observers.exec_lock.unregister(self.data.pipe_bundle) 300 301 # The embedded objects methods. 302 self.peak_intensity.observer_register(remove=True)
303 304
305 - def peak_wizard_launch(self, event):
306 """Launch the peak loading wizard. 307 308 @param event: The wx event. 309 @type event: wx event 310 """ 311 312 # Destroy the peak intensity wizard, if it exists. 313 if hasattr(self, 'peak_wizard'): 314 self.peak_wizard.Destroy() 315 316 # A new wizard instance. 317 self.peak_wizard = Peak_intensity_wizard(noe=True)
318 319
320 - def results_directory(self, event):
321 """The results directory selection. 322 323 @param event: The wx event. 324 @type event: wx event 325 """ 326 327 # The dialog. 328 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 329 330 # Show the dialog and catch if no file has been selected. 331 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 332 # Don't do anything. 333 return 334 335 # The path (don't do anything if not set). 336 path = gui_to_str(dialog.get_path()) 337 if not path: 338 return 339 340 # Store the path. 341 self.data.save_dir = path 342 343 # Place the path in the text box. 344 self.field_results_dir.SetValue(str_to_gui(path))
345 346
347 - def sync_ds(self, upload=False):
348 """Synchronise the noe analysis frame and the relax data store, both ways. 349 350 This method allows the frame information to be uploaded into the relax data store, or for the information in the relax data store to be downloaded by the frame. 351 352 @keyword upload: A flag which if True will cause the frame to send data to the relax data store. If False, data will be downloaded from the relax data store to update the frame. 353 @type upload: bool 354 """ 355 356 # The frequency. 357 if upload: 358 self.data.frq = gui_to_str(self.field_nmr_frq.GetValue()) 359 else: 360 self.field_nmr_frq.SetValue(str_to_gui(self.data.frq)) 361 362 # The results directory. 363 if upload: 364 self.data.save_dir = gui_to_str(self.field_results_dir.GetValue()) 365 else: 366 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))
367 368 369 370
371 -class Execute_noe(Execute):
372 """The NOE analysis execution object.""" 373
374 - def run_analysis(self):
375 """Execute the calculation.""" 376 377 # Execute. 378 NOE_calc(pipe_name=self.data.pipe_name, pipe_bundle=self.data.pipe_bundle, file_root=self.data.file_root, results_dir=self.data.save_dir, save_state=False) 379 380 # Alias the relax data store data. 381 data = ds.relax_gui.analyses[self.data_index] 382 383 # FIXME: This must be shifted to the core of relax!!! 384 # Create a PyMOL macro, if a structure exists. 385 if hasattr(data, 'structure_file'): 386 # The macro. 387 color_code_noe(data.save_dir, data.structure_file) 388 389 # Add the macro to the results list. 390 cdp.result_files.append(['pymol', 'PyMOL', data.save_dir+sep+'noe.pml']) 391 status.observers.result_file.notify()
392