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