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