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