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