1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23   
 24   
 25  """Module containing the base class for the automatic R1 and R2 analysis frames.""" 
 26   
 27   
 28  from os import sep 
 29  from string import lower 
 30  import sys 
 31  import wx 
 32   
 33   
 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   
 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   
 58      """The base class for the R1 and R2 frames.""" 
 59   
 60       
 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           
 91          self.gui = gui 
 92   
 93           
 94          self.init_flag = True 
 95   
 96           
 97          if data_index == None: 
 98               
 99              if not has_pipe(pipe_name): 
100                  self.gui.interpreter.apply('pipe.create', pipe_name, 'relax_fit') 
101   
102               
103              data_index = ds.relax_gui.analyses.add(self.label) 
104   
105               
106              ds.relax_gui.analyses[data_index].analysis_name = analysis_name 
107              ds.relax_gui.analyses[data_index].pipe_name = pipe_name 
108   
109               
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           
116          self.data = ds.relax_gui.analyses[data_index] 
117          self.data_index = data_index 
118   
119           
120          self.observer_register() 
121   
122           
123          super(Auto_rx, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name) 
 124   
125   
127          """Activate or deactivate certain elements of the analysis in response to the execution lock.""" 
128   
129           
130          enable = False 
131          if not status.exec_lock.locked(): 
132              enable = True 
133   
134           
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   
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           
154          data = Container() 
155          missing = [] 
156   
157           
158          data.pipe_name = self.data.pipe_name 
159   
160           
161          frq = gui_to_str(self.field_nmr_frq.GetValue()) 
162          if frq == None: 
163              missing.append('NMR frequency') 
164   
165           
166          data.file_root = '%s.%s' % (self.analysis_type, frq) 
167   
168           
169          if not exists_mol_res_spin_data(): 
170              missing.append("Sequence data") 
171   
172           
173          if not hasattr(cdp, 'spectrum_ids') or len(cdp.spectrum_ids) < 3: 
174              missing.append("Spectral data") 
175   
176           
177          data.inc = gui_to_int(self.grid_inc.GetValue()) 
178   
179           
180          data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 
181   
182           
183          data.save_dir = self.data.save_dir 
184   
185           
186          return data, missing 
 187   
188   
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           
197          box = wx.BoxSizer(wx.VERTICAL) 
198   
199           
200          self.add_title(box, "Setup for %s relaxation analysis" % self.label) 
201   
202           
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           
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           
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           
212          self.add_spin_systems(box, self) 
213   
214           
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           
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           
224          box.AddSpacer(30) 
225          box.AddStretchSpacer() 
226   
227           
228          self.button_exec_relax = self.add_execute_relax(box, self.execute) 
229   
230           
231          return box 
 232   
233   
235          """Unregister the spin count from the user functions.""" 
236   
237           
238          self.observer_register(remove=True) 
239   
240           
241          self.peak_intensity.delete() 
 242   
243   
284   
285   
306   
307   
309          """Launch the NOE peak loading wizard. 
310   
311          @param event:   The wx event. 
312          @type event:    wx event 
313          """ 
314   
315           
316          wx.BeginBusyCursor() 
317   
318           
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           
323          if not are_spins_named(): 
324               
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               
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           
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           
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           
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           
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           
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           
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           
365          if wx.IsBusy(): 
366              wx.EndBusyCursor() 
367   
368           
369          self.wizard.run() 
 370   
371   
373          """The results directory selection. 
374   
375          @param event:   The wx event. 
376          @type event:    wx event 
377          """ 
378   
379           
380          dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 
381   
382           
383          if status.show_gui and dialog.ShowModal() != wx.ID_OK: 
384               
385              return 
386   
387           
388          path = gui_to_str(dialog.get_path()) 
389          if not path: 
390              return 
391   
392           
393          self.data.save_dir = path 
394   
395           
396          self.field_results_dir.SetValue(str_to_gui(path)) 
 397   
398   
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           
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           
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           
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           
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           
441          if self.page_error_type.selection == 'rmsd': 
442              return self.page_indices['rmsd'] 
443   
444           
445          elif self.page_error_type.selection == 'repl': 
446              return self.page_indices['repl'] 
 447   
448   
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           
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           
462          else: 
463              return self.page_indices['relax_time'] 
 464   
465   
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           
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           
479          else: 
480              return self.page_indices['relax_time'] 
 481   
482   
484          """Update the spectrum.replicated page based on previous data.""" 
485   
486           
487          page = self.wizard.get_page(self.page_indices['read']) 
488   
489           
490          id = page.spectrum_id.GetValue() 
491   
492           
493          page = self.wizard.get_page(self.page_indices['pts']) 
494          page.spectrum_id.SetStringSelection(str_to_gui(id)) 
 495   
496   
498          """Update the spectrum.replicated page based on previous data.""" 
499   
500           
501          page = self.wizard.get_page(self.page_indices['read']) 
502   
503           
504          id = page.spectrum_id.GetValue() 
505   
506           
507          page = self.wizard.get_page(self.page_indices['repl']) 
508          page.spectrum_id_boxes[0].SetStringSelection(str_to_gui(id)) 
 509   
510   
512          """Update the spectrum.baseplane_rmsd page based on previous data.""" 
513   
514           
515          page = self.wizard.get_page(self.page_indices['read']) 
516   
517           
518          id = page.spectrum_id.GetValue() 
519   
520           
521          page = self.wizard.get_page(self.page_indices['rmsd']) 
522          page.spectrum_id.SetStringSelection(str_to_gui(id)) 
 523   
524   
526          """Update the relax_fit.relax_time page based on previous data.""" 
527   
528           
529          page = self.wizard.get_page(self.page_indices['read']) 
530   
531           
532          id = page.spectrum_id.GetValue() 
533   
534           
535          page = self.wizard.get_page(self.page_indices['relax_time']) 
536          page.spectrum_id.SetStringSelection(str_to_gui(id)) 
  537   
538   
539   
541      """The Rx analysis execution object.""" 
542   
 551