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

Source Code for Module gui.analyses.auto_model_free

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2009-2010 Michael Bieri                                       # 
   4  # Copyright (C) 2009-2013,2015 Edward d'Auvergne                              # 
   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 model-free protocol frame.""" 
  25   
  26  # Python module imports. 
  27  from math import ceil 
  28  from os import sep 
  29  import wx 
  30  import wx.lib.buttons 
  31  import wx.lib.mixins.listctrl 
  32   
  33  # relax module imports. 
  34  from auto_analyses import dauvergne_protocol 
  35  from data_store import Relax_data_store; ds = Relax_data_store() 
  36  from graphics import ANALYSIS_IMAGE_PATH, IMAGE_PATH, fetch_icon 
  37  from gui.about import About_base 
  38  from gui.analyses.base import Base_analysis 
  39  from gui.analyses.elements.spin_element import Spin_ctrl 
  40  from gui.analyses.elements.text_element import Text_ctrl 
  41  from gui.analyses.execute import Execute 
  42  from gui.analyses.elements.model_list import Model_list 
  43  from gui.base_classes import Container 
  44  from gui.components.relax_data import Relax_data_list 
  45  from gui.filedialog import RelaxDirDialog 
  46  from gui.fonts import font 
  47  from gui.message import error_message, Missing_data 
  48  from gui.misc import add_border, bitmap_setup 
  49  from gui.string_conv import gui_to_int, gui_to_str, str_to_gui 
  50  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
  51  from gui.wizards.wiz_objects import Wiz_window 
  52  from lib.physical_constants import NH_BOND_LENGTH 
  53  from lib.errors import RelaxError 
  54  from lib.text.gui import local_tm, rex, s2, s2f, te, tf, tm, ts 
  55  from lib.text.string import LIST, PARAGRAPH, SECTION, SUBSECTION, TITLE 
  56  from pipe_control.interatomic import interatomic_loop 
  57  from pipe_control.mol_res_spin import exists_mol_res_spin_data, return_spin, spin_loop 
  58  from pipe_control.pipes import has_bundle, has_pipe 
  59  from specific_analyses.api import return_api 
  60  from status import Status; status = Status() 
  61   
  62   
63 -class About_window(About_base):
64 """The model-free about window.""" 65 66 # The relax background colour. 67 colour1 = '#e5feff' 68 colour2 = '#88cbff' 69 70 # Dimensions. 71 dim_x = 800 72 dim_y = 800 73 max_y = 2500 74 75 # Spacer size (px). 76 border = 10 77 78 # Window style. 79 style = wx.DEFAULT_DIALOG_STYLE 80 81 # Destroy on clicking. 82 DESTROY_ON_CLICK = False 83
84 - def __init__(self, parent):
85 """Set up the user function class.""" 86 87 # Execute the base class method. 88 super(About_window, self).__init__(parent, id=-1, title="Automatic model-free analysis about window")
89 90
91 - def build_widget(self):
92 """Build the dialog using the dauvergne_protocol docstring.""" 93 94 # A global Y offset for packing the elements together (initialise to the border position). 95 self.offset(self.border) 96 97 # Loop over the lines. 98 for i in range(len(dauvergne_protocol.doc)): 99 # The level and text. 100 level, text = dauvergne_protocol.doc[i] 101 102 # The title. 103 if level == TITLE: 104 self.draw_title(text, alt_font=font.roman_font_18) 105 106 # The section. 107 elif level == SECTION: 108 self.draw_title(text, alt_font=font.roman_font_14) 109 110 # The section. 111 elif level == SUBSECTION: 112 self.draw_title(text, alt_font=font.roman_font_12) 113 114 # Paragraphs. 115 elif level == PARAGRAPH: 116 self.draw_wrapped_text(text) 117 118 # Lists. 119 elif level == LIST: 120 # Start of list. 121 if i and dauvergne_protocol.doc[i-1][0] != LIST: 122 self.offset(10) 123 124 # The text. 125 self.draw_wrapped_text(" - %s" % text) 126 127 # End of list. 128 if i < len(dauvergne_protocol.doc) and dauvergne_protocol.doc[i+1][0] == PARAGRAPH: 129 self.offset(10) 130 131 # Add space to the bottom. 132 self.offset(self.border) 133 134 # Round the offset up to the nearest factor of the scroll inc (needed for all scrolling). 135 scroll_x, scroll_y = self.window.GetScrollPixelsPerUnit() 136 y = self.offset() 137 self.offset(-y) 138 y = int(ceil(y/float(scroll_y)) * scroll_y) 139 self.offset(y) 140 141 # Resize the window. 142 dim_x = self.dim_x 143 virt_y = self.offset() 144 self.SetSize((dim_x, self.dim_y)) 145 self.window.SetVirtualSize((dim_x, virt_y)) 146 self.window.EnableScrolling(False, True)
147 148 149
150 -class Auto_model_free(Base_analysis):
151 """The model-free auto-analysis GUI element.""" 152
153 - 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):
154 """Build the automatic model-free protocol GUI element. 155 156 @param parent: The parent wx element. 157 @type parent: wx object 158 @keyword id: The unique ID number. 159 @type id: int 160 @keyword pos: The position. 161 @type pos: wx.Size object 162 @keyword size: The size. 163 @type size: wx.Size object 164 @keyword style: The style. 165 @type style: int 166 @keyword name: The name for the panel. 167 @type name: unicode 168 @keyword gui: The main GUI class. 169 @type gui: gui.relax_gui.Main instance 170 @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook). 171 @type analysis_name: str 172 @keyword pipe_name: The name of the original data pipe for this analysis. 173 @type pipe_name: str 174 @keyword pipe_bundle: The name of the data pipe bundle associated with this analysis. 175 @type pipe_bundle: str 176 @keyword uf_exec: The list of user function on_execute methods returned from the new analysis wizard. 177 @type uf_exec: list of methods 178 @keyword data_index: The index of the analysis in the relax data store (set to None if no data currently exists). 179 @type data_index: None or int 180 """ 181 182 # Store the GUI main class. 183 self.gui = gui 184 185 # Init. 186 self.init_flag = True 187 188 # New data container. 189 if data_index == None: 190 # First create the data pipe if not already in existence. 191 if not has_pipe(pipe_name): 192 self.gui.interpreter.apply('pipe.create', pipe_name=pipe_name, pipe_type='mf', bundle=pipe_bundle) 193 194 # Create the data pipe bundle if needed. 195 if not has_bundle(pipe_bundle): 196 self.gui.interpreter.apply('pipe.bundle', bundle=pipe_bundle, pipe=pipe_name) 197 198 # Generate a storage container in the relax data store, and alias it for easy access. 199 data_index = ds.relax_gui.analyses.add('model-free') 200 201 # Store the analysis and pipe names. 202 ds.relax_gui.analyses[data_index].analysis_name = analysis_name 203 ds.relax_gui.analyses[data_index].pipe_name = pipe_name 204 ds.relax_gui.analyses[data_index].pipe_bundle = pipe_bundle 205 206 # Initialise the variables. 207 ds.relax_gui.analyses[data_index].grid_inc = None 208 ds.relax_gui.analyses[data_index].diff_tensor_grid_inc = {'sphere': 11, 'prolate': 11, 'oblate': 11, 'ellipsoid': 6} 209 ds.relax_gui.analyses[data_index].mc_sim_num = None 210 ds.relax_gui.analyses[data_index].save_dir = self.gui.system_cwd_path 211 ds.relax_gui.analyses[data_index].local_tm_models = ['tm0', 'tm1', 'tm2', 'tm3', 'tm4', 'tm5', 'tm6', 'tm7', 'tm8', 'tm9'] 212 ds.relax_gui.analyses[data_index].mf_models = ['m0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9'] 213 ds.relax_gui.analyses[data_index].max_iter = 30 214 215 # Error checking. 216 if ds.relax_gui.analyses[data_index].pipe_bundle == None: 217 raise RelaxError("The pipe bundle must be supplied.") 218 219 # Alias the data. 220 self.data = ds.relax_gui.analyses[data_index] 221 self.data_index = data_index 222 223 # Backward compatibility. 224 if not hasattr(self.data, 'local_tm_models'): 225 self.data.local_tm_models = ['tm0', 'tm1', 'tm2', 'tm3', 'tm4', 'tm5', 'tm6', 'tm7', 'tm8', 'tm9'] 226 if not hasattr(self.data, 'mf_models'): 227 self.data.mf_models = ['m0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9'] 228 229 # Initialise the mode selection window. 230 self.mode_win = Protocol_mode_sel_window() 231 232 # Register the method for updating the spin count for the completion of user functions. 233 self.observer_register() 234 235 # Execute the base class method to build the panel. 236 super(Auto_model_free, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name)
237 238
239 - def _about(self, event=None):
240 """The about window. 241 242 @keyword event: The wx event. 243 @type event: wx event 244 """ 245 246 # Initialise the dialog. 247 self.about_dialog = About_window(self) 248 249 # Show the dialog. 250 if status.show_gui: 251 self.about_dialog.Show()
252 253
254 - def activate(self):
255 """Activate or deactivate certain elements of the analysis in response to the execution lock.""" 256 257 # Flag for enabling or disabling the elements. 258 enable = False 259 if not status.exec_lock.locked(): 260 enable = True 261 262 # Activate or deactivate the elements. 263 wx.CallAfter(self.field_results_dir.Enable, enable) 264 wx.CallAfter(self.spin_systems.Enable, enable) 265 wx.CallAfter(self.relax_data.Enable, enable) 266 wx.CallAfter(self.button_dipole_pair.Enable, enable) 267 wx.CallAfter(self.button_csa.Enable, enable) 268 wx.CallAfter(self.button_isotope_heteronuc.Enable, enable) 269 wx.CallAfter(self.button_isotope_proton.Enable, enable) 270 wx.CallAfter(self.local_tm_model_field.Enable, enable) 271 wx.CallAfter(self.mf_model_field.Enable, enable) 272 wx.CallAfter(self.grid_inc.Enable, enable) 273 wx.CallAfter(self.mc_sim_num.Enable, enable) 274 wx.CallAfter(self.max_iter.Enable, enable) 275 wx.CallAfter(self.mode.Enable, enable) 276 wx.CallAfter(self.button_exec_relax.Enable, enable)
277 278
279 - def add_values(self, box):
280 """Create and add the value.set buttons for the model-free analysis. 281 282 @param box: The box element to pack the GUI element into. 283 @type box: wx.BoxSizer instance 284 """ 285 286 # Sizer. 287 sizer = wx.BoxSizer(wx.HORIZONTAL) 288 289 # Dipole-dipole relaxation setup button. 290 self.button_dipole_pair = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Dipolar relaxation") 291 self.button_dipole_pair.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.dipole_pair", "22x22"), wx.BITMAP_TYPE_ANY)) 292 self.button_dipole_pair.SetFont(font.normal) 293 self.button_dipole_pair.SetSize((-1, 25)) 294 self.button_dipole_pair.SetToolTipString("Define the magnetic dipole-dipole relaxation mechanism.") 295 self.gui.Bind(wx.EVT_BUTTON, self.setup_dipole_pair, self.button_dipole_pair) 296 sizer.Add(self.button_dipole_pair, 1, wx.ALL|wx.EXPAND, 0) 297 298 # CSA button. 299 self.button_csa = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " CSA relaxation") 300 self.button_csa.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.align_tensor", "22x22"), wx.BITMAP_TYPE_ANY)) 301 self.button_csa.SetFont(font.normal) 302 self.button_csa.SetSize((-1, 25)) 303 self.button_csa.SetToolTipString("Define the Chemical Shift Anisotropy (CSA) relaxation mechanism via the value.set user function.") 304 self.gui.Bind(wx.EVT_BUTTON, self.value_set_csa, self.button_csa) 305 sizer.Add(self.button_csa, 1, wx.ALL|wx.EXPAND, 0) 306 307 # Isotope type button (heteronucleus). 308 self.button_isotope_heteronuc = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " X isotope") 309 self.button_isotope_heteronuc.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"), wx.BITMAP_TYPE_ANY)) 310 self.button_isotope_heteronuc.SetFont(font.normal) 311 self.button_isotope_heteronuc.SetSize((-1, 25)) 312 self.button_isotope_heteronuc.SetToolTipString("Set the nuclear isotope types of the heteronuclear spins via the spin.isotope user function.") 313 self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope_heteronuc, self.button_isotope_heteronuc) 314 sizer.Add(self.button_isotope_heteronuc, 1, wx.ALL|wx.EXPAND, 0) 315 316 # Isotope type button (proton). 317 self.button_isotope_proton = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " H isotope") 318 self.button_isotope_proton.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"), wx.BITMAP_TYPE_ANY)) 319 self.button_isotope_proton.SetFont(font.normal) 320 self.button_isotope_proton.SetSize((-1, 25)) 321 self.button_isotope_proton.SetToolTipString("Set the nuclear isotope types of the proton spins via the spin.isotope user function.") 322 self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope_proton, self.button_isotope_proton) 323 sizer.Add(self.button_isotope_proton, 1, wx.ALL|wx.EXPAND, 0) 324 325 # Add the element to the box. 326 box.Add(sizer, 0, wx.ALL|wx.EXPAND, 0)
327 328
329 - def assemble_data(self):
330 """Assemble the data required for the auto-analysis. 331 332 See the docstring for auto_analyses.dauvernge_protocol for details. All data is taken from the relax data store, so data upload from the GUI to there must have been previously performed. 333 334 @return: A container with all the data required for the auto-analysis. 335 @rtype: class instance, list of str 336 """ 337 338 # The data container. 339 data = Container() 340 missing = [] 341 342 # The pipe name and bundle. 343 data.pipe_name = self.data.pipe_name 344 data.pipe_bundle = self.data.pipe_bundle 345 346 # The model-free models (do not change these unless absolutely necessary). 347 data.local_tm_models = self.local_tm_model_field.GetValue() 348 data.mf_models = self.mf_model_field.GetValue() 349 350 # Automatic looping over all rounds until convergence (must be a boolean value of True or False). 351 data.conv_loop = True 352 353 # Increment size. 354 data.inc = gui_to_int(self.grid_inc.GetValue()) 355 if hasattr(self.data, 'diff_tensor_grid_inc'): 356 data.diff_tensor_grid_inc = self.data.diff_tensor_grid_inc 357 else: 358 data.diff_tensor_grid_inc = {'sphere': 11, 'prolate': 11, 'oblate': 11, 'ellipsoid': 6} 359 360 # The number of Monte Carlo simulations to be used for error analysis at the end of the analysis. 361 data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 362 363 # Number of maximum iterations. 364 data.max_iter = self.data.max_iter 365 366 # Results directory. 367 data.save_dir = self.data.save_dir 368 369 # Check if sequence data is loaded 370 if not exists_mol_res_spin_data(): 371 missing.append("Sequence data") 372 373 # Relaxation data. 374 if not hasattr(cdp, 'ri_ids') or len(cdp.ri_ids) == 0: 375 missing.append("Relaxation data") 376 377 # Insufficient data. 378 if hasattr(cdp, 'ri_ids') and len(cdp.ri_ids) <= 3: 379 missing.append("Insufficient relaxation data, 4 or more data sets are essential for the execution of the dauvergne_protocol auto-analysis. Check that you have entered data for a least two spectrometer fields.") 380 381 # Interatomic data containers. 382 if not hasattr(cdp, 'interatomic') or len(cdp.interatomic) == 0: 383 missing.append("Interatomic data (for the dipole-dipole interaction)") 384 385 # Get the mode. 386 mode = gui_to_str(self.mode.GetValue()) 387 388 # Solve for all global models. 389 if mode == 'Fully automated': 390 # The global model list. 391 data.global_models = ['local_tm', 'sphere', 'prolate', 'oblate', 'ellipsoid', 'final'] 392 393 # Any global model selected. 394 else: 395 data.global_models = [mode] 396 397 # Check for vectors. 398 vector_check = False 399 if 'prolate' in data.global_models or 'oblate' in data.global_models or 'ellipsoid' in data.global_models: 400 vector_check = True 401 402 # Spin variables. 403 for spin, spin_id in spin_loop(return_id=True): 404 # Skip deselected spins. 405 if not spin.select: 406 continue 407 408 # The message skeleton. 409 msg = "Spin '%s' - %s (try the %s user function)." % (spin_id, "%s", "%s") 410 411 # Test if the nuclear isotope type has been set. 412 if not hasattr(spin, 'isotope') or spin.isotope == None: 413 missing.append(msg % ("nuclear isotope data", "spin.isotope")) 414 415 # Test if the CSA value has been set for the heteronuclei. 416 if (hasattr(spin, 'isotope') and spin.isotope in ['15N', '13C']) and (not hasattr(spin, 'csa') or spin.csa == None): 417 missing.append(msg % ("CSA data", "value.set")) 418 419 # Interatomic data container variables. 420 for interatom in interatomic_loop(): 421 # Get the spin containers. 422 spin1 = return_spin(spin_hash=interatom._spin_hash1) 423 spin2 = return_spin(spin_hash=interatom._spin_hash2) 424 425 # Skip deselected spins. 426 if not spin1.select: 427 continue 428 if not spin2.select: 429 continue 430 431 # The message skeleton. 432 msg = "Spin pair '%s' and '%s' - %s (try the %s user function)." % (interatom.spin_id1, interatom.spin_id2, "%s", "%s") 433 434 # Test if the interatomic distance has been set. 435 if not hasattr(interatom, 'r') or interatom.r == None: 436 missing.append(msg % ("bond length data", "value.set")) 437 438 # Test if the unit vectors have been loaded. 439 if vector_check and (not hasattr(interatom, 'vector') or interatom.vector is None): 440 missing.append(msg % ("unit vectors", "interatom.unit_vectors")) 441 442 # Return the container and list of missing data. 443 return data, missing
444 445
446 - def build_left_box(self):
447 """Construct the left hand box to pack into the main model-free box. 448 449 @return: The left hand box element containing the bitmap and about button to pack into the main model-free box. 450 @rtype: wx.BoxSizer instance 451 """ 452 453 # Build the left hand box. 454 left_box = wx.BoxSizer(wx.VERTICAL) 455 456 # The images. 457 bitmaps = [ANALYSIS_IMAGE_PATH+"model_free"+sep+"model_free_200x200.png", 458 IMAGE_PATH+'modelfree.png'] 459 460 # Add the model-free bitmap picture. 461 for i in range(len(bitmaps)): 462 # The bitmap. 463 bitmap = wx.StaticBitmap(self, -1, bitmap_setup(bitmaps[i])) 464 465 # Add it. 466 left_box.Add(bitmap, 0, wx.ALL, 0) 467 468 # A spacer. 469 left_box.AddStretchSpacer() 470 471 # A button sizer, with some initial spacing. 472 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 473 474 # An about button. 475 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, "About") 476 button.SetBitmapLabel(wx.Bitmap(fetch_icon('oxygen.actions.help-about', "22x22"), wx.BITMAP_TYPE_ANY)) 477 button.SetFont(font.normal) 478 button.SetToolTipString("Information about this automatic analysis") 479 480 # Bind the click. 481 self.Bind(wx.EVT_BUTTON, self._about, button) 482 483 # A cursor for the button. 484 cursor = wx.StockCursor(wx.CURSOR_QUESTION_ARROW) 485 button.SetCursor(cursor) 486 487 # Pack the button. 488 button_sizer.Add(button, 0, 0, 0) 489 left_box.Add(button_sizer, 0, wx.ALL, 0) 490 491 # Return the packed box. 492 return left_box
493 494
495 - def build_right_box(self):
496 """Construct the right hand box to pack into the main model-free box. 497 498 @return: The right hand box element containing all model-free GUI elements (excluding the bitmap) to pack into the main model-free box. 499 @rtype: wx.BoxSizer instance 500 """ 501 502 # Use a vertical packing of elements. 503 box = wx.BoxSizer(wx.VERTICAL) 504 505 # Add the frame title. 506 self.add_title(box, "Model-free analysis") 507 508 # Display the data pipe. 509 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) 510 511 # Add the results directory GUI element. 512 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) 513 514 # Add the spin GUI element. 515 self.add_spin_systems(box, self) 516 517 # Add the relaxation data list GUI element, with spacing. 518 box.AddSpacer(10) 519 self.relax_data = Relax_data_list(gui=self.gui, parent=self, box=box, id=str(self.data_index)) 520 box.AddSpacer(10) 521 522 # Add the value.set buttons. 523 self.add_values(box) 524 box.AddSpacer(10) 525 526 # Add the local tau_m models GUI element, with spacing. 527 self.local_tm_model_field = Local_tm_list(self, box) 528 self.local_tm_model_field.set_value(self.data.local_tm_models) 529 530 # Add the model-free models GUI element, with spacing. 531 self.mf_model_field = Mf_list(self, box) 532 self.mf_model_field.set_value(self.data.mf_models) 533 534 # The optimisation settings. 535 self.grid_inc = Spin_ctrl(box, self, text="Grid search increments:", default=11, 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) 536 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.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 537 538 # Add maximum iteration selector. 539 self.max_iter = Spin_ctrl(box, self, text="Maximum iterations:", default=self.data.max_iter, tooltip="The maximum number of iterations for the protocol. This is the limit for the global looping over the optimisation of the model-free models, model elimination, model selection and then optimisation of the diffusion tensor.", min=25, max=100, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 540 541 # The calculation mode. 542 self.mode = Text_ctrl(box, self, text="Protocol mode:", default='Fully automated', tooltip="Select if the dauvergne_protocol analysis will be fully automated or whether the individual global models will be optimised separately.", tooltip_button="Open the protocol mode selection window.", icon=fetch_icon('oxygen.actions.system-run', "16x16"), fn=self.mode_dialog, editable=False, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal) 543 544 # Stretchable spacing (with a minimal space). 545 box.AddSpacer(30) 546 box.AddStretchSpacer() 547 548 # Add the execution GUI element. 549 self.button_exec_relax = self.add_execute_analysis(box, self.execute) 550 551 # Return the box. 552 return box
553 554
555 - def delete(self):
556 """Unregister the spin count from the user functions.""" 557 558 # Unregister the observer methods. 559 self.observer_register(remove=True) 560 561 # Clean up the relaxation data list object. 562 self.relax_data.delete() 563 564 # Destroy the dipole-dipole interaction wizard. 565 if hasattr(self, 'dipole_wizard'): 566 self.dipole_wizard.Destroy() 567 del self.dipole_wizard 568 569 # Destroy the mode selection window. 570 self.mode_win.Destroy() 571 del self.mode_win 572 573 # Destroy the model list windows. 574 self.local_tm_model_field.model_win.Destroy() 575 del self.local_tm_model_field 576 self.mf_model_field.model_win.Destroy() 577 del self.mf_model_field 578 579 # Destroy the missing data dialog, if present. 580 if hasattr(self, 'missing_data'): 581 self.missing_data.Destroy() 582 del self.missing_data
583 584
585 - def execute(self, event=None):
586 """Set up, execute, and process the automatic model-free protocol. 587 588 @keyword event: The wx event. 589 @type event: wx event 590 """ 591 592 # Flush the GUI interpreter internal queue to make sure all user functions are complete. 593 self.gui.interpreter.flush() 594 595 # relax execution lock. 596 if status.exec_lock.locked(): 597 error_message("relax is currently executing.", "relax execution lock") 598 event.Skip() 599 return 600 601 # User warning to close windows. 602 self.gui.close_windows() 603 604 # Synchronise the frame data to the relax data store. 605 self.sync_ds(upload=True) 606 607 # Assemble all the data needed for the auto-analysis. 608 data, missing = self.assemble_data() 609 610 # Missing data. 611 if len(missing): 612 self.missing_data = Missing_data(missing) 613 return 614 615 # Display the relax controller, and go to the end of the log window. 616 self.gui.show_controller(None) 617 self.gui.controller.log_panel.on_goto_end(None) 618 619 # Start the thread. 620 self.thread = Execute_mf(self.gui, data, self.data_index) 621 self.thread.start() 622 623 # Terminate the event. 624 event.Skip()
625 626
627 - def mode_dialog(self, event=None):
628 """The calculation mode selection. 629 630 @keyword event: The wx event. 631 @type event: wx event 632 """ 633 634 # Show the model selector window. 635 if status.show_gui: 636 self.mode_win.ShowModal() 637 638 # Set the model. 639 self.mode.SetValue(str_to_gui(self.mode_win.select))
640 641
642 - def observer_register(self, remove=False):
643 """Register and unregister methods with the observer objects. 644 645 @keyword remove: If set to True, then the methods will be unregistered. 646 @type remove: False 647 """ 648 649 # Register. 650 if not remove: 651 status.observers.gui_uf.register(self.data.pipe_bundle, self.update_spin_count, method_name='update_spin_count') 652 status.observers.exec_lock.register(self.data.pipe_bundle, self.activate, method_name='activate') 653 654 # Unregister. 655 else: 656 # The model-free methods. 657 status.observers.gui_uf.unregister(self.data.pipe_bundle) 658 status.observers.exec_lock.unregister(self.data.pipe_bundle) 659 660 # The embedded objects methods. 661 self.relax_data.observer_register(remove=True)
662 663
664 - def results_directory(self, event=None):
665 """The results directory selection. 666 667 @keyword event: The wx event. 668 @type event: wx event 669 """ 670 671 # The dialog. 672 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue()) 673 674 # Show the dialog and catch if no file has been selected. 675 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 676 # Don't do anything. 677 return 678 679 # The path (don't do anything if not set). 680 path = gui_to_str(dialog.get_path()) 681 if not path: 682 return 683 684 # Store the path. 685 self.data.save_dir = path 686 687 # Place the path in the text box. 688 self.field_results_dir.SetValue(str_to_gui(path))
689 690
691 - def setup_dipole_pair(self, event=None):
692 """Create the wizard for the dipole-dipole interaction. 693 694 @keyword event: The wx event. 695 @type event: wx event 696 """ 697 698 # Change the cursor to busy. 699 wx.BeginBusyCursor() 700 701 # Destroy the dipole-dipole interaction wizard, if it exists. 702 if hasattr(self, 'dipole_wizard'): 703 self.dipole_wizard.Destroy() 704 705 # Create the wizard. 706 self.dipole_wizard = Wiz_window(parent=self.gui, size_x=1000, size_y=750, title="Dipole-dipole interaction setup") 707 708 # Structural data. 709 if not hasattr(cdp, 'structure'): 710 # Create the PDB reading page. 711 page = uf_store['structure.read_pdb'].create_page(self.dipole_wizard, sync=True) 712 self.dipole_wizard.add_page(page, skip_button=True) 713 714 # Create the position reading page. 715 page = uf_store['structure.get_pos'].create_page(self.dipole_wizard, sync=True) 716 self.dipole_wizard.add_page(page, skip_button=True) 717 718 # Create the interatom.define page. 719 page = uf_store['interatom.define'].create_page(self.dipole_wizard, sync=True) 720 page.SetValue('spin_id1', '@N') 721 page.SetValue('spin_id2', '@H') 722 self.dipole_wizard.add_page(page) 723 724 # Create the interatom.set_dist page. 725 page = uf_store['interatom.set_dist'].create_page(self.dipole_wizard, sync=True) 726 page.SetValue('spin_id1', '@N*') 727 page.SetValue('spin_id2', '@H*') 728 page.SetValue('ave_dist', NH_BOND_LENGTH) 729 self.dipole_wizard.add_page(page) 730 731 # Create the interatom.unit_vectors page. 732 page = uf_store['interatom.unit_vectors'].create_page(self.dipole_wizard, sync=True) 733 self.dipole_wizard.add_page(page) 734 735 # Reset the cursor. 736 if wx.IsBusy(): 737 wx.EndBusyCursor() 738 739 # Execute the wizard. 740 self.dipole_wizard.run()
741 742
743 - def spin_isotope_heteronuc(self, event=None):
744 """Set the nuclear isotope types of the heteronuclear spins via the spin.isotope user function. 745 746 @keyword event: The wx event. 747 @type event: wx event 748 """ 749 750 # Call the user function. 751 uf_store['spin.isotope'](isotope='15N', spin_id='@N*')
752 753
754 - def spin_isotope_proton(self, event=None):
755 """Set the nuclear isotope types of the proton spins via the spin.isotope user function. 756 757 @keyword event: The wx event. 758 @type event: wx event 759 """ 760 761 # Call the user function. 762 uf_store['spin.isotope'](isotope='1H', spin_id='@H*')
763 764
765 - def sync_ds(self, upload=False):
766 """Synchronise the analysis frame and the relax data store, both ways. 767 768 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. 769 770 @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. 771 @type upload: bool 772 """ 773 774 # The local tau_m models to use. 775 if upload: 776 self.data.local_tm_models = self.local_tm_model_field.GetValue() 777 else: 778 self.local_tm_model_field.set_value(self.data.local_tm_models) 779 780 # The model-free models to use. 781 if upload: 782 self.data.mf_models = self.mf_model_field.GetValue() 783 else: 784 self.mf_model_field.set_value(self.data.mf_models) 785 786 # The grid incs. 787 if upload: 788 self.data.grid_inc = gui_to_int(self.grid_inc.GetValue()) 789 elif hasattr(self.data, 'grid_inc'): 790 self.grid_inc.SetValue(int(self.data.grid_inc)) 791 792 # The MC sim number. 793 if upload: 794 self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue()) 795 elif hasattr(self.data, 'mc_sim_num'): 796 self.mc_sim_num.SetValue(int(self.data.mc_sim_num)) 797 798 # The results directory. 799 if upload: 800 self.data.save_dir = str(self.field_results_dir.GetValue()) 801 else: 802 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir)) 803 804 # Maximum iterations. 805 if upload: 806 self.data.max_iter = gui_to_int(self.max_iter.GetValue()) 807 else: 808 self.max_iter.SetValue(int(self.data.max_iter))
809 810
811 - def value_set_csa(self, event=None):
812 """Set the CSA via the value.set uf. 813 814 @keyword event: The wx event. 815 @type event: wx event 816 """ 817 818 # Get the default value. 819 api = return_api() 820 val = api.default_value('csa') 821 822 # Call the user function. 823 uf_store['value.set'](val=val, param='csa', spin_id='@N*')
824 825 826
827 -class Execute_mf(Execute):
828 """The model-free analysis execution object.""" 829
830 - def run_analysis(self):
831 """Execute the calculation.""" 832 833 # Start the protocol. 834 dauvergne_protocol.dAuvergne_protocol(pipe_name=self.data.pipe_name, pipe_bundle=self.data.pipe_bundle, results_dir=self.data.save_dir, diff_model=self.data.global_models, mf_models=self.data.mf_models, local_tm_models=self.data.local_tm_models, grid_inc=self.data.inc, diff_tensor_grid_inc=self.data.diff_tensor_grid_inc, mc_sim_num=self.data.mc_sim_num, max_iter=self.data.max_iter, conv_loop=self.data.conv_loop)
835 836 837
838 -class Local_tm_list(Model_list):
839 """The local model-free model list GUI element.""" 840 841 # Some class variables. 842 desc = "Local %s models:" % tm 843 model_desc = [ 844 "Model m0 with a local molecular correlation time (%s)." % tm, 845 "Model m1 with a local molecular correlation time (%s)." % tm, 846 "Model m2 with a local molecular correlation time (%s)." % tm, 847 "Model m3 with a local molecular correlation time (%s)." % tm, 848 "Model m4 with a local molecular correlation time (%s)." % tm, 849 "Model m5 with a local molecular correlation time (%s)." % tm, 850 "Model m6 with a local molecular correlation time (%s)." % tm, 851 "Model m7 with a local molecular correlation time (%s)." % tm, 852 "Model m8 with a local molecular correlation time (%s)." % tm, 853 "Model m9 with a local molecular correlation time (%s)." % tm 854 ] 855 models = [ 856 "tm0", 857 "tm1", 858 "tm2", 859 "tm3", 860 "tm4", 861 "tm5", 862 "tm6", 863 "tm7", 864 "tm8", 865 "tm9" 866 ] 867 params = [ 868 "{%s}" % local_tm, 869 "{%s, %s}" % (local_tm, s2), 870 "{%s, %s, %s}" % (local_tm, s2, te), 871 "{%s, %s, %s}" % (local_tm, s2, rex), 872 "{%s, %s, %s, %s}" % (local_tm, s2, te, rex), 873 "{%s, %s, %s, %s}" % (local_tm, s2, s2f, ts), 874 "{%s, %s, %s, %s, %s}" % (local_tm, s2, tf, s2f, ts), 875 "{%s, %s, %s, %s, %s}" % (local_tm, s2, s2f, ts, rex), 876 "{%s, %s, %s, %s, %s, %s}" % (local_tm, s2, tf, s2f, ts, rex), 877 "{%s, %s}" % (local_tm, rex) 878 ] 879 warning = "The model-free models used in dauvergne_protocol auto-analysis should almost never be changed! The consequences will be unpredictable. Please proceed only if you are sure of what you are doing. Would you like to modify the model-free model list?" 880 red_flag = True 881 size = wx.Size(680, 350) 882 tooltip = "The list model-free models with the %s parameter to optimise as the first step of the protocol (see the about window for details). This really should not be changed." % local_tm 883 tooltip_button = "Open the model list selector window."
884 885 886
887 -class Mf_list(Model_list):
888 """The model-free model list GUI element.""" 889 890 # Some class variables. 891 desc = "Model-free models:" 892 model_desc = [ 893 "No statistically significant internal motions.", 894 "The original model with a statistically insignificant %s." % te, 895 "The original Lipari and Szabo model.", 896 "The original model with chemical exchange relaxation but a statistically insignificant %s." % te, 897 "The original model with chemical exchange relaxation.", 898 "The extended model with a statistically insignificant %s." % tf, 899 "The Clore et al., 1991 extended model-free model.", 900 "The extended model with chemical exchange relaxation but a statistically insignificant %s." % tf, 901 "The extended model with chemical exchange relaxation.", 902 "No statistically significant internal motions but chemical exchange relaxation present." 903 ] 904 models = [ 905 "m0", 906 "m1", 907 "m2", 908 "m3", 909 "m4", 910 "m5", 911 "m6", 912 "m7", 913 "m8", 914 "m9" 915 ] 916 params = [ 917 "{}", 918 "{%s}" % s2, 919 "{%s, %s}" % (s2, te), 920 "{%s, %s}" % (s2, rex), 921 "{%s, %s, %s}" % (s2, te, rex), 922 "{%s, %s, %s}" % (s2, s2f, ts), 923 "{%s, %s, %s, %s}" % (s2, tf, s2f, ts), 924 "{%s, %s, %s, %s}" % (s2, s2f, ts, rex), 925 "{%s, %s, %s, %s, %s}" % (s2, tf, s2f, ts, rex), 926 "{%s}" % rex 927 ] 928 warning = "The model-free models used in dauvergne_protocol auto-analysis should almost never be changed! The consequences will be unpredictable. Please proceed only if you are sure of what you are doing. Would you like to modify the model-free model list?" 929 red_flag = True 930 size = wx.Size(850, 350) 931 tooltip = "The list model-free models to optimise as the iterative part of the protocol (see the about window for details). This really should not be changed." 932 tooltip_button = "Open the model list selector window."
933 934 935
936 -class Protocol_mode_sel_window(wx.Dialog):
937 """The protocol mode selector window object.""" 938
939 - def __init__(self):
940 """Set up the window.""" 941 942 # Set up the dialog. 943 wx.Dialog.__init__(self, None, id=-1, title="Protocol mode selection") 944 945 # Initialise some values 946 size_x = 600 947 size_y = 600 948 border = 10 949 self.select = 'Fully automated' 950 951 # Set the frame properties. 952 self.SetSize((size_x, size_y)) 953 self.Centre() 954 self.SetFont(font.normal) 955 956 # The main box sizer. 957 main_sizer = wx.BoxSizer(wx.VERTICAL) 958 959 # Pack the sizer into the frame. 960 self.SetSizer(main_sizer) 961 962 # Build the central sizer, with borders. 963 sizer = add_border(main_sizer, border=border, packing=wx.HORIZONTAL) 964 965 # Build the automatic part. 966 self.build_auto(sizer) 967 968 # Line separator. 969 sizer.Add(wx.StaticLine(self, -1, style=wx.LI_VERTICAL), 0, wx.EXPAND|wx.ALL, border) 970 971 # Build the manual part. 972 self.build_manual(sizer)
973 974
975 - def build_auto(self, sizer):
976 """Build the fully automated part of the window. 977 978 @param sizer: The sizer to pack the elements into. 979 @type sizer: wx.BoxSizer instance 980 """ 981 982 # Create a vertical sizer for the elements. 983 sub_sizer = wx.BoxSizer(wx.VERTICAL) 984 985 # The title. 986 title = wx.StaticText(self, -1, "Fully automated") 987 title.SetFont(font.subtitle) 988 sub_sizer.Add(title, 0, wx.ALIGN_CENTRE_HORIZONTAL, 0) 989 990 # Spacing. 991 sub_sizer.AddStretchSpacer() 992 993 # The button. 994 button = wx.BitmapButton(self, -1, wx.Bitmap(fetch_icon('oxygen.actions.go-bottom', "48x48"), wx.BITMAP_TYPE_ANY)) 995 button.SetMinSize((80, 80)) 996 button.SetToolTipString("Perform a fully automated analysis, looping over global models I to V and terminating with the final run. Please click on the 'About' button for more information.") 997 sub_sizer.Add(button, 3, wx.EXPAND, 0) 998 self.Bind(wx.EVT_BUTTON, self.select_full_analysis, button) 999 1000 # Spacing. 1001 sub_sizer.AddStretchSpacer() 1002 1003 # Add the sub-sizer. 1004 sizer.Add(sub_sizer, 1, wx.ALL|wx.EXPAND, 0)
1005 1006
1007 - def build_manual(self, sizer):
1008 """Build the manual part of the window. 1009 1010 @param sizer: The sizer to pack the elements into. 1011 @type sizer: wx.BoxSizer instance 1012 """ 1013 1014 # Create a vertical sizer for the elements. 1015 sub_sizer = wx.BoxSizer(wx.VERTICAL) 1016 1017 # The title. 1018 title = wx.StaticText(self, -1, "Manual modes") 1019 title.SetFont(font.subtitle) 1020 sub_sizer.Add(title, 0, wx.ALIGN_CENTRE_HORIZONTAL, 0) 1021 1022 # Spacing. 1023 sub_sizer.AddSpacer(10) 1024 1025 # The local_tm button. 1026 button = wx.Button(self, -1, "Local %s" % tm) 1027 button.SetToolTipString("Optimise global model I, the %s models. Please click on the 'About' button for more information." % local_tm) 1028 button.SetFont(font.normal) 1029 sub_sizer.Add(button, 1, wx.EXPAND, 0) 1030 self.Bind(wx.EVT_BUTTON, self.select_local_tm, button) 1031 1032 # The sphere button. 1033 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, str_to_gui(" Sphere")) 1034 button.SetBitmapLabel(wx.Bitmap(IMAGE_PATH+'sphere.png', wx.BITMAP_TYPE_ANY)) 1035 button.SetFont(font.normal) 1036 button.SetToolTipString("Optimise global model II, the spherical diffusion model. Please click on the 'About' button for more information.") 1037 sub_sizer.Add(button, 1, wx.EXPAND, 0) 1038 self.Bind(wx.EVT_BUTTON, self.select_sphere, button) 1039 1040 # The prolate spheroid button. 1041 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, str_to_gui(" Prolate spheroid")) 1042 button.SetBitmapLabel(wx.Bitmap(IMAGE_PATH+'prolate.png', wx.BITMAP_TYPE_ANY)) 1043 button.SetFont(font.normal) 1044 button.SetToolTipString("Optimise global model III, the prolate spheroid diffusion model. Please click on the 'About' button for more information.") 1045 sub_sizer.Add(button, 1, wx.EXPAND, 0) 1046 self.Bind(wx.EVT_BUTTON, self.select_prolate, button) 1047 1048 # The oblate spheroid button. 1049 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, str_to_gui(" Oblate spheroid")) 1050 button.SetBitmapLabel(wx.Bitmap(IMAGE_PATH+'oblate.png', wx.BITMAP_TYPE_ANY)) 1051 button.SetFont(font.normal) 1052 button.SetToolTipString("Optimise global model IV, the oblate spheroid diffusion model. Please click on the 'About' button for more information.") 1053 sub_sizer.Add(button, 1, wx.EXPAND, 0) 1054 self.Bind(wx.EVT_BUTTON, self.select_oblate, button) 1055 1056 # The ellipsoid button. 1057 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, str_to_gui(" Ellipsoid")) 1058 button.SetBitmapLabel(wx.Bitmap(IMAGE_PATH+'ellipsoid.png', wx.BITMAP_TYPE_ANY)) 1059 button.SetFont(font.normal) 1060 button.SetToolTipString("Optimise global model V, the ellipsoid diffusion model. Please click on the 'About' button for more information.") 1061 sub_sizer.Add(button, 1, wx.EXPAND, 0) 1062 self.Bind(wx.EVT_BUTTON, self.select_ellipsoid, button) 1063 1064 # The final button. 1065 button = wx.Button(self, -1, str_to_gui("Final")) 1066 button.SetToolTipString("The final run of the protocol. Please click on the 'About' button for more information.") 1067 button.SetFont(font.normal) 1068 sub_sizer.Add(button, 1, wx.EXPAND, 0) 1069 self.Bind(wx.EVT_BUTTON, self.select_final, button) 1070 1071 # Add the sub-sizer. 1072 sizer.Add(sub_sizer, 1, wx.ALL|wx.EXPAND, 0)
1073 1074
1075 - def select_ellipsoid(self, event=None):
1076 """The ellipsoid global model has been selected. 1077 1078 @keyword event: The wx event. 1079 @type event: wx event 1080 """ 1081 1082 # Set the value. 1083 self.select = 'ellipsoid' 1084 1085 # Close the dialog. 1086 self.Close()
1087 1088
1089 - def select_final(self, event=None):
1090 """The final stage of the protocol has been selected. 1091 1092 @keyword event: The wx event. 1093 @type event: wx event 1094 """ 1095 1096 # Set the value. 1097 self.select = 'final' 1098 1099 # Close the dialog. 1100 self.Close()
1101 1102
1103 - def select_full_analysis(self, event=None):
1104 """The full analysis has been selected. 1105 1106 @keyword event: The wx event. 1107 @type event: wx event 1108 """ 1109 1110 # Set the value. 1111 self.select = 'Fully automated' 1112 1113 # Close the dialog. 1114 self.Close()
1115 1116
1117 - def select_local_tm(self, event=None):
1118 """The local_tm global model has been selected. 1119 1120 @keyword event: The wx event. 1121 @type event: wx event 1122 """ 1123 1124 # Set the value. 1125 self.select = 'local_tm' 1126 1127 # Close the dialog. 1128 self.Close()
1129 1130
1131 - def select_prolate(self, event=None):
1132 """The prolate global model has been selected. 1133 1134 @keyword event: The wx event. 1135 @type event: wx event 1136 """ 1137 1138 # Set the value. 1139 self.select = 'prolate' 1140 1141 # Close the dialog. 1142 self.Close()
1143 1144
1145 - def select_oblate(self, event=None):
1146 """The oblate global model has been selected. 1147 1148 @keyword event: The wx event. 1149 @type event: wx event 1150 """ 1151 1152 # Set the value. 1153 self.select = 'oblate' 1154 1155 # Close the dialog. 1156 self.Close()
1157 1158
1159 - def select_sphere(self, event=None):
1160 """The sphere global model has been selected. 1161 1162 @keyword event: The wx event. 1163 @type event: wx event 1164 """ 1165 1166 # Set the value. 1167 self.select = 'sphere' 1168 1169 # Close the dialog. 1170 self.Close()
1171