1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the automatic relaxation dispersion analysis."""
24
25
26 import wx
27
28
29 from auto_analyses.relax_disp import Relax_disp
30 from data_store import Relax_data_store; ds = Relax_data_store()
31 from graphics import ANALYSIS_IMAGE_PATH, fetch_icon
32 from gui.analyses.base import Base_analysis
33 from gui.analyses.elements.bool_element import Boolean_ctrl
34 from gui.analyses.elements.float_element import Float_ctrl
35 from gui.analyses.elements.spin_element import Spin_ctrl
36 from gui.analyses.elements.text_element import Text_ctrl
37 from gui.analyses.elements.model_list import Model_list
38 from gui.analyses.execute import Execute
39 from gui.base_classes import Container
40 from gui.components.spectrum import Spectra_list
41 from gui.filedialog import RelaxDirDialog
42 from gui.fonts import font
43 from gui.message import error_message, Missing_data
44 from gui.string_conv import float_to_gui, gui_to_float, gui_to_int, gui_to_str, str_to_gui
45 from gui.uf_objects import Uf_storage; uf_store = Uf_storage()
46 from gui.wizards.peak_intensity import Peak_intensity_wizard
47 from lib.text.gui import dw, dw_AB, dw_BC, dwH, dwH_AB, dwH_BC, i0, kex, kAB, kBC, kAC, padw2, phi_ex, phi_exB, phi_exC, r1, r1rho, r1rho_prime, r2, r2a, r2b, r2eff
48 from pipe_control.mol_res_spin import exists_mol_res_spin_data, spin_loop
49 from pipe_control.pipes import has_bundle, has_pipe
50 from specific_analyses.relax_disp.data import has_cpmg_exp_type, has_r1rho_exp_type
51 from specific_analyses.relax_disp.variables import MODEL_B14, MODEL_B14_FULL, MODEL_CR72, MODEL_CR72_FULL, MODEL_DPL94, MODEL_IT99, MODEL_LIST_CPMG, MODEL_LIST_R1RHO, MODEL_LM63, MODEL_LM63_3SITE, MODEL_M61, MODEL_M61B, MODEL_MMQ_CR72, MODEL_MP05, MODEL_NOREX, MODEL_NS_CPMG_2SITE_3D, MODEL_NS_CPMG_2SITE_3D_FULL, MODEL_NS_CPMG_2SITE_EXPANDED, MODEL_NS_CPMG_2SITE_STAR, MODEL_NS_CPMG_2SITE_STAR_FULL, MODEL_NS_MMQ_2SITE, MODEL_NS_MMQ_3SITE, MODEL_NS_MMQ_3SITE_LINEAR, MODEL_NS_R1RHO_2SITE, MODEL_NS_R1RHO_3SITE, MODEL_NS_R1RHO_3SITE_LINEAR, MODEL_R2EFF, MODEL_TAP03, MODEL_TP02, MODEL_TSMFK01
52 from status import Status; status = Status()
53
54
56 """The relaxation dispersion auto-analysis GUI element."""
57
58
59 analysis_type = None
60 bitmap = ANALYSIS_IMAGE_PATH+"relax_disp_200x200.png"
61 label = 'Relax-disp'
62
63 - 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):
64 """Build the automatic R1 and R2 analysis GUI frame elements.
65
66 @param parent: The parent wx element.
67 @type parent: wx object
68 @keyword id: The unique ID number.
69 @type id: int
70 @keyword pos: The position.
71 @type pos: wx.Size object
72 @keyword size: The size.
73 @type size: wx.Size object
74 @keyword style: The style.
75 @type style: int
76 @keyword name: The name for the panel.
77 @type name: unicode
78 @keyword gui: The main GUI class.
79 @type gui: gui.relax_gui.Main instance
80 @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook).
81 @type analysis_name: str
82 @keyword pipe_name: The name of the data pipe associated with this analysis.
83 @type pipe_name: str
84 @keyword pipe_bundle: The name of the data pipe bundle associated with this analysis.
85 @type pipe_bundle: str
86 @keyword uf_exec: The list of user function on_execute methods returned from the new analysis wizard.
87 @type uf_exec: list of methods
88 @keyword data_index: The index of the analysis in the relax data store (set to None if no data currently exists).
89 @type data_index: None or int
90 """
91
92
93 self.gui = gui
94
95
96 self.init_flag = True
97
98
99 if data_index == None:
100
101 if not has_pipe(pipe_name):
102 self.gui.interpreter.apply('pipe.create', pipe_name=pipe_name, pipe_type='relax_disp', bundle=pipe_bundle)
103
104
105 if not has_bundle(pipe_bundle):
106 self.gui.interpreter.apply('pipe.bundle', bundle=pipe_bundle, pipe=pipe_name)
107
108
109 data_index = ds.relax_gui.analyses.add(self.label)
110
111
112 ds.relax_gui.analyses[data_index].analysis_name = analysis_name
113 ds.relax_gui.analyses[data_index].pipe_name = pipe_name
114 ds.relax_gui.analyses[data_index].pipe_bundle = pipe_bundle
115
116
117 ds.relax_gui.analyses[data_index].numeric_only = False
118 ds.relax_gui.analyses[data_index].grid_inc = None
119 ds.relax_gui.analyses[data_index].mc_sim_num = None
120 ds.relax_gui.analyses[data_index].pre_run_dir = None
121 ds.relax_gui.analyses[data_index].mc_sim_all_models = False
122 ds.relax_gui.analyses[data_index].insignificance = 1.0
123 ds.relax_gui.analyses[data_index].save_dir = self.gui.launch_dir
124
125
126 ds.relax_gui.analyses[data_index].disp_models = [
127 MODEL_R2EFF,
128 MODEL_NOREX,
129 MODEL_CR72,
130 MODEL_NS_CPMG_2SITE_EXPANDED,
131 MODEL_MP05,
132 MODEL_NS_R1RHO_2SITE
133 ]
134
135
136 if ds.relax_gui.analyses[data_index].pipe_bundle == None:
137 raise RelaxError("The pipe bundle must be supplied.")
138
139
140 self.data = ds.relax_gui.analyses[data_index]
141 self.data_index = data_index
142
143
144 self.observer_register()
145
146
147 super(Auto_relax_disp, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name)
148
149
150 self.opt_func_tol = 1e-25
151 self.opt_max_iterations = int(1e7)
152
153
154 self.update_clusters()
155
156
158 """Activate or deactivate certain elements of the analysis in response to the execution lock."""
159
160
161 enable = False
162 if not status.exec_lock.locked():
163 enable = True
164
165
166 wx.CallAfter(self.field_results_dir.Enable, enable)
167 wx.CallAfter(self.field_pre_run_dir.Enable, enable)
168 wx.CallAfter(self.spin_systems.Enable, enable)
169 wx.CallAfter(self.field_cluster.Enable, enable)
170 wx.CallAfter(self.button_isotope.Enable, enable)
171 wx.CallAfter(self.button_r1.Enable, enable)
172 wx.CallAfter(self.button_chemical_shift.Enable, enable)
173 wx.CallAfter(self.button_interatom_define.Enable, enable)
174 wx.CallAfter(self.peak_intensity.Enable, enable)
175 wx.CallAfter(self.model_field.Enable, enable)
176 wx.CallAfter(self.button_exec_relax.Enable, enable)
177
178
237
238
240 """Assemble the data required for the Auto_noe class.
241
242 @return: A container with all the data required for the auto-analysis, the missing list, and a list of models that don't match the experiment types.
243 @rtype: class instance, list of str, list of str
244 """
245
246
247 data = Container()
248 missing = []
249 model_mismatch = []
250
251
252 data.pipe_name = self.data.pipe_name
253 data.pipe_bundle = self.data.pipe_bundle
254
255
256 data.save_dir = self.data.save_dir
257 data.pre_run_dir = gui_to_str(self.field_pre_run_dir.GetValue())
258
259
260 if not exists_mol_res_spin_data():
261 missing.append("Sequence data")
262
263
264 for spin, spin_id in spin_loop(return_id=True, skip_desel=True):
265
266 msg = "Spin '%s' - %s (try the %s user function)." % (spin_id, "%s", "%s")
267
268
269 if not hasattr(spin, 'isotope') or spin.isotope == None:
270 missing.append(msg % ("nuclear isotope data", "spin.isotope"))
271
272
273 if not hasattr(cdp, 'spectrum_ids') or len(cdp.spectrum_ids) < 2:
274 missing.append("Spectral data")
275
276
277 data.models = self.model_field.GetValue()
278
279
280 for model in data.models:
281
282 if model != MODEL_NOREX and model in MODEL_LIST_CPMG and not has_cpmg_exp_type():
283 model_mismatch.append([model, 'CPMG'])
284
285
286 if model != MODEL_NOREX and model in MODEL_LIST_R1RHO and not has_r1rho_exp_type():
287 model_mismatch.append([model, 'R1rho'])
288
289
290 data.numeric_only = self.numeric_only.GetValue()
291
292
293 data.inc = gui_to_int(self.grid_inc.GetValue())
294
295
296 data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue())
297 data.mc_sim_all_models = self.mc_sim_all_models.GetValue()
298
299
300 data.insignificance = self.insignificance.GetValue()
301 try:
302 data.insignificance = gui_to_float(data.insignificance)
303 except:
304 missing.append("The insignificance level must be a number.")
305
306
307 data.opt_func_tol = self.opt_func_tol
308 data.opt_max_iterations = self.opt_max_iterations
309
310
311 return data, missing, model_mismatch
312
313
315 """Construct the right hand box to pack into the main relax_disp box.
316
317 @return: The right hand box element containing all relaxation dispersion GUI elements (excluding the bitmap) to pack into the main box.
318 @rtype: wx.BoxSizer instance
319 """
320
321
322 box = wx.BoxSizer(wx.VERTICAL)
323
324
325 self.add_title(box, "Relaxation dispersion analysis")
326
327
328 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)
329
330
331 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)
332
333
334 tooltip = "The optional directory containing the dispersion auto-analysis results from a previous run. The optimised parameters from these previous results will be used as the starting point for optimisation rather than performing a grid search. This is essential for when large spin clusters are specified, as a grid search becomes prohibitively expensive with clusters of three or more spins. At some point a RelaxError will occur because the grid search is impossibly large. For the cluster specific parameters, i.e. the populations of the states and the exchange parameters, an average value will be used as the starting point. For all other parameters, the R20 values for each spin and magnetic field, as well as the parameters related to the chemical shift difference dw, the optimised values of the previous run will be directly copied."
335 self.field_pre_run_dir = Text_ctrl(box, self, text="Previous run directory:", icon=fetch_icon('oxygen.actions.document-open-folder', "16x16"), tooltip=tooltip, tooltip_button="Select the results directory of the previous run.", fn=self.pre_run_directory, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
336
337
338 self.add_spin_systems(box, self)
339
340
341 self.field_cluster = Text_ctrl(box, self, text="Spin cluster IDs:", button_text=" Cluster", icon=fetch_icon("relax.cluster", "16x16"), tooltip="The list of currently defined spin clusters. A spin cluster will share the same the dispersion parameters during the optimisation of the dispersion model. The special 'free spins' cluster ID refers to all non-clustered spins.", tooltip_button="Define clusters of spins using the relax_disp.cluster user function.", fn=self.relax_disp_cluster, button=True, editable=False, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
342
343
344 box.AddSpacer(20)
345 self.add_buttons(box=box)
346
347
348 box.AddSpacer(20)
349 self.peak_intensity = Spectra_list(gui=self.gui, parent=self, box=box, id=str(self.data_index), fn_add=self.peak_wizard_launch, relax_disp_flag=True)
350 box.AddSpacer(10)
351
352
353 self.model_field = Disp_model_list(self, box)
354 self.model_field.set_value(self.data.disp_models)
355
356
357 tooltip = "The class of models to use in the final model selection.\n\nThe default of False allows all dispersion models to be compared for statistical significance in the analysis (no exchange, the analytic models and the numeric models). The value of True will activate a pure numeric solution - the analytic models will be optimised, as they are very useful for replacing the grid search for the numeric models, but the final model selection will not include them."
358 self.numeric_only = Boolean_ctrl(box, self, text="Pure numeric solutions:", default=False, tooltip=tooltip, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
359
360
361 self.grid_inc = Spin_ctrl(box, self, text="Grid search increments:", default=21, min=1, max=100, tooltip="This is the number of increments per dimension of the grid search performed prior to numerical optimisation.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
362
363
364 self.mc_sim_num = Spin_ctrl(box, self, text="Monte Carlo simulation number:", default=500, min=1, max=100000, tooltip="This is the number of Monte Carlo simulations performed for error propagation and analysis. For best results, at least 500 is recommended.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
365 self.mc_sim_all_models = Boolean_ctrl(box, self, text="Per model error analysis:", default=False, tooltip="A flag which if True will cause Monte Carlo simulations to be performed for each individual model. Otherwise Monte Carlo simulations will be reserved for the final model.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
366
367
368 tooltip = "Experimental option, be careful. True will set the grid %s values from the minimum %s values. This will speed up the grid search with a factor GRID_INC^(Nr_spec_freq). For a CPMG experiment with two fields and standard GRID_INC=21, the speed-up is a factor 441." % (r2, r2eff)
369 self.set_grid_r20 = Boolean_ctrl(box, self, text="Set R20 to the minimum R2eff:", default=False, tooltip=tooltip, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
370
371
372 tooltip = "The %s/%s value in rad/s by which to judge insignificance. If the maximum difference between two points on all dispersion curves for a spin is less than this value, that spin will be deselected. This does not affect the '%s' model. Set this value to 0.0 to use all data." % (r2eff, r1rho, MODEL_NOREX)
373 self.insignificance = Float_ctrl(box, self, text="Insignificance level:", default=1.0, tooltip=tooltip, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
374
375
376 box.AddSpacer(30)
377 box.AddStretchSpacer()
378
379
380 self.button_exec_relax = self.add_execute_analysis(box, self.execute)
381
382
383 return box
384
385
394
395
397 """Set up, execute, and process the automatic Rx analysis.
398
399 @param event: The wx event.
400 @type event: wx event
401 """
402
403
404 self.gui.interpreter.flush()
405
406
407 if status.exec_lock.locked():
408 error_message("relax is currently executing.", "relax execution lock")
409 event.Skip()
410 return
411
412
413 self.gui.close_windows()
414
415
416 self.sync_ds(upload=True)
417
418
419 data, missing, model_mismatch = self.assemble_data()
420
421
422 if len(missing):
423 Missing_data(missing)
424 return
425
426
427 if len(model_mismatch):
428
429 text = ''
430 for model, exp in model_mismatch:
431 text += "The '%s' %s model cannot be used as no %s experiment types have been set up.\n" % (model, exp, exp)
432
433
434 error_message(text, caption='Model mismatch')
435 return
436
437
438 self.gui.show_controller(None)
439 self.gui.controller.log_panel.on_goto_end(None)
440
441
442 self.thread = Execute_relax_disp(self.gui, data, self.data_index)
443 self.thread.start()
444
445
446 event.Skip()
447
448
450 """Define the interatomic interactions of the spins via the interatom.define user function.
451
452 @keyword event: The wx event.
453 @type event: wx event
454 """
455
456
457 uf_store['interatom.define'](wx_wizard_modal=True, spin_id1='@N', spin_id2='@H')
458
459
461 """Read chemical shift data from a peak list via the chemical_shift.read user function.
462
463 @keyword event: The wx event.
464 @type event: wx event
465 """
466
467
468 uf_store['chemical_shift.read'](wx_wizard_modal=True)
469
470
472 """Load R1 relaxation data via the relax_data.read user function.
473
474 @keyword event: The wx event.
475 @type event: wx event
476 """
477
478
479 uf_store['relax_data.read'](wx_wizard_modal=True, ri_type='R1')
480
481
505
506
508 """Launch the peak loading wizard.
509
510 @param event: The wx event.
511 @type event: wx event
512 """
513
514
515 self.peak_wizard = Peak_intensity_wizard(relax_disp=True)
516
517
519 """The pre-run directory selection.
520
521 @param event: The wx event.
522 @type event: wx event
523 """
524
525
526 dialog = RelaxDirDialog(parent=self, message='Select the directory of the previous run', defaultPath=self.field_pre_run_dir.GetValue())
527
528
529 if status.show_gui and dialog.ShowModal() != wx.ID_OK:
530
531 return
532
533
534 path = gui_to_str(dialog.get_path())
535 if not path:
536 return
537
538
539 self.field_pre_run_dir.SetValue(str_to_gui(path))
540
541
543 """Set up spin clustering via the relax_disp.cluster user function.
544
545 @keyword event: The wx event.
546 @type event: wx event
547 """
548
549
550 uf_store['relax_disp.cluster'](wx_wizard_modal=True)
551
552
554 """The results directory selection.
555
556 @param event: The wx event.
557 @type event: wx event
558 """
559
560
561 dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue())
562
563
564 if status.show_gui and dialog.ShowModal() != wx.ID_OK:
565
566 return
567
568
569 path = gui_to_str(dialog.get_path())
570 if not path:
571 return
572
573
574 self.data.save_dir = path
575
576
577 self.field_results_dir.SetValue(str_to_gui(path))
578
579
581 """Set the nuclear isotope types of the spins via the spin.isotope user function.
582
583 @keyword event: The wx event.
584 @type event: wx event
585 """
586
587
588 uf_store['spin.isotope'](wx_wizard_modal=True, isotope='15N', spin_id='@N*')
589
590
592 """Synchronise the analysis frame and the relax data store, both ways.
593
594 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.
595
596 @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.
597 @type upload: bool
598 """
599
600
601 if upload:
602 self.data.numeric_only = self.numeric_only.GetValue()
603 elif hasattr(self.data, 'numeric_only'):
604 self.numeric_only.SetValue(bool(self.data.numeric_only))
605
606
607 if upload:
608 self.data.grid_inc = gui_to_int(self.grid_inc.GetValue())
609 elif hasattr(self.data, 'grid_inc'):
610 self.grid_inc.SetValue(int(self.data.grid_inc))
611
612
613 if upload:
614 self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue())
615 elif hasattr(self.data, 'mc_sim_num'):
616 self.mc_sim_num.SetValue(int(self.data.mc_sim_num))
617
618
619 if upload:
620 self.data.mc_sim_all_models = self.mc_sim_all_models.GetValue()
621 elif hasattr(self.data, 'mc_sim_all_models'):
622 self.mc_sim_all_models.SetValue(bool(self.data.mc_sim_all_models))
623
624
625 if upload:
626 self.data.insignificance = self.insignificance.GetValue()
627 try:
628 self.data.insignificance = gui_to_float(self.data.insignificance)
629 except:
630 pass
631 elif hasattr(self.data, 'insignificance'):
632 self.insignificance.SetValue(float_to_gui(self.data.insignificance))
633
634
635 if upload:
636 self.data.save_dir = gui_to_str(self.field_results_dir.GetValue())
637 else:
638 self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))
639
640
641 if upload:
642 self.data.pre_run_dir = gui_to_str(self.field_pre_run_dir.GetValue())
643 elif hasattr(self.data, 'pre_run_dir'):
644 self.field_pre_run_dir.SetValue(str_to_gui(self.data.pre_run_dir))
645
646
647 if upload:
648 self.data.disp_models = self.model_field.GetValue()
649 else:
650 self.model_field.set_value(self.data.disp_models)
651
652
654 """Update the cluster field."""
655
656
657 cluster_keys = []
658 if hasattr(cdp, 'clustering'):
659 cluster_keys = sorted(cdp.clustering.keys())
660
661
662 if not len(cluster_keys):
663 wx.CallAfter(self.field_cluster.SetValue, "free spins")
664
665
666 else:
667
668 text = ""
669 if "free spins" in cluster_keys:
670 text += "free spins"
671 for i in range(len(cluster_keys)):
672 if cluster_keys[i] != "free spins":
673 text += ", %s" % cluster_keys[i]
674
675
676 wx.CallAfter(self.field_cluster.SetValue, text)
677
678
680 """Launch the value.set user function.
681
682 @keyword event: The wx event.
683 @type event: wx event
684 """
685
686
687 uf_store['value.set'](wx_wizard_modal=True)
688
689
690
692 """The relaxation dispersion analysis execution object."""
693
706
707
708
710 """The diffusion model list GUI element."""
711
712
713 desc = "Relaxation dispersion models:"
714 models = [
715 MODEL_R2EFF,
716 None,
717 MODEL_NOREX,
718 None,
719 MODEL_LM63,
720 MODEL_LM63_3SITE,
721 MODEL_CR72,
722 MODEL_CR72_FULL,
723 MODEL_IT99,
724 MODEL_TSMFK01,
725 MODEL_B14,
726 MODEL_B14_FULL,
727 MODEL_NS_CPMG_2SITE_EXPANDED,
728 MODEL_NS_CPMG_2SITE_3D,
729 MODEL_NS_CPMG_2SITE_3D_FULL,
730 MODEL_NS_CPMG_2SITE_STAR,
731 MODEL_NS_CPMG_2SITE_STAR_FULL,
732 None,
733 MODEL_M61,
734 MODEL_M61B,
735 MODEL_DPL94,
736 MODEL_TP02,
737 MODEL_TAP03,
738 MODEL_MP05,
739 MODEL_NS_R1RHO_2SITE,
740 MODEL_NS_R1RHO_3SITE_LINEAR,
741 MODEL_NS_R1RHO_3SITE,
742 None,
743 MODEL_MMQ_CR72,
744 MODEL_NS_MMQ_2SITE,
745 MODEL_NS_MMQ_3SITE_LINEAR,
746 MODEL_NS_MMQ_3SITE
747 ]
748 params = [
749 "{%s/%s, %s}" % (r2eff, r1rho, i0),
750 None,
751 "{%s, ...}" % (r2),
752 None,
753 "{%s, ..., %s, %s}" % (r2, phi_ex, kex),
754 "{%s, ..., %s, kB, %s, kC}" % (r2, phi_exB, phi_exC),
755 "{%s, ..., pA, %s, %s}" % (r2, dw, kex),
756 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex),
757 "{%s, ..., %s, %s, %s}" % (r2, phi_ex, padw2, kex),
758 "{%s, ..., %s, k_AB}" % (r2a, dw),
759 "{%s, ..., pA, %s, %s}" % (r2, dw, kex),
760 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex),
761 "{%s, ..., pA, %s, %s}" % (r2, dw, kex),
762 "{%s, ..., pA, %s, %s}" % (r2, dw, kex),
763 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex),
764 "{%s, ..., pA, %s, %s}" % (r2, dw, kex),
765 "{%s, %s, ..., pA, %s, %s}" % (r2a, r2b, dw, kex),
766 None,
767 "{%s, ..., %s, %s}" % (r1rho_prime, phi_ex, kex),
768 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex),
769 "{%s, ..., %s, %s}" % (r1rho_prime, phi_ex, kex),
770 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex),
771 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex),
772 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex),
773 "{%s, ..., pA, %s, %s}" % (r1rho_prime, dw, kex),
774 "{%s, ..., pA, %s, %s, pB, %s, %s}" % (r1rho_prime, dw_AB, kAB, dw_BC, kBC),
775 "{%s, ..., pA, %s, %s, pB, %s, %s, %s}" % (r1rho_prime, dw_AB, kAB, dw_BC, kBC, kAC),
776 None,
777 "{%s, ..., pA, %s, %s, %s}" % (r2, dw, dwH, kex),
778 "{%s, ..., pA, %s, %s, %s}" % (r2, dw, dwH, kex),
779 "{%s, ..., pA, %s, %s, %s, pB, %s, %s, %s}" % (r2, dw_AB, dwH_AB, kAB, dw_BC, dwH_BC, kBC),
780 "{%s, ..., pA, %s, %s, %s, pB, %s, %s, %s, %s}" % (r2, dw_AB, dwH_AB, kAB, dw_BC, dwH_BC, kBC, kAC)
781 ]
782 model_desc = [
783 "The base model for determining the %s/%s values and errors for all other models." % (r2eff, r1rho),
784 None,
785 "The model for no chemical exchange relaxation.",
786 None,
787 "The original Luz and Meiboom (1963) 2-site fast exchange equation.",
788 "The original Luz and Meiboom (1963) 3-site fast exchange equation.",
789 "The Carver and Richards (1972) 2-site equation for all time scales (with %s = %s)." % (r2a, r2b),
790 "The Carver and Richards (1972) 2-site equation for all time scales.",
791 "The Ishima and Torchia (1999) 2-site model for all time scales with pA >> pB.",
792 "The Tollinger et al. (2001) 2-site very-slow exchange model.",
793 "The Baldwin (2014) 2-site exact solution model for all time scales (with %s = %s)." % (r2a, r2b),
794 "The Baldwin (2014) 2-site exact solution model for all time scales.",
795 "The 2-site numerical solution expanded using Maple by Nikolai Skrynnikov.",
796 "The 2-site numerical solution using 3D magnetisation vectors (with %s = %s)." % (r2a, r2b),
797 "The 2-site numerical solution using 3D magnetisation vectors.",
798 "The 2-site numerical solution using complex conjugate matrices (with %s = %s)." % (r2a, r2b),
799 "The 2-site numerical solution using complex conjugate matrices.",
800 None,
801 "The Meiboom (1961) 2-site fast exchange equation.",
802 "The Meiboom (1961) 2-site equation for all time scales with pA >> pB.",
803 "The Davis, Perlman and London (1994) 2-site fast exchange equation.",
804 "The Trott and Palmer (2002) 2-site equation for all time scales.",
805 "The Trott, Abergel and Palmer (2003) off-resonance 2-site equation for all time scales.",
806 "The Miloushev and Palmer (2005) off-resonance 2-site equation for all time scales.",
807 "The 2-site numerical solution using 3D magnetisation vectors.",
808 "The 3-site linearised numerical solution using 3D magnetisation vectors.",
809 "The 3-site numerical solution using 3D magnetisation vectors.",
810 None,
811 "The CR72 2-site model extended to MMQ CPMG data by Korzhnev et al., 2004.",
812 "The 2-site numerical solution of Korzhnev et al. (2004) from multi-quantum CPMG data.",
813 "The 3-site linearised numerical solution of Korzhnev et al. (2005) for MMQ CPMG data.",
814 "The 3-site numerical solution of Korzhnev et al. (2005) for MMQ CPMG data."
815 ]
816 size = wx.Size(1024, 750)
817 tooltip = "The list of all relaxation dispersion models to be optimised as part of the protocol."
818 tooltip_button = "Open the model list selector window."
819