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