Package test_suite :: Package gui_tests :: Module model_free
[hide private]
[frames] | no frames]

Source Code for Module test_suite.gui_tests.model_free

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2006-2015 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Python module imports. 
 23  from os import sep 
 24  import wx 
 25   
 26  # relax module imports. 
 27  from data_store import Relax_data_store; ds = Relax_data_store() 
 28  from pipe_control.interatomic import interatomic_loop 
 29  from pipe_control.mol_res_spin import spin_loop 
 30  from status import Status; status = Status() 
 31  from test_suite.gui_tests.base_classes import GuiTestCase 
 32   
 33  # relax GUI imports. 
 34  from gui.analyses import auto_model_free 
 35  from gui.interpreter import Interpreter; interpreter = Interpreter() 
 36  from gui.string_conv import str_to_gui 
 37  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 38   
 39   
40 -class Mf(GuiTestCase):
41 """Class for testing various aspects specific to the model-free auto-analysis.""" 42
44 """Catch U{bug #20479<https://web.archive.org/web/https://gna.org/bugs/?20479>}, the failure to load a relax state in the GUI. 45 46 This was reported by U{Stanislava Panova<https://web.archive.org/web/https://gna.org/users/stacy>}. 47 """ 48 49 # Simulate the new analysis wizard. 50 analysis = self.new_analysis_wizard(analysis_type='mf', analysis_name='Model-free test') 51 52 # Change the results directory. 53 analysis.field_results_dir.SetValue(str_to_gui(ds.tmpdir)) 54 55 # The data path. 56 data_path = status.install_path + sep + 'test_suite' + sep + 'shared_data' + sep + 'model_free' + sep + 'bug_20479_gui_final_pipe' + sep 57 58 # Launch the spin viewer window. 59 self.app.gui.show_tree() 60 61 # Spin loading wizard: Initialisation. 62 self.app.gui.spin_viewer.load_spins_wizard() 63 64 # Spin loading wizard: The NOE data file. 65 page = self.app.gui.spin_viewer.wizard.get_page(0) 66 page.selection = 'sequence' 67 self.app.gui.spin_viewer.wizard._go_next() 68 page = self.app.gui.spin_viewer.wizard.get_page(self.app.gui.spin_viewer.wizard._current_page) 69 page.uf_args['file'].SetValue(str_to_gui(data_path + 'NoeRelN')) 70 self.app.gui.spin_viewer.wizard._go_next() 71 interpreter.flush() # Required because of the asynchronous uf call. 72 73 # Spin loading wizard: The spin loading. 74 self.app.gui.spin_viewer.wizard._go_next() 75 interpreter.flush() # Required because of the asynchronous uf call. 76 77 # Close the spin viewer window. 78 self.app.gui.spin_viewer.handler_close() 79 80 # Flush the interpreter in preparation for the synchronous user functions of the peak list wizard. 81 interpreter.flush() 82 83 # Set the element type. 84 self._execute_uf(uf_name='spin.element', element='N') 85 86 # Load the relaxation data. 87 data = [ 88 ['NoeRelN', 'noe_800', 'NOE', 800000031.0], 89 ['R1850', 'r1_800', 'R1', 800000031.0], 90 ['R2863', 'r2_800', 'R2', 800000031.0], 91 ['R2604', 'r2_600', 'R2', 599999000.0] 92 ] 93 for i in range(len(data)): 94 self._execute_uf(uf_name='relax_data.read', file=data_path+data[i][0], ri_id=data[i][1], ri_type=data[i][2], frq=data[i][3], mol_name_col=1, res_num_col=2, res_name_col=3, spin_num_col=4, spin_name_col=5, data_col=6, error_col=7) 95 96 # Attach the protons. 97 self._execute_uf(uf_name='sequence.attach_protons') 98 99 # Dipole-dipole interaction wizard. 100 analysis.setup_dipole_pair() # Initialisation. 101 analysis.dipole_wizard._skip() # Skip the structure.read_pdb user function. 102 analysis.dipole_wizard._skip() # Skip the structure.get_pos user function. 103 analysis.dipole_wizard._go_next() # The interatom.define user function. 104 interpreter.flush() # Required because of the asynchronous uf call. 105 analysis.dipole_wizard._go_next() # The interatom.set_dist user function. 106 interpreter.flush() # Required because of the asynchronous uf call. 107 analysis.dipole_wizard._skip() # Skip the interatom.unit_vectors user function. 108 109 # Set up the CSA interaction. 110 analysis.value_set_csa() 111 uf_store['value.set'].wizard._go_next() 112 interpreter.flush() # Required because of the asynchronous uf call. 113 114 # Set up the nuclear isotopes. 115 analysis.spin_isotope_heteronuc() 116 uf_store['spin.isotope'].wizard._go_next() 117 interpreter.flush() # Required because of the asynchronous uf call. 118 analysis.spin_isotope_proton() 119 uf_store['spin.isotope'].wizard._go_next() 120 interpreter.flush() # Required because of the asynchronous uf call. 121 122 # Select only the tm0 and tm1 local tm models. 123 analysis.local_tm_model_field.select = [True, True, False, False, False, False, False, False, False, False] 124 analysis.local_tm_model_field.modify() 125 126 # Select only the m1 and m2 model-free models. 127 analysis.mf_model_field.select = [False, True, True, False, False, False, False, False, False, False] 128 analysis.mf_model_field.modify() 129 130 # Change the grid increments. 131 analysis.grid_inc.SetValue(3) 132 analysis.data.diff_tensor_grid_inc = {'sphere': 5, 'prolate': 5, 'oblate': 5, 'ellipsoid': 3} 133 134 # Set the number of Monte Carlo simulations. 135 analysis.mc_sim_num.SetValue(3) 136 137 # Set the maximum number of iterations (changing the allowed values). 138 analysis.max_iter.control.SetRange(0, 100) 139 analysis.max_iter.SetValue(1) 140 141 # Modify some of the class variables to speed up optimisation. 142 auto_model_free.dauvergne_protocol.dAuvergne_protocol.opt_func_tol = 1e-5 143 auto_model_free.dauvergne_protocol.dAuvergne_protocol.opt_max_iterations = 1000 144 145 # Execute the 'local_tm', 'sphere' and 'final' protocol stages sequentially. 146 for protocol in ['local_tm', 'sphere', 'final']: 147 # Print out. 148 text = "Sequential global model optimisation: %s" % protocol 149 char = "%" 150 print("\n\n\n\n%s\n%s %s %s\n%s\n\n\n" % (char*(len(text)+4), char, text, char, char*(len(text)+4))) 151 152 # Set the protocol mode. 153 if protocol == 'local_tm': 154 analysis.mode_win.select_local_tm() 155 elif protocol == 'sphere': 156 analysis.mode_win.select_sphere() 157 else: 158 analysis.mode_win.select_final() 159 analysis.mode_dialog() 160 161 # Execute relax. 162 state = analysis.execute(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, analysis.button_exec_relax.GetId())) 163 164 # Wait for execution to complete. 165 if hasattr(analysis, 'thread'): 166 analysis.thread.join() 167 168 # Flush all wx events. 169 wx.Yield() 170 171 # Exceptions in the thread. 172 self.check_exceptions()
173 174
176 """Catch U{bug #21615<https://web.archive.org/web/https://gna.org/bugs/?21615>}, the failure of showing the missing data dialog when executing the analysis with an incomplete setup. 177 178 This was reported by Ivan Leung. 179 """ 180 181 # Simulate the new analysis wizard. 182 analysis = self.new_analysis_wizard(analysis_type='mf', analysis_name='Model-free incomplete setup failure') 183 184 # Change the results directory. 185 analysis.field_results_dir.SetValue(str_to_gui(ds.tmpdir)) 186 187 # The data path. 188 data_path = status.install_path + sep + 'test_suite' + sep + 'shared_data' + sep + 'model_free' + sep + 'bug_21615_incomplete_setup_failure' + sep 189 190 # Launch the spin viewer window. 191 self.app.gui.show_tree() 192 193 # Spin loading wizard: Initialisation. 194 self.app.gui.spin_viewer.load_spins_wizard() 195 196 # Spin loading wizard: The PDB file. 197 page = self.app.gui.spin_viewer.wizard.get_page(0) 198 page.selection = 'new pdb' 199 self.app.gui.spin_viewer.wizard._go_next() 200 page = self.app.gui.spin_viewer.wizard.get_page(self.app.gui.spin_viewer.wizard._current_page) 201 page.uf_args['file'].SetValue(str_to_gui(data_path + 'Truncated_ForBugReport.pdb')) 202 self.app.gui.spin_viewer.wizard._go_next() 203 interpreter.flush() # Required because of the asynchronous uf call. 204 205 # Spin loading wizard: The spin loading. 206 page = self.app.gui.spin_viewer.wizard.get_page(self.app.gui.spin_viewer.wizard._current_page) 207 page.uf_args['spin_id'].SetValue(str_to_gui('@N')) 208 self.app.gui.spin_viewer.wizard._apply() 209 interpreter.flush() # Required because of the asynchronous uf call. 210 page.uf_args['spin_id'].SetValue(str_to_gui('@H')) 211 self.app.gui.spin_viewer.wizard._go_next() 212 interpreter.flush() # Required because of the asynchronous uf call. 213 214 # Close the spin viewer window. 215 self.app.gui.spin_viewer.handler_close() 216 217 # Flush the interpreter in preparation for the synchronous user functions of the peak list wizard. 218 interpreter.flush() 219 220 # Set the element type. 221 self._execute_uf(uf_name='spin.element', element='N') 222 223 # Load the relaxation data. 224 data = [ 225 ['NOE_ForBugReport.txt', 'noe_800', 'NOE', 800000001.0], 226 ['T1_ForBugReport.txt', 'r1_800', 'R1', 800000001.0], 227 ['T2_ForBugReport.txt', 'r2_800', 'R2', 800000001.0] 228 ] 229 for i in range(len(data)): 230 self._execute_uf(uf_name='relax_data.read', file=data_path+data[i][0], ri_id=data[i][1], ri_type=data[i][2], frq=data[i][3], mol_name_col=1, res_num_col=2, res_name_col=3, spin_num_col=4, spin_name_col=5, data_col=6, error_col=7) 231 232 # Execute relax. 233 state = analysis.execute(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, analysis.button_exec_relax.GetId())) 234 235 # Wait for execution to complete. 236 if hasattr(analysis, 'thread'): 237 analysis.thread.join() 238 239 # Flush all wx events. 240 wx.Yield() 241 242 # Exceptions in the thread. 243 self.check_exceptions()
244 245
246 - def test_mf_auto_analysis(self):
247 """Test the model-free auto-analysis. 248 249 This now catches U{bug #20603<https://web.archive.org/web/https://gna.org/bugs/?20603>}. 250 """ 251 252 # Simulate the new analysis wizard. 253 analysis = self.new_analysis_wizard(analysis_type='mf', analysis_name='Model-free test') 254 255 # Change the results directory. 256 analysis.field_results_dir.SetValue(str_to_gui(ds.tmpdir)) 257 258 # The data path. 259 data_path = status.install_path + sep + 'test_suite' + sep + 'shared_data' + sep + 'model_free' + sep + 'sphere' + sep 260 261 # Open and close the about window (mimicking user behaviour). 262 analysis._about() 263 analysis.about_dialog.Close() 264 265 # Launch the spin viewer window. 266 self.app.gui.show_tree() 267 268 # Spin loading wizard: Initialisation. 269 self.app.gui.spin_viewer.load_spins_wizard() 270 271 # Spin loading wizard: The PDB file. 272 page = self.app.gui.spin_viewer.wizard.get_page(0) 273 page.selection = 'new pdb' 274 self.app.gui.spin_viewer.wizard._go_next() 275 page = self.app.gui.spin_viewer.wizard.get_page(self.app.gui.spin_viewer.wizard._current_page) 276 page.uf_args['file'].SetValue(str_to_gui(status.install_path + sep + 'test_suite' + sep + 'shared_data' + sep + 'model_free' + sep + 'sphere' + sep + 'sphere.pdb')) 277 self.app.gui.spin_viewer.wizard._go_next() 278 interpreter.flush() # Required because of the asynchronous uf call. 279 280 # Spin loading wizard: The spin loading. 281 self.app.gui.spin_viewer.wizard._go_next() 282 interpreter.flush() # Required because of the asynchronous uf call. 283 284 # Close the spin viewer window. 285 self.app.gui.spin_viewer.handler_close() 286 287 # Flush the interpreter in preparation for the synchronous user functions of the peak list wizard. 288 interpreter.flush() 289 290 # Load the relaxation data. 291 data = [ 292 ['noe.500.out', 'noe_500', 'NOE', 500e6], 293 ['r1.500.out', 'r1_500', 'R1', 500e6], 294 ['r2.500.out', 'r2_500', 'R2', 500e6], 295 ['noe.900.out', 'noe_900', 'NOE', 900e6], 296 ['r1.900.out', 'r1_900', 'R1', 900e6], 297 ['r2.900.out', 'r2_900', 'R2', 900e6] 298 ] 299 for i in range(len(data)): 300 self._execute_uf(uf_name='relax_data.read', file=data_path+data[i][0], ri_id=data[i][1], ri_type=data[i][2], frq=data[i][3], mol_name_col=1, res_num_col=2, res_name_col=3, spin_num_col=4, spin_name_col=5, data_col=6, error_col=7) 301 302 # Simulate right clicking on the NOE to test the pop up menu (bug #20603, https://web.archive.org/web/https://gna.org/bugs/?20603). 303 analysis.relax_data.on_right_click(Fake_right_click()) 304 305 # Dipole-dipole interaction wizard: Initialisation. 306 analysis.setup_dipole_pair() 307 308 # Dipole-dipole interaction wizard: The interatom.define, interatom.set_dist, and interatom.unit_vectors user functions. 309 analysis.dipole_wizard._apply() 310 interpreter.flush() # Required because of the asynchronous uf call. 311 page = analysis.dipole_wizard.get_page(0) 312 page.uf_args['spin_id1'].SetValue(str_to_gui("@NE1")) 313 page.uf_args['spin_id2'].SetValue(str_to_gui("@HE1")) 314 analysis.dipole_wizard._go_next() 315 interpreter.flush() # Required because of the asynchronous uf call. 316 analysis.dipole_wizard._go_next() 317 interpreter.flush() # Required because of the asynchronous uf call. 318 analysis.dipole_wizard._go_next() 319 interpreter.flush() # Required because of the asynchronous uf call. 320 321 # Set up the CSA interaction. 322 analysis.value_set_csa() 323 uf_store['value.set'].wizard._go_next() 324 interpreter.flush() # Required because of the asynchronous uf call. 325 326 # Set up the nuclear isotopes. 327 analysis.spin_isotope_heteronuc() 328 uf_store['spin.isotope'].wizard._go_next() 329 interpreter.flush() # Required because of the asynchronous uf call. 330 analysis.spin_isotope_proton() 331 uf_store['spin.isotope'].wizard._go_next() 332 interpreter.flush() # Required because of the asynchronous uf call. 333 334 # Select only the tm0 and tm1 local tm models. 335 analysis.local_tm_model_field.select = [True, True, False, False, False, False, False, False, False, False] 336 analysis.local_tm_model_field.modify() 337 338 # Select only the m1 and m2 model-free models. 339 analysis.mf_model_field.select = [False, True, True, False, False, False, False, False, False, False] 340 analysis.mf_model_field.modify() 341 342 # Change the grid increments. 343 analysis.grid_inc.SetValue(3) 344 analysis.data.diff_tensor_grid_inc = {'sphere': 5, 'prolate': 5, 'oblate': 5, 'ellipsoid': 3} 345 346 # Set the number of Monte Carlo simulations. 347 analysis.mc_sim_num.SetValue(3) 348 349 # Set the maximum number of iterations (changing the allowed values). 350 analysis.max_iter.control.SetRange(0, 100) 351 analysis.max_iter.SetValue(1) 352 353 # Set the protocol mode to automatic. 354 analysis.mode_win.select_full_analysis() 355 analysis.mode_dialog() 356 357 # Check that the data has been correctly updated prior to execution. 358 analysis.sync_ds(upload=True) 359 self.assertEqual(analysis.data.save_dir, ds.tmpdir) 360 self.assertEqual(analysis.data.local_tm_models, ['tm0', 'tm1']) 361 self.assertEqual(analysis.data.mf_models, ['m1', 'm2']) 362 self.assertEqual(analysis.data.grid_inc, 3) 363 self.assertEqual(analysis.data.mc_sim_num, 3) 364 self.assertEqual(analysis.data.max_iter, 1) 365 self.assertEqual(analysis.data.diff_tensor_grid_inc['sphere'], 5) 366 self.assertEqual(analysis.data.diff_tensor_grid_inc['prolate'], 5) 367 self.assertEqual(analysis.data.diff_tensor_grid_inc['oblate'], 5) 368 self.assertEqual(analysis.data.diff_tensor_grid_inc['ellipsoid'], 3) 369 370 # Modify some of the class variables to speed up optimisation. 371 auto_model_free.dauvergne_protocol.dAuvergne_protocol.opt_func_tol = 1e-5 372 auto_model_free.dauvergne_protocol.dAuvergne_protocol.opt_max_iterations = 1000 373 374 # Execute relax. 375 state = analysis.execute(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, analysis.button_exec_relax.GetId())) 376 377 # Wait for execution to complete. 378 if hasattr(analysis, 'thread'): 379 analysis.thread.join() 380 381 # Flush all wx events. 382 wx.Yield() 383 384 # Exceptions in the thread. 385 self.check_exceptions() 386 387 # Check the relax controller. 388 # FIXME: skipping the checks for certain wxPython bugs. 389 if status.relax_mode != 'gui' and wx.version() != '2.9.4.1 gtk2 (classic)': 390 self.assertEqual(self.app.gui.controller.mc_gauge_mf.GetValue(), 100) 391 self.assertEqual(self.app.gui.controller.progress_gauge_mf.GetValue(), 100) 392 self.assertEqual(self.app.gui.controller.main_gauge.GetValue(), 100) 393 394 # Check the diffusion tensor. 395 self.assertEqual(cdp.diff_tensor.type, 'sphere') 396 self.assertAlmostEqual(cdp.diff_tensor.tm, 1e-8) 397 self.assertEqual(cdp.diff_tensor.fixed, True) 398 399 # The global minimisation info. 400 self.assertAlmostEqual(cdp.chi2, 4e-19) 401 402 # The spin ID info. 403 mol_names = ["sphere_mol1"] * 20 404 res_names = ["GLY"] * 20 405 res_nums = [] 406 for i in range(1, 10): 407 res_nums.append(i) 408 res_nums.append(i) 409 res_nums.append(i) 410 res_nums.append(i) 411 spin_names = ["N", "H"] * 9 + ["NE1", "HE1"] 412 spin_nums = list(range(1, 21)) 413 isotopes = ["15N", "1H"] * 10 414 csa = [-172e-6, None] * 10 415 select = [True, False] * 10 416 fixed = [False, False] * 10 417 s2 = [0.8, None] * 10 418 te = [20e-12, None] * 10 419 420 # Check the spin data. 421 i = 0 422 for spin, mol_name, res_num, res_name in spin_loop(full_info=True): 423 # The ID info. 424 self.assertEqual(mol_name, mol_names[i]) 425 self.assertEqual(res_name, res_names[i]) 426 self.assertEqual(res_num, res_nums[i]) 427 self.assertEqual(spin.name, spin_names[i]) 428 self.assertEqual(spin.num, spin_nums[i]) 429 430 # The data. 431 self.assertEqual(spin.select, select[i]) 432 self.assertEqual(spin.fixed, fixed[i]) 433 self.assertEqual(spin.isotope, isotopes[i]) 434 if csa[i] == None: 435 self.assertEqual(spin.csa, None) 436 else: 437 self.assertAlmostEqual(spin.csa, csa[i]) 438 439 # The model-free data. 440 self.assertEqual(spin.model, 'm2') 441 self.assertEqual(spin.equation, 'mf_orig') 442 self.assertEqual(len(spin.params), 2) 443 self.assertEqual(spin.params[0], 's2') 444 self.assertEqual(spin.params[1], 'te') 445 if s2[i] == None: 446 self.assertEqual(spin.s2, None) 447 else: 448 self.assertAlmostEqual(spin.s2, 0.8) 449 self.assertEqual(spin.s2f, None) 450 self.assertEqual(spin.s2s, None) 451 self.assertEqual(spin.local_tm, None) 452 if te[i] == None: 453 self.assertEqual(spin.te, None) 454 else: 455 self.assertAlmostEqual(spin.te, 20e-12) 456 self.assertEqual(spin.tf, None) 457 self.assertEqual(spin.ts, None) 458 self.assertEqual(spin.rex, None) 459 460 # The spin minimisation info. 461 self.assertEqual(spin.chi2, None) 462 self.assertEqual(spin.iter, None) 463 self.assertEqual(spin.f_count, None) 464 self.assertEqual(spin.g_count, None) 465 self.assertEqual(spin.h_count, None) 466 self.assertEqual(spin.warning, None) 467 468 # Increment the index. 469 i += 1 470 471 # Check the interatomic data. 472 i = 0 473 for interatom in interatomic_loop(): 474 self.assertAlmostEqual(interatom.r, 1.02 * 1e-10)
475 476
477 - def test_opendx_s2_te_rex(self):
478 """Mapping the {S2, te, Rex} chi2 space through the OpenDX user function dx.map(). 479 480 This is to catch U{bug #22035<https://web.archive.org/web/https://gna.org/bugs/?22035>}, the dx.map user function being broken in the GUI. 481 """ 482 483 # Execute the script. 484 self.script_exec(status.install_path + sep+'test_suite'+sep+'system_tests'+sep+'scripts'+sep+'model_free'+sep+'opendx_s2_te_rex.py')
485 486 487
488 -class Fake_right_click:
489 """Simulate a grid_cell_right_click event .""" 490
491 - def GetPosition(self):
492 """Simulate the GetPosition() method.""" 493 494 # Return some random position. 495 return wx.Point(10, 10)
496 497
498 - def GetRow(self):
499 """Simulate the GetRow() method.""" 500 501 # Return the first row. 502 return 0
503