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