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 Michael Bieri                                            # 
  4  # Copyright (C) 2010-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.launch_dir 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
231 - def execute(self, event):
232 """Set up, execute, and process the automatic Rx analysis. 233 234 @param event: The wx event. 235 @type event: wx event 236 """ 237 238 # Flush the GUI interpreter internal queue to make sure all user functions are complete. 239 self.gui.interpreter.flush() 240 241 # relax execution lock. 242 if status.exec_lock.locked(): 243 error_message("relax is currently executing.", "relax execution lock") 244 event.Skip() 245 return 246 247 # User warning to close windows. 248 self.gui.close_windows() 249 250 # Synchronise the frame data to the relax data store. 251 self.sync_ds(upload=True) 252 253 # Assemble all the data needed for the auto-analysis. 254 data, missing = self.assemble_data() 255 256 # Missing data. 257 if len(missing): 258 Missing_data(missing) 259 return 260 261 # Display the relax controller, and go to the end of the log window. 262 self.gui.show_controller(None) 263 self.gui.controller.log_panel.on_goto_end(None) 264 265 # Start the thread. 266 self.thread = Execute_noe(self.gui, data, self.data_index) 267 self.thread.start() 268 269 # Terminate the event. 270 event.Skip()
271 272
273 - def observer_register(self, remove=False):
274 """Register and unregister methods with the observer objects. 275 276 @keyword remove: If set to True, then the methods will be unregistered. 277 @type remove: False 278 """ 279 280 # Register. 281 if not remove: 282 status.observers.gui_uf.register(self.data.pipe_bundle, self.update_spin_count, method_name='update_spin_count') 283 status.observers.exec_lock.register(self.data.pipe_bundle, self.activate, method_name='activate') 284 285 # Unregister. 286 else: 287 # The model-free methods. 288 status.observers.gui_uf.unregister(self.data.pipe_bundle) 289 status.observers.exec_lock.unregister(self.data.pipe_bundle) 290 291 # The embedded objects methods. 292 self.peak_intensity.observer_register(remove=True)
293 294
295 - def peak_wizard_launch(self, event):
296 """Launch the peak loading wizard. 297 298 @param event: The wx event. 299 @type event: wx event 300 """ 301 302 # A new wizard instance. 303 self.peak_wizard = Peak_intensity_wizard(noe=True)
304 305
306 - def results_directory(self, event):
307 """The results directory selection. 308 309 @param event: The wx event. 310 @type event: wx event 311 """ 312 313 # The dialog. 314 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 315 316 # Show the dialog and catch if no file has been selected. 317 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 318 # Don't do anything. 319 return 320 321 # The path (don't do anything if not set). 322 path = gui_to_str(dialog.get_path()) 323 if not path: 324 return 325 326 # Store the path. 327 self.data.save_dir = path 328 329 # Place the path in the text box. 330 self.field_results_dir.SetValue(str_to_gui(path))
331 332
333 - def sync_ds(self, upload=False):
334 """Synchronise the noe analysis frame and the relax data store, both ways. 335 336 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. 337 338 @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. 339 @type upload: bool 340 """ 341 342 # The frequency. 343 if upload: 344 self.data.frq = gui_to_str(self.field_nmr_frq.GetValue()) 345 else: 346 self.field_nmr_frq.SetValue(str_to_gui(self.data.frq)) 347 348 # The results directory. 349 if upload: 350 self.data.save_dir = gui_to_str(self.field_results_dir.GetValue()) 351 else: 352 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))
353 354 355 356
357 -class Execute_noe(Execute):
358 """The NOE analysis execution object.""" 359
360 - def run_analysis(self):
361 """Execute the calculation.""" 362 363 # Execute. 364 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) 365 366 # Alias the relax data store data. 367 data = ds.relax_gui.analyses[self.data_index] 368 369 # FIXME: This must be shifted to the core of relax!!! 370 # Create a PyMOL macro, if a structure exists. 371 if hasattr(data, 'structure_file'): 372 # The macro. 373 color_code_noe(data.save_dir, data.structure_file) 374 375 # Add the macro to the results list. 376 cdp.result_files.append(['pymol', 'PyMOL', data.save_dir+sep+'noe.pml']) 377 status.observers.result_file.notify()
378