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

Source Code for Module gui.analyses.auto_relax_disp

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2013-2014 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Module for the automatic relaxation dispersion analysis.""" 
 24   
 25  # Python module imports. 
 26  import wx 
 27   
 28  # relax module imports. 
 29  from auto_analyses.relax_disp import Relax_disp 
 30  from data_store import Relax_data_store; ds = Relax_data_store() 
 31  from graphics import ANALYSIS_IMAGE_PATH, fetch_icon 
 32  from gui.analyses.base import Base_analysis 
 33  from gui.analyses.elements.bool_element import Boolean_ctrl 
 34  from gui.analyses.elements.float_element import Float_ctrl 
 35  from gui.analyses.elements.spin_element import Spin_ctrl 
 36  from gui.analyses.elements.text_element import Text_ctrl 
 37  from gui.analyses.elements.model_list import Model_list 
 38  from gui.analyses.execute import Execute 
 39  from gui.base_classes import Container 
 40  from gui.components.spectrum import Spectra_list 
 41  from gui.filedialog import RelaxDirDialog 
 42  from gui.fonts import font 
 43  from gui.message import error_message, Missing_data 
 44  from gui.string_conv import float_to_gui, gui_to_float, gui_to_int, gui_to_str, str_to_gui 
 45  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 46  from gui.wizards.peak_intensity import Peak_intensity_wizard 
 47  from lib.text.gui import dw, dw_AB, dw_BC, dwH, dwH_AB, dwH_BC, i0, kex, kAB, kBC, kAC, padw2, phi_ex, phi_exB, phi_exC, r1, r1rho, r1rho_prime, r2, r2a, r2b, r2eff 
 48  from pipe_control.mol_res_spin import exists_mol_res_spin_data, spin_loop 
 49  from pipe_control.pipes import has_bundle, has_pipe 
 50  from specific_analyses.relax_disp.data import has_cpmg_exp_type, has_r1rho_exp_type 
 51  from specific_analyses.relax_disp.variables import MODEL_B14, MODEL_B14_FULL, MODEL_CR72, MODEL_CR72_FULL, MODEL_DPL94, MODEL_IT99, MODEL_LIST_CPMG, MODEL_LIST_R1RHO, MODEL_LM63, MODEL_LM63_3SITE, MODEL_M61, MODEL_M61B, MODEL_MMQ_CR72, MODEL_MP05, MODEL_NOREX, MODEL_NS_CPMG_2SITE_3D, MODEL_NS_CPMG_2SITE_3D_FULL, MODEL_NS_CPMG_2SITE_EXPANDED, MODEL_NS_CPMG_2SITE_STAR, MODEL_NS_CPMG_2SITE_STAR_FULL, MODEL_NS_MMQ_2SITE, MODEL_NS_MMQ_3SITE, MODEL_NS_MMQ_3SITE_LINEAR, MODEL_NS_R1RHO_2SITE, MODEL_NS_R1RHO_3SITE, MODEL_NS_R1RHO_3SITE_LINEAR, MODEL_R2EFF, MODEL_TAP03, MODEL_TP02, MODEL_TSMFK01 
 52  from status import Status; status = Status() 
 53   
 54   
55 -class Auto_relax_disp(Base_analysis):
56 """The relaxation dispersion auto-analysis GUI element.""" 57 58 # Hardcoded variables. 59 analysis_type = None 60 bitmap = ANALYSIS_IMAGE_PATH+"relax_disp_200x200.png" 61 label = 'Relax-disp' 62
63 - 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):
64 """Build the automatic R1 and R2 analysis GUI frame elements. 65 66 @param parent: The parent wx element. 67 @type parent: wx object 68 @keyword id: The unique ID number. 69 @type id: int 70 @keyword pos: The position. 71 @type pos: wx.Size object 72 @keyword size: The size. 73 @type size: wx.Size object 74 @keyword style: The style. 75 @type style: int 76 @keyword name: The name for the panel. 77 @type name: unicode 78 @keyword gui: The main GUI class. 79 @type gui: gui.relax_gui.Main instance 80 @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook). 81 @type analysis_name: str 82 @keyword pipe_name: The name of the data pipe associated with this analysis. 83 @type pipe_name: str 84 @keyword pipe_bundle: The name of the data pipe bundle associated with this analysis. 85 @type pipe_bundle: str 86 @keyword uf_exec: The list of user function on_execute methods returned from the new analysis wizard. 87 @type uf_exec: list of methods 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='relax_disp', 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(self.label) 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].numeric_only = False 118 ds.relax_gui.analyses[data_index].grid_inc = None 119 ds.relax_gui.analyses[data_index].mc_sim_num = None 120 ds.relax_gui.analyses[data_index].pre_run_dir = None 121 ds.relax_gui.analyses[data_index].mc_sim_all_models = False 122 ds.relax_gui.analyses[data_index].insignificance = 1.0 123 ds.relax_gui.analyses[data_index].save_dir = self.gui.launch_dir 124 125 # Set the default dispersion models based on the experiment type. 126 ds.relax_gui.analyses[data_index].disp_models = [ 127 MODEL_R2EFF, 128 MODEL_NOREX, 129 MODEL_CR72, 130 MODEL_NS_CPMG_2SITE_EXPANDED, 131 MODEL_MP05, 132 MODEL_NS_R1RHO_2SITE 133 ] 134 135 # Error checking. 136 if ds.relax_gui.analyses[data_index].pipe_bundle == None: 137 raise RelaxError("The pipe bundle must be supplied.") 138 139 # Alias the data. 140 self.data = ds.relax_gui.analyses[data_index] 141 self.data_index = data_index 142 143 # Register the method for updating the spin count for the completion of user functions. 144 self.observer_register() 145 146 # Execute the base class method to build the panel. 147 super(Auto_relax_disp, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name) 148 149 # Optimisation variables for speeding up the test suite. 150 self.opt_func_tol = 1e-25 151 self.opt_max_iterations = int(1e7) 152 153 # Update the isotope and cluster information. 154 self.update_clusters()
155 156
157 - def activate(self):
158 """Activate or deactivate certain elements of the analysis in response to the execution lock.""" 159 160 # Flag for enabling or disabling the elements. 161 enable = False 162 if not status.exec_lock.locked(): 163 enable = True 164 165 # Activate or deactivate the elements. 166 wx.CallAfter(self.field_results_dir.Enable, enable) 167 wx.CallAfter(self.field_pre_run_dir.Enable, enable) 168 wx.CallAfter(self.spin_systems.Enable, enable) 169 wx.CallAfter(self.field_cluster.Enable, enable) 170 wx.CallAfter(self.button_isotope.Enable, enable) 171 wx.CallAfter(self.button_r1.Enable, enable) 172 wx.CallAfter(self.button_chemical_shift.Enable, enable) 173 wx.CallAfter(self.button_interatom_define.Enable, enable) 174 wx.CallAfter(self.peak_intensity.Enable, enable) 175 wx.CallAfter(self.model_field.Enable, enable) 176 wx.CallAfter(self.button_exec_relax.Enable, enable)
177 178
179 - def add_buttons(self, box):
180 """Add all of the buttons. 181 182 @param box: The box element to pack the GUI element into. 183 @type box: wx.BoxSizer instance 184 """ 185 186 # Sizer. 187 sizer = wx.BoxSizer(wx.HORIZONTAL) 188 189 # Isotope type button. 190 self.button_isotope = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Spin isotope") 191 self.button_isotope.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"), wx.BITMAP_TYPE_ANY)) 192 self.button_isotope.SetFont(font.normal) 193 self.button_isotope.SetSize((-1, 25)) 194 self.button_isotope.SetToolTipString("Set the nuclear isotope types via the spin.isotope user function.") 195 self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope, self.button_isotope) 196 sizer.Add(self.button_isotope, 1, wx.ALL|wx.EXPAND, 0) 197 198 # R1 button. 199 self.button_r1 = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " %s relaxation data"%r1) 200 self.button_r1.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.fid", "22x22"), wx.BITMAP_TYPE_ANY)) 201 self.button_r1.SetFont(font.normal) 202 self.button_r1.SetSize((-1, 25)) 203 self.button_r1.SetToolTipString("Load the %s relaxation data for the off-resonance %s-type experiments. For all other experiment types this is unused. One %s data set per magnetic field strength must be loaded."%(r1, r1rho, r1)) 204 self.gui.Bind(wx.EVT_BUTTON, self.load_r1_data, self.button_r1) 205 sizer.Add(self.button_r1, 1, wx.ALL|wx.EXPAND, 0) 206 207 # Chemical shift button. 208 self.button_chemical_shift = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Chemical shift") 209 self.button_chemical_shift.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.chemical_shift", "22x22"), wx.BITMAP_TYPE_ANY)) 210 self.button_chemical_shift.SetFont(font.normal) 211 self.button_chemical_shift.SetSize((-1, 25)) 212 self.button_chemical_shift.SetToolTipString("Read chemical shifts from a peak list for the off-resonance %s-type experiments. For all other experiment types this is unused."%r1rho) 213 self.gui.Bind(wx.EVT_BUTTON, self.load_cs_data, self.button_chemical_shift) 214 sizer.Add(self.button_chemical_shift, 1, wx.ALL|wx.EXPAND, 0) 215 216 # Interatomic interaction button. 217 self.button_interatom_define = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Interatomic interaction") 218 self.button_interatom_define.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.dipole_pair", "22x22"), wx.BITMAP_TYPE_ANY)) 219 self.button_interatom_define.SetFont(font.normal) 220 self.button_interatom_define.SetSize((-1, 25)) 221 self.button_interatom_define.SetToolTipString("Define the interatomic interations via the interatom.define user function for the MQ dispersion models.") 222 self.gui.Bind(wx.EVT_BUTTON, self.interatom_define, self.button_interatom_define) 223 sizer.Add(self.button_interatom_define, 1, wx.ALL|wx.EXPAND, 0) 224 225 # value.set button. 226 self.button_value_set = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Value setting") 227 self.button_value_set.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.value", "22x22"), wx.BITMAP_TYPE_ANY)) 228 self.button_value_set.SetFont(font.normal) 229 self.button_value_set.SetSize((-1, 25)) 230 tooltip = "Set certain parameters to experimentally determined values.\n\nThis is simply used to speed up optimisation by skipping this parameter in the initial grid search. The result is that the number of dimensions in the grid search is decreased, resulting in roughly one order of magnitude decrease in time for each parameter in this part of the analysis. Important to note is that the parameter will be optimised after the initial grid search." 231 self.button_value_set.SetToolTipString(tooltip) 232 self.gui.Bind(wx.EVT_BUTTON, self.value_set, self.button_value_set) 233 sizer.Add(self.button_value_set, 1, wx.ALL|wx.EXPAND, 0) 234 235 # Add the element to the box. 236 box.Add(sizer, 0, wx.ALL|wx.EXPAND, 0)
237 238
239 - def assemble_data(self):
240 """Assemble the data required for the Auto_noe class. 241 242 @return: A container with all the data required for the auto-analysis, the missing list, and a list of models that don't match the experiment types. 243 @rtype: class instance, list of str, list of str 244 """ 245 246 # The data container. 247 data = Container() 248 missing = [] 249 model_mismatch = [] 250 251 # The pipe name and bundle. 252 data.pipe_name = self.data.pipe_name 253 data.pipe_bundle = self.data.pipe_bundle 254 255 # Results directories. 256 data.save_dir = self.data.save_dir 257 data.pre_run_dir = gui_to_str(self.field_pre_run_dir.GetValue()) 258 259 # Check if sequence data is loaded 260 if not exists_mol_res_spin_data(): 261 missing.append("Sequence data") 262 263 # Spin variables. 264 for spin, spin_id in spin_loop(return_id=True, skip_desel=True): 265 # The message skeleton. 266 msg = "Spin '%s' - %s (try the %s user function)." % (spin_id, "%s", "%s") 267 268 # Test if the nuclear isotope type has been set. 269 if not hasattr(spin, 'isotope') or spin.isotope == None: 270 missing.append(msg % ("nuclear isotope data", "spin.isotope")) 271 272 # Spectral data. 273 if not hasattr(cdp, 'spectrum_ids') or len(cdp.spectrum_ids) < 2: 274 missing.append("Spectral data") 275 276 # The dispersion models. 277 data.models = self.model_field.GetValue() 278 279 # Invalid models. 280 for model in data.models: 281 # Invalid CPMG models. 282 if model != MODEL_NOREX and model in MODEL_LIST_CPMG and not has_cpmg_exp_type(): 283 model_mismatch.append([model, 'CPMG']) 284 285 # Invalid R1rho models. 286 if model != MODEL_NOREX and model in MODEL_LIST_R1RHO and not has_r1rho_exp_type(): 287 model_mismatch.append([model, 'R1rho']) 288 289 # The numeric only solution. 290 data.numeric_only = self.numeric_only.GetValue() 291 292 # Increment size. 293 data.inc = gui_to_int(self.grid_inc.GetValue()) 294 295 # The number of Monte Carlo simulations to be used for error analysis at the end of the analysis. 296 data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 297 data.mc_sim_all_models = self.mc_sim_all_models.GetValue() 298 299 # The insignificance level. 300 data.insignificance = self.insignificance.GetValue() 301 try: 302 data.insignificance = gui_to_float(data.insignificance) 303 except: 304 missing.append("The insignificance level must be a number.") 305 306 # Optimisation precision. 307 data.opt_func_tol = self.opt_func_tol 308 data.opt_max_iterations = self.opt_max_iterations 309 310 # Return the container, the list of missing data, and any models that don't match the experiment types. 311 return data, missing, model_mismatch
312 313
314 - def build_right_box(self):
315 """Construct the right hand box to pack into the main relax_disp box. 316 317 @return: The right hand box element containing all relaxation dispersion GUI elements (excluding the bitmap) to pack into the main box. 318 @rtype: wx.BoxSizer instance 319 """ 320 321 # Use a vertical packing of elements. 322 box = wx.BoxSizer(wx.VERTICAL) 323 324 # Add the frame title. 325 self.add_title(box, "Relaxation dispersion analysis") 326 327 # Display the data pipe. 328 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) 329 330 # Add the results directory GUI element. 331 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) 332 333 # Add the results directory GUI element. 334 tooltip = "The optional directory containing the dispersion auto-analysis results from a previous run. The optimised parameters from these previous results will be used as the starting point for optimisation rather than performing a grid search. This is essential for when large spin clusters are specified, as a grid search becomes prohibitively expensive with clusters of three or more spins. At some point a RelaxError will occur because the grid search is impossibly large. For the cluster specific parameters, i.e. the populations of the states and the exchange parameters, an average value will be used as the starting point. For all other parameters, the R20 values for each spin and magnetic field, as well as the parameters related to the chemical shift difference dw, the optimised values of the previous run will be directly copied." 335 self.field_pre_run_dir = Text_ctrl(box, self, text="Previous run directory:", icon=fetch_icon('oxygen.actions.document-open-folder', "16x16"), tooltip=tooltip, tooltip_button="Select the results directory of the previous run.", fn=self.pre_run_directory, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 336 337 # Add the spin GUI element. 338 self.add_spin_systems(box, self) 339 340 # Spin cluster setup. 341 self.field_cluster = Text_ctrl(box, self, text="Spin cluster IDs:", button_text=" Cluster", icon=fetch_icon("relax.cluster", "16x16"), tooltip="The list of currently defined spin clusters. A spin cluster will share the same the dispersion parameters during the optimisation of the dispersion model. The special 'free spins' cluster ID refers to all non-clustered spins.", tooltip_button="Define clusters of spins using the relax_disp.cluster user function.", fn=self.relax_disp_cluster, button=True, editable=False, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 342 343 # Add the buttons. 344 box.AddSpacer(20) 345 self.add_buttons(box=box) 346 347 # Add the peak list selection GUI element, with spacing. 348 box.AddSpacer(20) 349 self.peak_intensity = Spectra_list(gui=self.gui, parent=self, box=box, id=str(self.data_index), fn_add=self.peak_wizard_launch, relax_disp_flag=True) 350 box.AddSpacer(10) 351 352 # Add the dispersion models GUI element, with spacing. 353 self.model_field = Disp_model_list(self, box) 354 self.model_field.set_value(self.data.disp_models) 355 356 # The numeric only solution. 357 tooltip = "The class of models to use in the final model selection.\n\nThe default of False allows all dispersion models to be compared for statistical significance in the analysis (no exchange, the analytic models and the numeric models). The value of True will activate a pure numeric solution - the analytic models will be optimised, as they are very useful for replacing the grid search for the numeric models, but the final model selection will not include them." 358 self.numeric_only = Boolean_ctrl(box, self, text="Pure numeric solutions:", default=False, tooltip=tooltip, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 359 360 # The grid search optimisation settings. 361 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) 362 363 # The MC simulation settings. 364 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) 365 self.mc_sim_all_models = Boolean_ctrl(box, self, text="Per model error analysis:", default=False, tooltip="A flag which if True will cause Monte Carlo simulations to be performed for each individual model. Otherwise Monte Carlo simulations will be reserved for the final model.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 366 367 # The speed up of grid search. 368 tooltip = "Experimental option, be careful. True will set the grid %s values from the minimum %s values. This will speed up the grid search with a factor GRID_INC^(Nr_spec_freq). For a CPMG experiment with two fields and standard GRID_INC=21, the speed-up is a factor 441." % (r2, r2eff) 369 self.set_grid_r20 = Boolean_ctrl(box, self, text="Set R20 to the minimum R2eff:", default=False, tooltip=tooltip, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 370 371 # The insignificance cutoff. 372 tooltip = "The %s/%s value in rad/s by which to judge insignificance. If the maximum difference between two points on all dispersion curves for a spin is less than this value, that spin will be deselected. This does not affect the '%s' model. Set this value to 0.0 to use all data." % (r2eff, r1rho, MODEL_NOREX) 373 self.insignificance = Float_ctrl(box, self, text="Insignificance level:", default=1.0, tooltip=tooltip, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 374 375 # Stretchable spacing (with a minimal space). 376 box.AddSpacer(30) 377 box.AddStretchSpacer() 378 379 # Add the execution GUI element. 380 self.button_exec_relax = self.add_execute_analysis(box, self.execute) 381 382 # Return the box. 383 return box
384 385
386 - def delete(self):
387 """Unregister the spin count from the user functions.""" 388 389 # Unregister the observer methods. 390 self.observer_register(remove=True) 391 392 # Clean up the peak intensity object. 393 self.peak_intensity.delete()
394 395
396 - def execute(self, event):
397 """Set up, execute, and process the automatic Rx analysis. 398 399 @param event: The wx event. 400 @type event: wx event 401 """ 402 403 # Flush the GUI interpreter internal queue to make sure all user functions are complete. 404 self.gui.interpreter.flush() 405 406 # relax execution lock. 407 if status.exec_lock.locked(): 408 error_message("relax is currently executing.", "relax execution lock") 409 event.Skip() 410 return 411 412 # User warning to close windows. 413 self.gui.close_windows() 414 415 # Synchronise the frame data to the relax data store. 416 self.sync_ds(upload=True) 417 418 # Assemble all the data needed for the auto-analysis. 419 data, missing, model_mismatch = self.assemble_data() 420 421 # Missing data. 422 if len(missing): 423 Missing_data(missing) 424 return 425 426 # Model mismatch. 427 if len(model_mismatch): 428 # Generate the text. 429 text = '' 430 for model, exp in model_mismatch: 431 text += "The '%s' %s model cannot be used as no %s experiment types have been set up.\n" % (model, exp, exp) 432 433 # The error message. 434 error_message(text, caption='Model mismatch') 435 return 436 437 # Display the relax controller, and go to the end of the log window. 438 self.gui.show_controller(None) 439 self.gui.controller.log_panel.on_goto_end(None) 440 441 # Start the thread. 442 self.thread = Execute_relax_disp(self.gui, data, self.data_index) 443 self.thread.start() 444 445 # Terminate the event. 446 event.Skip()
447 448
449 - def interatom_define(self, event=None):
450 """Define the interatomic interactions of the spins via the interatom.define user function. 451 452 @keyword event: The wx event. 453 @type event: wx event 454 """ 455 456 # Call the user function. 457 uf_store['interatom.define'](wx_wizard_modal=True, spin_id1='@N', spin_id2='@H')
458 459
460 - def load_cs_data(self, event=None):
461 """Read chemical shift data from a peak list via the chemical_shift.read user function. 462 463 @keyword event: The wx event. 464 @type event: wx event 465 """ 466 467 # Call the user function. 468 uf_store['chemical_shift.read'](wx_wizard_modal=True)
469 470
471 - def load_r1_data(self, event=None):
472 """Load R1 relaxation data via the relax_data.read user function. 473 474 @keyword event: The wx event. 475 @type event: wx event 476 """ 477 478 # Call the user function. 479 uf_store['relax_data.read'](wx_wizard_modal=True, ri_type='R1')
480 481
482 - def observer_register(self, remove=False):
483 """Register and unregister methods with the observer objects. 484 485 @keyword remove: If set to True, then the methods will be unregistered. 486 @type remove: False 487 """ 488 489 # Register. 490 if not remove: 491 status.observers.gui_uf.register('spin count - %s' % self.data.pipe_bundle, self.update_spin_count, method_name='update_spin_count') 492 status.observers.exec_lock.register(self.data.pipe_bundle, self.activate, method_name='activate') 493 status.observers.gui_uf.register('clusters - %s' % self.data.pipe_bundle, self.update_clusters, method_name='update_clusters') 494 495 # Unregister. 496 else: 497 # The methods. 498 status.observers.gui_uf.unregister('spin count - %s' % self.data.pipe_bundle) 499 status.observers.exec_lock.unregister(self.data.pipe_bundle) 500 status.observers.gui_uf.unregister('isotopes - %s' % self.data.pipe_bundle) 501 status.observers.gui_uf.unregister('clusters - %s' % self.data.pipe_bundle) 502 503 # The embedded objects methods. 504 self.peak_intensity.observer_register(remove=True)
505 506
507 - def peak_wizard_launch(self, event):
508 """Launch the peak loading wizard. 509 510 @param event: The wx event. 511 @type event: wx event 512 """ 513 514 # A new wizard instance. 515 self.peak_wizard = Peak_intensity_wizard(relax_disp=True)
516 517
518 - def pre_run_directory(self, event):
519 """The pre-run directory selection. 520 521 @param event: The wx event. 522 @type event: wx event 523 """ 524 525 # The dialog. 526 dialog = RelaxDirDialog(parent=self, message='Select the directory of the previous run', defaultPath=self.field_pre_run_dir.GetValue()) 527 528 # Show the dialog and catch if no file has been selected. 529 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 530 # Don't do anything. 531 return 532 533 # The path (don't do anything if not set). 534 path = gui_to_str(dialog.get_path()) 535 if not path: 536 return 537 538 # Place the path in the text box. 539 self.field_pre_run_dir.SetValue(str_to_gui(path))
540 541
542 - def relax_disp_cluster(self, event=None):
543 """Set up spin clustering via the relax_disp.cluster user function. 544 545 @keyword event: The wx event. 546 @type event: wx event 547 """ 548 549 # Call the user function. 550 uf_store['relax_disp.cluster'](wx_wizard_modal=True)
551 552
553 - def results_directory(self, event):
554 """The results directory selection. 555 556 @param event: The wx event. 557 @type event: wx event 558 """ 559 560 # The dialog. 561 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 562 563 # Show the dialog and catch if no file has been selected. 564 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 565 # Don't do anything. 566 return 567 568 # The path (don't do anything if not set). 569 path = gui_to_str(dialog.get_path()) 570 if not path: 571 return 572 573 # Store the path. 574 self.data.save_dir = path 575 576 # Place the path in the text box. 577 self.field_results_dir.SetValue(str_to_gui(path))
578 579
580 - def spin_isotope(self, event=None):
581 """Set the nuclear isotope types of the spins via the spin.isotope user function. 582 583 @keyword event: The wx event. 584 @type event: wx event 585 """ 586 587 # Call the user function. 588 uf_store['spin.isotope'](wx_wizard_modal=True, isotope='15N', spin_id='@N*')
589 590
591 - def sync_ds(self, upload=False):
592 """Synchronise the analysis frame and the relax data store, both ways. 593 594 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. 595 596 @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. 597 @type upload: bool 598 """ 599 600 # The numeric solution only flag. 601 if upload: 602 self.data.numeric_only = self.numeric_only.GetValue() 603 elif hasattr(self.data, 'numeric_only'): 604 self.numeric_only.SetValue(bool(self.data.numeric_only)) 605 606 # The grid incs. 607 if upload: 608 self.data.grid_inc = gui_to_int(self.grid_inc.GetValue()) 609 elif hasattr(self.data, 'grid_inc'): 610 self.grid_inc.SetValue(int(self.data.grid_inc)) 611 612 # The MC sim number. 613 if upload: 614 self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 615 elif hasattr(self.data, 'mc_sim_num'): 616 self.mc_sim_num.SetValue(int(self.data.mc_sim_num)) 617 618 # The All model MC sim flag. 619 if upload: 620 self.data.mc_sim_all_models = self.mc_sim_all_models.GetValue() 621 elif hasattr(self.data, 'mc_sim_all_models'): 622 self.mc_sim_all_models.SetValue(bool(self.data.mc_sim_all_models)) 623 624 # The insignificance level. 625 if upload: 626 self.data.insignificance = self.insignificance.GetValue() 627 try: 628 self.data.insignificance = gui_to_float(self.data.insignificance) 629 except: 630 pass 631 elif hasattr(self.data, 'insignificance'): 632 self.insignificance.SetValue(float_to_gui(self.data.insignificance)) 633 634 # The results directory. 635 if upload: 636 self.data.save_dir = gui_to_str(self.field_results_dir.GetValue()) 637 else: 638 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir)) 639 640 # The previous run results directory. 641 if upload: 642 self.data.pre_run_dir = gui_to_str(self.field_pre_run_dir.GetValue()) 643 elif hasattr(self.data, 'pre_run_dir'): 644 self.field_pre_run_dir.SetValue(str_to_gui(self.data.pre_run_dir)) 645 646 # The models to use. 647 if upload: 648 self.data.disp_models = self.model_field.GetValue() 649 else: 650 self.model_field.set_value(self.data.disp_models)
651 652
653 - def update_clusters(self):
654 """Update the cluster field.""" 655 656 # Assemble a list of all unique isotope types. 657 cluster_keys = [] 658 if hasattr(cdp, 'clustering'): 659 cluster_keys = sorted(cdp.clustering.keys()) 660 661 # Nothing yet. 662 if not len(cluster_keys): 663 wx.CallAfter(self.field_cluster.SetValue, "free spins") 664 665 # List the clusters. 666 else: 667 # Build the text to show. 668 text = "" 669 if "free spins" in cluster_keys: 670 text += "free spins" 671 for i in range(len(cluster_keys)): 672 if cluster_keys[i] != "free spins": 673 text += ", %s" % cluster_keys[i] 674 675 # Update the text. 676 wx.CallAfter(self.field_cluster.SetValue, text)
677 678
679 - def value_set(self, event=None):
680 """Launch the value.set user function. 681 682 @keyword event: The wx event. 683 @type event: wx event 684 """ 685 686 # Call the user function. 687 uf_store['value.set'](wx_wizard_modal=True)
688 689 690
691 -class Execute_relax_disp(Execute):
692 """The relaxation dispersion analysis execution object.""" 693
694 - def run_analysis(self):
695 """Execute the calculation.""" 696 697 # Optimisation precision. 698 Relax_disp.opt_func_tol = self.data.opt_func_tol 699 Relax_disp.opt_max_iterations = self.data.opt_max_iterations 700 701 # Execute. 702 Relax_disp(pipe_name=self.data.pipe_name, pipe_bundle=self.data.pipe_bundle, results_dir=self.data.save_dir, models=self.data.models, grid_inc=self.data.inc, mc_sim_num=self.data.mc_sim_num, pre_run_dir=self.data.pre_run_dir, mc_sim_all_models=self.data.mc_sim_all_models, insignificance=self.data.insignificance, numeric_only=self.data.numeric_only) 703 704 # Alias the relax data store data. 705 data = ds.relax_gui.analyses[self.data_index]
706 707 708
709 -class Disp_model_list(Model_list):
710 """The diffusion model list GUI element.""" 711 712 # Class variables. 713 desc = "Relaxation dispersion models:" 714 models = [ 715 MODEL_R2EFF, 716 None, 717 MODEL_NOREX, 718 None, 719 MODEL_LM63, 720 MODEL_LM63_3SITE, 721 MODEL_CR72, 722 MODEL_CR72_FULL, 723 MODEL_IT99, 724 MODEL_TSMFK01, 725 MODEL_B14, 726 MODEL_B14_FULL, 727 MODEL_NS_CPMG_2SITE_EXPANDED, 728 MODEL_NS_CPMG_2SITE_3D, 729 MODEL_NS_CPMG_2SITE_3D_FULL, 730 MODEL_NS_CPMG_2SITE_STAR, 731 MODEL_NS_CPMG_2SITE_STAR_FULL, 732 None, 733 MODEL_M61, 734 MODEL_M61B, 735 MODEL_DPL94, 736 MODEL_TP02, 737 MODEL_TAP03, 738 MODEL_MP05, 739 MODEL_NS_R1RHO_2SITE, 740 MODEL_NS_R1RHO_3SITE_LINEAR, 741 MODEL_NS_R1RHO_3SITE, 742 None, 743 MODEL_MMQ_CR72, 744 MODEL_NS_MMQ_2SITE, 745 MODEL_NS_MMQ_3SITE_LINEAR, 746 MODEL_NS_MMQ_3SITE 747 ] 748 params = [ 749 "{%s/%s, %s}" % (r2eff, r1rho, i0), 750 None, 751 "{%s, ...}" % (r2), 752 None, 753 "{%s, ..., %s, %s}" % (r2, phi_ex, kex), 754 "{%s, ..., %s, kB, %s, kC}" % (r2, phi_exB, phi_exC), 755 "{%s, ..., pA, %s, %s}" % (r2, dw, kex), 756 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex), 757 "{%s, ..., %s, %s, %s}" % (r2, phi_ex, padw2, kex), 758 "{%s, ..., %s, k_AB}" % (r2a, dw), 759 "{%s, ..., pA, %s, %s}" % (r2, dw, kex), 760 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex), 761 "{%s, ..., pA, %s, %s}" % (r2, dw, kex), 762 "{%s, ..., pA, %s, %s}" % (r2, dw, kex), 763 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex), 764 "{%s, ..., pA, %s, %s}" % (r2, dw, kex), 765 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex), 766 None, 767 "{%s, ..., %s, %s}" % (r1rho_prime, phi_ex, kex), 768 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex), 769 "{%s, ..., %s, %s}" % (r1rho_prime, phi_ex, kex), 770 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex), 771 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex), 772 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex), 773 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex), 774 "{%s, ..., pA, %s, %s, pB, %s, %s}" % (r1rho_prime, dw_AB, kAB, dw_BC, kBC), 775 "{%s, ..., pA, %s, %s, pB, %s, %s, %s}" % (r1rho_prime, dw_AB, kAB, dw_BC, kBC, kAC), 776 None, 777 "{%s, ..., pA, %s, %s, %s}" % (r2, dw, dwH, kex), 778 "{%s, ..., pA, %s, %s, %s}" % (r2, dw, dwH, kex), 779 "{%s, ..., pA, %s, %s, %s, pB, %s, %s, %s}" % (r2, dw_AB, dwH_AB, kAB, dw_BC, dwH_BC, kBC), 780 "{%s, ..., pA, %s, %s, %s, pB, %s, %s, %s, %s}" % (r2, dw_AB, dwH_AB, kAB, dw_BC, dwH_BC, kBC, kAC) 781 ] 782 model_desc = [ 783 "The base model for determining the %s/%s values and errors for all other models." % (r2eff, r1rho), 784 None, 785 "The model for no chemical exchange relaxation.", 786 None, 787 "The original Luz and Meiboom (1963) 2-site fast exchange equation.", 788 "The original Luz and Meiboom (1963) 3-site fast exchange equation.", 789 "The Carver and Richards (1972) 2-site equation for all time scales (with %s = %s)." % (r2a, r2b), 790 "The Carver and Richards (1972) 2-site equation for all time scales.", 791 "The Ishima and Torchia (1999) 2-site model for all time scales with pA >> pB.", 792 "The Tollinger et al. (2001) 2-site very-slow exchange model.", 793 "The Baldwin (2014) 2-site exact solution model for all time scales (with %s = %s)." % (r2a, r2b), 794 "The Baldwin (2014) 2-site exact solution model for all time scales.", 795 "The 2-site numerical solution expanded using Maple by Nikolai Skrynnikov.", 796 "The 2-site numerical solution using 3D magnetisation vectors (with %s = %s)." % (r2a, r2b), 797 "The 2-site numerical solution using 3D magnetisation vectors.", 798 "The 2-site numerical solution using complex conjugate matrices (with %s = %s)." % (r2a, r2b), 799 "The 2-site numerical solution using complex conjugate matrices.", 800 None, 801 "The Meiboom (1961) 2-site fast exchange equation.", 802 "The Meiboom (1961) 2-site equation for all time scales with pA >> pB.", 803 "The Davis, Perlman and London (1994) 2-site fast exchange equation.", 804 "The Trott and Palmer (2002) 2-site equation for all time scales.", 805 "The Trott, Abergel and Palmer (2003) off-resonance 2-site equation for all time scales.", 806 "The Miloushev and Palmer (2005) off-resonance 2-site equation for all time scales.", 807 "The 2-site numerical solution using 3D magnetisation vectors.", 808 "The 3-site linearised numerical solution using 3D magnetisation vectors.", 809 "The 3-site numerical solution using 3D magnetisation vectors.", 810 None, 811 "The CR72 2-site model extended to MMQ CPMG data by Korzhnev et al., 2004.", 812 "The 2-site numerical solution of Korzhnev et al. (2004) from multi-quantum CPMG data.", 813 "The 3-site linearised numerical solution of Korzhnev et al. (2005) for MMQ CPMG data.", 814 "The 3-site numerical solution of Korzhnev et al. (2005) for MMQ CPMG data." 815 ] 816 size = wx.Size(1024, 750) 817 tooltip = "The list of all relaxation dispersion models to be optimised as part of the protocol." 818 tooltip_button = "Open the model list selector window."
819