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

Source Code for Module gui.analyses.auto_rx_base

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2009-2011 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 R1 and R2 analysis frames.""" 
 25   
 26  # Python module imports. 
 27  import wx 
 28   
 29  # relax module imports. 
 30  from auto_analyses.relax_fit import Relax_fit 
 31  from data_store import Relax_data_store; ds = Relax_data_store() 
 32  from graphics import fetch_icon 
 33  from gui.analyses.base import Base_analysis 
 34  from gui.analyses.elements.spin_element import Spin_ctrl 
 35  from gui.analyses.elements.text_element import Text_ctrl 
 36  from gui.analyses.execute import Execute 
 37  from gui.base_classes import Container 
 38  from gui.components.spectrum import Spectra_list 
 39  from gui.filedialog import RelaxDirDialog 
 40  from gui.message import error_message, Missing_data 
 41  from gui.string_conv import gui_to_int, gui_to_str, str_to_gui 
 42  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 43  from gui.wizards.peak_intensity import Peak_intensity_wizard 
 44  from pipe_control.mol_res_spin import exists_mol_res_spin_data 
 45  from pipe_control.pipes import has_bundle, has_pipe 
 46  from status import Status; status = Status() 
 47   
 48   
49 -class Auto_rx(Base_analysis):
50 """The base class for the R1 and R2 frames.""" 51 52 # Hardcoded variables. 53 analysis_type = None 54 bitmap = None 55 label = None 56
57 - 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):
58 """Build the automatic R1 and R2 analysis GUI frame elements. 59 60 @param parent: The parent wx element. 61 @type parent: wx object 62 @keyword id: The unique ID number. 63 @type id: int 64 @keyword pos: The position. 65 @type pos: wx.Size object 66 @keyword size: The size. 67 @type size: wx.Size object 68 @keyword style: The style. 69 @type style: int 70 @keyword name: The name for the panel. 71 @type name: unicode 72 @keyword gui: The main GUI class. 73 @type gui: gui.relax_gui.Main instance 74 @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook). 75 @type analysis_name: str 76 @keyword pipe_name: The name of the data pipe associated with this analysis. 77 @type pipe_name: str 78 @keyword pipe_bundle: The name of the data pipe bundle associated with this analysis. 79 @type pipe_bundle: str 80 @keyword uf_exec: The list of user function on_execute methods returned from the new analysis wizard. 81 @type uf_exec: list of methods 82 @keyword data_index: The index of the analysis in the relax data store (set to None if no data currently exists). 83 @type data_index: None or int 84 """ 85 86 # Store the GUI main class. 87 self.gui = gui 88 89 # Init. 90 self.init_flag = True 91 92 # New data container. 93 if data_index == None: 94 # First create the data pipe if not already in existence. 95 if not has_pipe(pipe_name): 96 self.gui.interpreter.apply('pipe.create', pipe_name=pipe_name, pipe_type='relax_fit', bundle=pipe_bundle) 97 98 # Create the data pipe bundle if needed. 99 if not has_bundle(pipe_bundle): 100 self.gui.interpreter.apply('pipe.bundle', bundle=pipe_bundle, pipe=pipe_name) 101 102 # Generate a storage container in the relax data store, and alias it for easy access. 103 data_index = ds.relax_gui.analyses.add(self.label) 104 105 # Store the analysis and pipe names. 106 ds.relax_gui.analyses[data_index].analysis_name = analysis_name 107 ds.relax_gui.analyses[data_index].pipe_name = pipe_name 108 ds.relax_gui.analyses[data_index].pipe_bundle = pipe_bundle 109 110 # Initialise the variables. 111 ds.relax_gui.analyses[data_index].frq = '' 112 ds.relax_gui.analyses[data_index].grid_inc = None 113 ds.relax_gui.analyses[data_index].mc_sim_num = None 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_rx, 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.grid_inc.Enable, enable) 141 wx.CallAfter(self.mc_sim_num.Enable, enable) 142 wx.CallAfter(self.button_exec_relax.Enable, enable)
143 144
145 - def assemble_data(self):
146 """Assemble the data required for the auto-analysis. 147 148 See the docstring for auto_analyses.relax_fit for details. All data is taken from the relax data store, so data upload from the GUI to there must have been previously performed. 149 150 @return: A container with all the data required for the auto-analysis. 151 @rtype: class instance, list of str 152 """ 153 154 # The data container. 155 data = Container() 156 missing = [] 157 158 # The pipe name and bundle. 159 data.pipe_name = self.data.pipe_name 160 data.pipe_bundle = self.data.pipe_bundle 161 162 # The frequency. 163 frq = gui_to_str(self.field_nmr_frq.GetValue()) 164 if frq == None: 165 missing.append('NMR frequency') 166 167 # File root. 168 data.file_root = '%s.%s' % (self.analysis_type, frq) 169 170 # Check if sequence data is loaded 171 if not exists_mol_res_spin_data(): 172 missing.append("Sequence data") 173 174 # Spectral data. 175 if not hasattr(cdp, 'spectrum_ids') or len(cdp.spectrum_ids) < 3: 176 missing.append("Spectral data") 177 178 # Increment size. 179 data.inc = gui_to_int(self.grid_inc.GetValue()) 180 181 # The number of Monte Carlo simulations to be used for error analysis at the end of the analysis. 182 data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 183 184 # Results directory. 185 data.save_dir = self.data.save_dir 186 187 # Return the container and list of missing data. 188 return data, missing
189 190
191 - def build_right_box(self):
192 """Construct the right hand box to pack into the main Rx box. 193 194 @return: The right hand box element containing all Rx GUI elements (excluding the bitmap) to pack into the main Rx box. 195 @rtype: wx.BoxSizer instance 196 """ 197 198 # Use a vertical packing of elements. 199 box = wx.BoxSizer(wx.VERTICAL) 200 201 # Add the frame title. 202 self.add_title(box, "%s relaxation analysis" % self.gui_label) 203 204 # Display the data pipe. 205 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) 206 207 # Add the frequency selection GUI element. 208 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 %s values will be located in the file '%s.600.out'." % (self.gui_label, self.label.lower()), width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 209 210 # Add the results directory GUI element. 211 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) 212 213 # Add the spin GUI element. 214 self.add_spin_systems(box, self) 215 216 # Add the peak list wizard and selection GUI element, with spacing. 217 box.AddSpacer(20) 218 self.peak_intensity = Spectra_list(gui=self.gui, parent=self, box=box, id=str(self.data_index), fn_add=self.peak_wizard_launch, relax_times=True) 219 box.AddSpacer(10) 220 221 # The optimisation settings. 222 self.grid_inc = Spin_ctrl(box, self, text="Grid search increments:", default=21, min=1, max=100, tooltip="This is the number of increments per dimension of the grid search performed prior to numerical optimisation.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 223 self.mc_sim_num = Spin_ctrl(box, self, text="Monte Carlo simulation number:", default=500, min=1, max=100000, tooltip="This is the number of Monte Carlo simulations performed for error propagation and analysis. For best results, at least 500 is recommended.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 224 225 # Stretchable spacing (with a minimal space). 226 box.AddSpacer(30) 227 box.AddStretchSpacer() 228 229 # Add the execution GUI element. 230 self.button_exec_relax = self.add_execute_analysis(box, self.execute) 231 232 # Return the box. 233 return box
234 235
236 - def delete(self):
237 """Unregister the spin count from the user functions.""" 238 239 # Unregister the observer methods. 240 self.observer_register(remove=True) 241 242 # Clean up the peak intensity object. 243 self.peak_intensity.delete()
244 245
246 - def execute(self, event):
247 """Set up, execute, and process the automatic Rx analysis. 248 249 @param event: The wx event. 250 @type event: wx event 251 """ 252 253 # Flush the GUI interpreter internal queue to make sure all user functions are complete. 254 self.gui.interpreter.flush() 255 256 # relax execution lock. 257 if status.exec_lock.locked(): 258 error_message("relax is currently executing.", "relax execution lock") 259 event.Skip() 260 return 261 262 # User warning to close windows. 263 self.gui.close_windows() 264 265 # Synchronise the frame data to the relax data store. 266 self.sync_ds(upload=True) 267 268 # Assemble all the data needed for the auto-analysis. 269 data, missing = self.assemble_data() 270 271 # Missing data. 272 if len(missing): 273 Missing_data(missing) 274 return 275 276 # Display the relax controller, and go to the end of the log window. 277 self.gui.show_controller(None) 278 self.gui.controller.log_panel.on_goto_end(None) 279 280 # Start the thread. 281 self.thread = Execute_rx(self.gui, data, self.data_index) 282 self.thread.start() 283 284 # Terminate the event. 285 event.Skip()
286 287
288 - def observer_register(self, remove=False):
289 """Register and unregister methods with the observer objects. 290 291 @keyword remove: If set to True, then the methods will be unregistered. 292 @type remove: False 293 """ 294 295 # Register. 296 if not remove: 297 status.observers.gui_uf.register(self.data.pipe_bundle, self.update_spin_count, method_name='update_spin_count') 298 status.observers.exec_lock.register(self.data.pipe_bundle, self.activate, method_name='activate') 299 300 # Unregister. 301 else: 302 # The model-free methods. 303 status.observers.gui_uf.unregister(self.data.pipe_bundle) 304 status.observers.exec_lock.unregister(self.data.pipe_bundle) 305 306 # The embedded objects methods. 307 self.peak_intensity.observer_register(remove=True)
308 309
310 - def peak_wizard_launch(self, event):
311 """Launch the peak loading wizard. 312 313 @param event: The wx event. 314 @type event: wx event 315 """ 316 317 # A new wizard instance. 318 self.peak_wizard = Peak_intensity_wizard(relax_fit=True)
319 320
321 - def results_directory(self, event):
322 """The results directory selection. 323 324 @param event: The wx event. 325 @type event: wx event 326 """ 327 328 # The dialog. 329 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 330 331 # Show the dialog and catch if no file has been selected. 332 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 333 # Don't do anything. 334 return 335 336 # The path (don't do anything if not set). 337 path = gui_to_str(dialog.get_path()) 338 if not path: 339 return 340 341 # Store the path. 342 self.data.save_dir = path 343 344 # Place the path in the text box. 345 self.field_results_dir.SetValue(str_to_gui(path))
346 347
348 - def sync_ds(self, upload=False):
349 """Synchronise the analysis frame and the relax data store, both ways. 350 351 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. 352 353 @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. 354 @type upload: bool 355 """ 356 357 # The frequency. 358 if upload: 359 self.data.frq = gui_to_str(self.field_nmr_frq.GetValue()) 360 else: 361 self.field_nmr_frq.SetValue(str_to_gui(self.data.frq)) 362 363 # The grid incs. 364 if upload: 365 self.data.grid_inc = gui_to_int(self.grid_inc.GetValue()) 366 elif hasattr(self.data, 'grid_inc'): 367 self.grid_inc.SetValue(int(self.data.grid_inc)) 368 369 # The MC sim number. 370 if upload: 371 self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 372 elif hasattr(self.data, 'mc_sim_num'): 373 self.mc_sim_num.SetValue(int(self.data.mc_sim_num)) 374 375 # The results directory. 376 if upload: 377 self.data.save_dir = gui_to_str(self.field_results_dir.GetValue()) 378 else: 379 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))
380 381 382
383 -class Execute_rx(Execute):
384 """The Rx analysis execution object.""" 385
386 - def run_analysis(self):
387 """Execute the calculation.""" 388 389 # Execute. 390 Relax_fit(pipe_name=self.data.pipe_name, pipe_bundle=self.data.pipe_bundle, file_root=self.data.file_root, results_dir=self.data.save_dir, grid_inc=self.data.inc, mc_sim_num=self.data.mc_sim_num, view_plots=False) 391 392 # Alias the relax data store data. 393 data = ds.relax_gui.analyses[self.data_index]
394