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-2012 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax.                                     # 
  7  #                                                                             # 
  8  # relax 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 2 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # relax 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 relax; if not, write to the Free Software                        # 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 21  #                                                                             # 
 22  ############################################################################### 
 23   
 24  # Module docstring. 
 25  """Module containing the base class for the automatic R1 and R2 analysis frames.""" 
 26   
 27  # Python module imports. 
 28  from os import sep 
 29  from string import lower 
 30  import sys 
 31  import wx 
 32   
 33  # relax module imports. 
 34  from auto_analyses.relax_fit import Relax_fit 
 35  from data import Relax_data_store; ds = Relax_data_store() 
 36  from generic_fns.mol_res_spin import are_spins_named, exists_mol_res_spin_data 
 37  from generic_fns.pipes import has_pipe 
 38  from status import Status; status = Status() 
 39   
 40  # relax GUI module imports. 
 41  from gui.analyses.base import Base_analysis, Spectral_error_type_page 
 42  from gui.analyses.elements import Spin_ctrl, Text_ctrl 
 43  from gui.analyses.execute import Execute 
 44  from gui.base_classes import Container 
 45  from gui.components.spectrum import Spectra_list 
 46  from gui.filedialog import RelaxDirDialog 
 47  from gui.message import error_message, Missing_data, Question 
 48  from gui.misc import gui_to_int, gui_to_str, int_to_gui, protected_exec, str_to_gui 
 49  from gui import paths 
 50  from gui.user_functions.relax_fit import Relax_time_page 
 51  from gui.user_functions.spectrum import Baseplane_rmsd_page, Integration_points_page, Read_intensities_page, Replicated_page 
 52  from gui.user_functions.spin import Name_page 
 53  from gui.wizard import Wiz_window 
 54   
 55   
 56   
57 -class Auto_rx(Base_analysis):
58 """The base class for the R1 and R2 frames.""" 59 60 # Hardcoded variables. 61 analysis_type = None 62 bitmap = None 63 label = None 64
65 - 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, data_index=None):
66 """Build the automatic R1 and R2 analysis GUI frame elements. 67 68 @param parent: The parent wx element. 69 @type parent: wx object 70 @keyword id: The unique ID number. 71 @type id: int 72 @keyword pos: The position. 73 @type pos: wx.Size object 74 @keyword size: The size. 75 @type size: wx.Size object 76 @keyword style: The style. 77 @type style: int 78 @keyword name: The name for the panel. 79 @type name: unicode 80 @keyword gui: The main GUI class. 81 @type gui: gui.relax_gui.Main instance 82 @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook). 83 @type analysis_name: str 84 @keyword pipe_name: The name of the data pipe associated with this analysis. 85 @type pipe_name: str 86 @keyword data_index: The index of the analysis in the relax data store (set to None if no data currently exists). 87 @type data_index: None or int 88 """ 89 90 # Store the GUI main class. 91 self.gui = gui 92 93 # Init. 94 self.init_flag = True 95 96 # New data container. 97 if data_index == None: 98 # First create the data pipe if not already in existence. 99 if not has_pipe(pipe_name): 100 self.gui.interpreter.apply('pipe.create', pipe_name, 'relax_fit') 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 109 # Initialise the variables. 110 ds.relax_gui.analyses[data_index].frq = '' 111 ds.relax_gui.analyses[data_index].grid_inc = None 112 ds.relax_gui.analyses[data_index].mc_sim_num = None 113 ds.relax_gui.analyses[data_index].save_dir = self.gui.launch_dir 114 115 # Alias the data. 116 self.data = ds.relax_gui.analyses[data_index] 117 self.data_index = data_index 118 119 # Register the method for updating the spin count for the completion of user functions. 120 self.observer_register() 121 122 # Execute the base class method to build the panel. 123 super(Auto_rx, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name)
124 125
126 - def activate(self):
127 """Activate or deactivate certain elements of the analysis in response to the execution lock.""" 128 129 # Flag for enabling or disabling the elements. 130 enable = False 131 if not status.exec_lock.locked(): 132 enable = True 133 134 # Activate or deactivate the elements. 135 wx.CallAfter(self.field_nmr_frq.Enable, enable) 136 wx.CallAfter(self.field_results_dir.Enable, enable) 137 wx.CallAfter(self.spin_systems.Enable, enable) 138 wx.CallAfter(self.peak_intensity.Enable, enable) 139 wx.CallAfter(self.grid_inc.Enable, enable) 140 wx.CallAfter(self.mc_sim_num.Enable, enable) 141 wx.CallAfter(self.button_exec_relax.Enable, enable)
142 143
144 - def assemble_data(self):
145 """Assemble the data required for the auto-analysis. 146 147 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. 148 149 @return: A container with all the data required for the auto-analysis. 150 @rtype: class instance, list of str 151 """ 152 153 # The data container. 154 data = Container() 155 missing = [] 156 157 # The pipe name. 158 data.pipe_name = self.data.pipe_name 159 160 # The frequency. 161 frq = gui_to_str(self.field_nmr_frq.GetValue()) 162 if frq == None: 163 missing.append('NMR frequency') 164 165 # File root. 166 data.file_root = '%s.%s' % (self.analysis_type, frq) 167 168 # Check if sequence data is loaded 169 if not exists_mol_res_spin_data(): 170 missing.append("Sequence data") 171 172 # Spectral data. 173 if not hasattr(cdp, 'spectrum_ids') or len(cdp.spectrum_ids) < 3: 174 missing.append("Spectral data") 175 176 # Increment size. 177 data.inc = gui_to_int(self.grid_inc.GetValue()) 178 179 # The number of Monte Carlo simulations to be used for error analysis at the end of the analysis. 180 data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 181 182 # Results directory. 183 data.save_dir = self.data.save_dir 184 185 # Return the container and list of missing data. 186 return data, missing
187 188
189 - def build_right_box(self):
190 """Construct the right hand box to pack into the main Rx box. 191 192 @return: The right hand box element containing all Rx GUI elements (excluding the bitmap) to pack into the main Rx box. 193 @rtype: wx.BoxSizer instance 194 """ 195 196 # Use a vertical packing of elements. 197 box = wx.BoxSizer(wx.VERTICAL) 198 199 # Add the frame title. 200 self.add_title(box, "Setup for %s relaxation analysis" % self.label) 201 202 # Display the data pipe. 203 Text_ctrl(box, self, text="The data pipe:", default=self.data.pipe_name, tooltip="This is the data pipe associated with this analysis.", editable=False, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 204 205 # Add the frequency selection GUI element. 206 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.label, lower(self.label)), width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 207 208 # Add the results directory GUI element. 209 self.field_results_dir = Text_ctrl(box, self, text="Results directory", icon=paths.icon_16x16.open_folder, default=self.data.save_dir, fn=self.results_directory, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 210 211 # Add the spin GUI element. 212 self.add_spin_systems(box, self) 213 214 # Add the peak list selection GUI element, with spacing. 215 box.AddSpacer(20) 216 self.peak_intensity = Spectra_list(gui=self.gui, parent=self, box=box, id=str(self.data_index), fn_add=self.peak_wizard) 217 box.AddSpacer(10) 218 219 # The optimisation settings. 220 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) 221 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) 222 223 # Stretchable spacing (with a minimal space). 224 box.AddSpacer(30) 225 box.AddStretchSpacer() 226 227 # Add the execution GUI element. 228 self.button_exec_relax = self.add_execute_relax(box, self.execute) 229 230 # Return the box. 231 return box
232 233
234 - def delete(self):
235 """Unregister the spin count from the user functions.""" 236 237 # Unregister the observer methods. 238 self.observer_register(remove=True) 239 240 # Clean up the peak intensity object. 241 self.peak_intensity.delete()
242 243
244 - def execute(self, event):
245 """Set up, execute, and process the automatic Rx analysis. 246 247 @param event: The wx event. 248 @type event: wx event 249 """ 250 251 # Flush the GUI interpreter internal queue to make sure all user functions are complete. 252 self.gui.interpreter.flush() 253 254 # relax execution lock. 255 if status.exec_lock.locked(): 256 error_message("relax is currently executing.", "relax execution lock") 257 event.Skip() 258 return 259 260 # User warning to close windows. 261 self.gui.close_windows() 262 263 # Synchronise the frame data to the relax data store. 264 self.sync_ds(upload=True) 265 266 # Assemble all the data needed for the auto-analysis. 267 data, missing = self.assemble_data() 268 269 # Missing data. 270 if len(missing): 271 Missing_data(missing) 272 return 273 274 # Display the relax controller, and go to the end of the log window. 275 self.gui.show_controller(None) 276 self.gui.controller.log_panel.on_goto_end(None) 277 278 # Start the thread. 279 self.thread = Execute_rx(self.gui, data, self.data_index) 280 self.thread.start() 281 282 # Terminate the event. 283 event.Skip()
284 285
286 - def observer_register(self, remove=False):
287 """Register and unregister methods with the observer objects. 288 289 @keyword remove: If set to True, then the methods will be unregistered. 290 @type remove: False 291 """ 292 293 # Register. 294 if not remove: 295 status.observers.gui_uf.register(self.data.pipe_name, self.update_spin_count) 296 status.observers.exec_lock.register(self.data.pipe_name, self.activate) 297 298 # Unregister. 299 else: 300 # The model-free methods. 301 status.observers.gui_uf.unregister(self.data.pipe_name) 302 status.observers.exec_lock.unregister(self.data.pipe_name) 303 304 # The embedded objects methods. 305 self.peak_intensity.observer_register(remove=True)
306 307
308 - def peak_wizard(self, event):
309 """Launch the NOE peak loading wizard. 310 311 @param event: The wx event. 312 @type event: wx event 313 """ 314 315 # Change the cursor to busy. 316 wx.BeginBusyCursor() 317 318 # Initialise a wizard. 319 self.wizard = Wiz_window(parent=self.gui, size_x=1000, size_y=800, title="Set up the %s peak intensities" % self.label) 320 self.page_indices = {} 321 322 # First check that at least a single spin is named! 323 if not are_spins_named(): 324 # The message. 325 msg = "No spins have been named. Please use the spin.name user function first, otherwise it is unlikely that any data will be loaded from the peak intensity file.\n\nThis message can be ignored if the generic file format is used and spin names have not been specified. Would you like to name the spins already loaded into the relax data store?" 326 327 # Ask about naming spins, and add the spin.name user function page. 328 if status.show_gui and Question(msg, title="Incomplete setup", size=(450, 250), default=True).ShowModal() == wx.ID_YES: 329 page = Name_page(self.wizard, sync=True) 330 self.page_indices['read'] = self.wizard.add_page(page, proceed_on_error=False) 331 332 333 # The spectrum.read_intensities page. 334 self.page_intensity = Read_intensities_page(self.wizard, sync=True) 335 self.page_indices['read'] = self.wizard.add_page(self.page_intensity, skip_button=True, proceed_on_error=False) 336 337 # Error type selection page. 338 self.page_error_type = Spectral_error_type_page(self.wizard) 339 self.page_indices['err_type'] = self.wizard.add_page(self.page_error_type, apply_button=False) 340 self.wizard.set_seq_next_fn(self.page_indices['err_type'], self.wizard_page_after_error_type) 341 342 # The spectrum.replicated page. 343 page = Replicated_page(self.wizard, sync=True) 344 self.page_indices['repl'] = self.wizard.add_page(page, skip_button=True, proceed_on_error=False) 345 self.wizard.set_seq_next_fn(self.page_indices['repl'], self.wizard_page_after_repl) 346 page.on_init = self.wizard_update_repl 347 348 # The spectrum.baseplane_rmsd page. 349 page = Baseplane_rmsd_page(self.wizard, sync=True) 350 self.page_indices['rmsd'] = self.wizard.add_page(page, skip_button=True, proceed_on_error=False) 351 self.wizard.set_seq_next_fn(self.page_indices['rmsd'], self.wizard_page_after_rmsd) 352 page.on_init = self.wizard_update_rmsd 353 354 # The spectrum.integration_points page. 355 page = Integration_points_page(self.wizard, sync=True) 356 self.page_indices['pts'] = self.wizard.add_page(page, skip_button=True, proceed_on_error=False) 357 page.on_init = self.wizard_update_pts 358 359 # The relax_fit.relax_time page. 360 page = Relax_time_page(self.wizard, sync=True) 361 self.page_indices['relax_time'] = self.wizard.add_page(page, skip_button=False, proceed_on_error=False) 362 page.on_init = self.wizard_update_relax_time 363 364 # Reset the cursor. 365 if wx.IsBusy(): 366 wx.EndBusyCursor() 367 368 # Run the wizard. 369 self.wizard.run()
370 371
372 - def results_directory(self, event):
373 """The results directory selection. 374 375 @param event: The wx event. 376 @type event: wx event 377 """ 378 379 # The dialog. 380 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 381 382 # Show the dialog and catch if no file has been selected. 383 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 384 # Don't do anything. 385 return 386 387 # The path (don't do anything if not set). 388 path = gui_to_str(dialog.get_path()) 389 if not path: 390 return 391 392 # Store the path. 393 self.data.save_dir = path 394 395 # Place the path in the text box. 396 self.field_results_dir.SetValue(str_to_gui(path))
397 398
399 - def sync_ds(self, upload=False):
400 """Synchronise the analysis frame and the relax data store, both ways. 401 402 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. 403 404 @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. 405 @type upload: bool 406 """ 407 408 # The frequency. 409 if upload: 410 self.data.frq = gui_to_str(self.field_nmr_frq.GetValue()) 411 else: 412 self.field_nmr_frq.SetValue(str_to_gui(self.data.frq)) 413 414 # The grid incs. 415 if upload: 416 self.data.grid_inc = gui_to_int(self.grid_inc.GetValue()) 417 elif hasattr(self.data, 'grid_inc'): 418 self.grid_inc.SetValue(int(self.data.grid_inc)) 419 420 # The MC sim number. 421 if upload: 422 self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 423 elif hasattr(self.data, 'mc_sim_num'): 424 self.mc_sim_num.SetValue(int(self.data.mc_sim_num)) 425 426 # The results directory. 427 if upload: 428 self.data.save_dir = gui_to_str(self.field_results_dir.GetValue()) 429 else: 430 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))
431 432
434 """Set the page after the error type choice. 435 436 @return: The index of the next page, which is the current page index plus one. 437 @rtype: int 438 """ 439 440 # Go to the spectrum.baseplane_rmsd page. 441 if self.page_error_type.selection == 'rmsd': 442 return self.page_indices['rmsd'] 443 444 # Go to the spectrum.replicated page. 445 elif self.page_error_type.selection == 'repl': 446 return self.page_indices['repl']
447 448
449 - def wizard_page_after_repl(self):
450 """Set the page that comes after the spectrum.replicated page. 451 452 @return: The index of the next page. 453 @rtype: int 454 """ 455 456 # Go to the spectrum.integration_points page. 457 int_method = gui_to_str(self.page_intensity.int_method.GetValue()) 458 if int_method != 'height': 459 return self.page_indices['pts'] 460 461 # Skip to the relax_fit.relax_time page. 462 else: 463 return self.page_indices['relax_time']
464 465
466 - def wizard_page_after_rmsd(self):
467 """Set the page that comes after the spectrum.baseplane_rmsd page. 468 469 @return: The index of the next page. 470 @rtype: int 471 """ 472 473 # Go to the spectrum.integration_points page. 474 int_method = gui_to_str(self.page_intensity.int_method.GetValue()) 475 if int_method != 'height': 476 return self.page_indices['pts'] 477 478 # Skip to the relax_fit.relax_time page. 479 else: 480 return self.page_indices['relax_time']
481 482
483 - def wizard_update_pts(self):
484 """Update the spectrum.replicated page based on previous data.""" 485 486 # The spectrum.read_intensities page. 487 page = self.wizard.get_page(self.page_indices['read']) 488 489 # Set the spectrum ID. 490 id = page.spectrum_id.GetValue() 491 492 # Set the ID in the spectrum.replicated page. 493 page = self.wizard.get_page(self.page_indices['pts']) 494 page.spectrum_id.SetStringSelection(str_to_gui(id))
495 496
497 - def wizard_update_repl(self):
498 """Update the spectrum.replicated page based on previous data.""" 499 500 # The spectrum.read_intensities page. 501 page = self.wizard.get_page(self.page_indices['read']) 502 503 # Set the spectrum ID. 504 id = page.spectrum_id.GetValue() 505 506 # Set the ID in the spectrum.replicated page. 507 page = self.wizard.get_page(self.page_indices['repl']) 508 page.spectrum_id_boxes[0].SetStringSelection(str_to_gui(id))
509 510
511 - def wizard_update_rmsd(self):
512 """Update the spectrum.baseplane_rmsd page based on previous data.""" 513 514 # The spectrum.read_intensities page. 515 page = self.wizard.get_page(self.page_indices['read']) 516 517 # Set the spectrum ID. 518 id = page.spectrum_id.GetValue() 519 520 # Set the ID in the spectrum.baseplane_rmsd page. 521 page = self.wizard.get_page(self.page_indices['rmsd']) 522 page.spectrum_id.SetStringSelection(str_to_gui(id))
523 524
525 - def wizard_update_relax_time(self):
526 """Update the relax_fit.relax_time page based on previous data.""" 527 528 # The spectrum.read_intensities page. 529 page = self.wizard.get_page(self.page_indices['read']) 530 531 # Set the spectrum ID. 532 id = page.spectrum_id.GetValue() 533 534 # Set the ID in the relax_fit.relax_time page. 535 page = self.wizard.get_page(self.page_indices['relax_time']) 536 page.spectrum_id.SetStringSelection(str_to_gui(id))
537 538 539
540 -class Execute_rx(Execute):
541 """The Rx analysis execution object.""" 542
543 - def run_analysis(self):
544 """Execute the calculation.""" 545 546 # Execute. 547 Relax_fit(pipe_name=self.data.pipe_name, 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) 548 549 # Alias the relax data store data. 550 data = ds.relax_gui.analyses[self.data_index]
551