diff --git a/docs/source/release/v4.1.0/muon.rst b/docs/source/release/v4.1.0/muon.rst index 5830cc7f34cc1d7273106d34249adc993e56308f..80d0b647a6d52b16e9cadcc226543972331ee406 100644 --- a/docs/source/release/v4.1.0/muon.rst +++ b/docs/source/release/v4.1.0/muon.rst @@ -14,4 +14,11 @@ MuSR Changes New ### -* Added phase tab for calculating :ref:`phase tables <algm-CalMuonDetectorPhases>` and :ref:`PhaseQuad <algm-PhaseQuad>` workspaces to Frequency Domain Analysis GUI. \ No newline at end of file + +* Added phase tab for calculating :ref:`phase tables <algm-CalMuonDetectorPhases>` and :ref:`PhaseQuad <algm-PhaseQuad>` workspaces to Frequency Domain Analysis GUI. + +Improvements +############ + +* Phase table and phase Quad options from frequency domain transform tab moved to phase calculations tab. + diff --git a/scripts/Muon/GUI/Common/ADSHandler/muon_workspace_wrapper.py b/scripts/Muon/GUI/Common/ADSHandler/muon_workspace_wrapper.py index 841ba85ac7c0161ef39ce7d7b5e4e40a9f52f532..e53619e3a10cde8536429ec99f56eb7cb69c56f2 100644 --- a/scripts/Muon/GUI/Common/ADSHandler/muon_workspace_wrapper.py +++ b/scripts/Muon/GUI/Common/ADSHandler/muon_workspace_wrapper.py @@ -9,7 +9,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.simpleapi import mtd from mantid import api -from mantid.api import Workspace, WorkspaceGroup +from mantid.api import Workspace def add_directory_structure(dirs): @@ -63,13 +63,14 @@ class MuonWorkspaceWrapper(object): A basic muon workspace which is either the workspace or the name of the workspace in the ADS """ - def __init__(self, workspace): + def __init__(self, workspace, name=''): self._is_in_ads = False self._workspace = None self._directory_structure = "" self._workspace_name = "" self.workspace = workspace + self.name = name def __str__(self): return "MuonWorkspaceWrapper Object \n" \ @@ -116,15 +117,13 @@ class MuonWorkspaceWrapper(object): if mtd.doesExist(self._workspace_name): mtd.remove(self._workspace_name) self._is_in_ads = False - self.name = "" - self._directory_structure = "" - if isinstance(value, Workspace) and not isinstance(value, WorkspaceGroup): + if isinstance(value, Workspace): self._workspace = value else: raise AttributeError("Attempting to set object of type {}, must be" " a Mantid Workspace type".format(type(value))) - def show(self, name): + def show(self, name=''): """ Show the workspace in the ADS inside the WorkspaceGroup structure specified in name name = dirs/../dirs/workspace_name @@ -132,8 +131,10 @@ class MuonWorkspaceWrapper(object): if not self.is_hidden: return - if len(name) > 0 and self.is_hidden: + if len(name) > 0: self.name = str(name) + + if len(self.name) > 0 and self.is_hidden: # add workspace to ADS mtd.addOrReplace(self._workspace_name, self._workspace) @@ -158,8 +159,6 @@ class MuonWorkspaceWrapper(object): mtd.remove(self._workspace_name) self._is_in_ads = False - self._workspace_name = "" - self._directory_structure = "" def add_directory_structure(self): """ diff --git a/scripts/Muon/GUI/Common/ADSHandler/workspace_naming.py b/scripts/Muon/GUI/Common/ADSHandler/workspace_naming.py index de54a72faff3a79ec57aa387d8408869244433a2..056303a55b730bf3b4b455a5f4ffce2637b0bb82 100644 --- a/scripts/Muon/GUI/Common/ADSHandler/workspace_naming.py +++ b/scripts/Muon/GUI/Common/ADSHandler/workspace_naming.py @@ -5,6 +5,7 @@ # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) +import re def get_raw_data_workspace_name(context, run, period='1'): @@ -96,5 +97,54 @@ def get_pair_data_directory(context, run): return context.data_context._base_run_name(run) + " Pairs/" -def get_phase_quad_workspace_name(context, run, period): - return get_raw_data_workspace_name(context, run, period=str(period)) + " (PhaseQuad)" +def get_phase_table_workspace_name(raw_workspace, forward_group, backward_group): + workspace_name = raw_workspace.replace('_raw_data', '; PhaseTable') + workspace_name += '; ' + forward_group + ', ' + backward_group + return workspace_name + + +def get_base_run_name(run, instrument): + if isinstance(run, int): + return str(instrument) + str(run) + else: + return str(instrument) + run + + +def get_phase_table_workspace_group_name(insertion_workspace_name, instrument): + run = re.search('[0-9]+', insertion_workspace_name).group() + group = get_base_run_name(run, instrument) + ' Phase Tab/' + + return group + + +def get_fft_workspace_group_name(insertion_workspace_name, instrument): + run = re.search('[0-9]+', insertion_workspace_name).group() + group = get_base_run_name(run, instrument) + ' FFT/' + + return group + + +def get_phase_quad_workspace_name(input_workspace, phase_table): + return input_workspace.replace('_raw_data', '; PhaseQuad') + ' ' + phase_table + + +def get_fitting_workspace_name(base_name): + return base_name + '; fit_information' + + +def get_fft_workspace_name(input_workspace, imaginary_input_workspace): + if imaginary_input_workspace: + return 'FFT; Re ' + input_workspace + '; Im ' + imaginary_input_workspace + else: + return 'FFT; Re ' + input_workspace + + +def get_maxent_workspace_name(input_workspace): + return input_workspace + '; MaxEnt' + + +def get_maxent_workspace_group_name(insertion_workspace_name, instrument): + run = re.search('[0-9]+', insertion_workspace_name).group() + group = get_base_run_name(run, instrument) + ' Maxent/' + + return group diff --git a/scripts/Muon/GUI/Common/contexts/muon_context.py b/scripts/Muon/GUI/Common/contexts/muon_context.py index faa41858fdada37e8b5531bf694213f0b0a1913f..34ae205d1cbf208450569a96fb9740a37ae79b54 100644 --- a/scripts/Muon/GUI/Common/contexts/muon_context.py +++ b/scripts/Muon/GUI/Common/contexts/muon_context.py @@ -28,6 +28,8 @@ class MuonContext(object): self._phase_context = muon_phase_context self.base_directory = base_directory + self.gui_context.update({'DeadTimeSource': 'None', 'LastGoodDataFromFile': True}) + @property def data_context(self): return self._data_context @@ -146,9 +148,8 @@ class MuonContext(object): workspace_options = [] for run in run_numbers: - workspace_options += [ - wsName.get_phase_quad_workspace_name(self, run_list_to_string(run), period=str(period + 1)) - for period in range(self.data_context.num_periods(run))] + workspace_options += self.phase_context.get_phase_quad(self.data_context.instrument, run_list_to_string(run)) + for name in pair_names: workspace_options.append( wsName.get_pair_data_workspace_name(self, @@ -179,9 +180,37 @@ class MuonContext(object): for run_number in run_numbers for period in range(self.data_context.num_periods(run_number))] return runs - @property - def first_good_data(self): + def first_good_data(self, run): + if not self.data_context.get_loaded_data_for_run(run): + return 0.0 + if self.gui_context['FirstGoodDataFromFile']: - return self.data_context.get_loaded_data_for_run(self.data_context.current_runs[-1])["FirstGoodData"] + return self.data_context.get_loaded_data_for_run(run)["FirstGoodData"] else: - return self.gui_context['FirstGoodData'] + if 'FirstGoodData' in self.gui_context: + return self.gui_context['FirstGoodData'] + else: + self.gui_context['FirstGoodData'] = self.data_context.get_loaded_data_for_run(run)["FirstGoodData"] + return self.gui_context['FirstGoodData'] + + def last_good_data(self, run): + if not self.data_context.get_loaded_data_for_run(run): + return 0.0 + + if self.gui_context['LastGoodDataFromFile']: + return round(max(self.data_context.get_loaded_data_for_run(run)["OutputWorkspace"][0].workspace.dataX(0)), 2) + else: + if 'LastGoodData' in self.gui_context: + return self.gui_context['LastGoodData'] + else: + self.gui_context['LastGoodData'] = round(max(self.data_context.get_loaded_data_for_run(run) + ["OutputWorkspace"][0].workspace.dataX(0)), 2) + return self.gui_context['LastGoodData'] + + def dead_time_table(self, run): + if self.gui_context['DeadTimeSource'] == 'FromADS': + return self.gui_context['DeadTimeTable'] + elif self.gui_context['DeadTimeSource'] == 'FromFile': + return self.data_context.get_loaded_data_for_run(run)["DataDeadTimeTable"] + elif self.gui_context['DeadTimeSource'] == 'None': + return None diff --git a/scripts/Muon/GUI/Common/contexts/phase_table_context.py b/scripts/Muon/GUI/Common/contexts/phase_table_context.py index d2c081389bfd3729e2527e1e2e92d9eeb5029345..6afb6a2eb9aba855d255597b36ee7ad0f5d382f8 100644 --- a/scripts/Muon/GUI/Common/contexts/phase_table_context.py +++ b/scripts/Muon/GUI/Common/contexts/phase_table_context.py @@ -6,10 +6,19 @@ class PhaseTableContext(object): def __init__(self): self.options_dict = default_dict.copy() self.phase_tables = [] + self.phase_quad = [] - def add_phase_table(self, name): - if name not in self.phase_tables: - self.phase_tables.append(name) + def add_phase_table(self, workspace): + self.phase_tables = [phase_table for phase_table in self.phase_tables if phase_table.workspace_name != workspace.workspace_name] + self.phase_tables.append(workspace) def get_phase_table_list(self, instrument): - return [phase_table for phase_table in self.phase_tables if instrument in phase_table] + return [phase_table.workspace_name for phase_table in self.phase_tables if instrument in phase_table.workspace_name] + + def add_phase_quad(self, workspace): + self.phase_quad = [item for item in self.phase_quad if item.workspace_name != workspace.workspace_name] + self.phase_quad.append(workspace) + + def get_phase_quad(self, instrument, run): + return [phase_quad.workspace_name for phase_quad in self.phase_quad if instrument in phase_quad.workspace_name + and run in phase_quad.workspace_name] diff --git a/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_model.py b/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_model.py index 8e16a632c036651077a74f5d67a5f6761e91229d..5d1bffe3715ab04cb9d3dc0167f9f4f490380690 100644 --- a/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_model.py +++ b/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_model.py @@ -51,6 +51,9 @@ class InstrumentWidgetModel(object): def set_first_good_data_source(self, state): self._context.gui_context.update_and_send_signal(FirstGoodDataFromFile=state) + def set_last_good_data_source(self, state): + self._context.gui_context.update_and_send_signal(LastGoodDataFromFile=state) + def get_file_first_good_data(self): return self._data.current_data["FirstGoodData"] @@ -63,12 +66,22 @@ class InstrumentWidgetModel(object): first_good_data = self._context.gui_context["FirstGoodData"] return first_good_data + def get_last_good_data(self): + if self._data.current_runs: + run = self._data.current_runs[0] + return self._context.last_good_data(run) + else: + return 0.0 + def set_user_time_zero(self, time_zero): self._context.gui_context.update_and_send_signal(TimeZero=time_zero) def set_user_first_good_data(self, first_good_data): self._context.gui_context.update_and_send_signal(FirstGoodData=first_good_data) + def set_user_last_good_data(self, last_good_data): + self._context.gui_context.update_and_send_signal(LastGoodData=last_good_data) + def get_dead_time_table_from_data(self): return self._data.current_data["DataDeadTimeTable"] diff --git a/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_presenter.py b/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_presenter.py index 685564b771e55dac8d206907ad288faa7e9d9d40..8e4b5efc07316b6715696f81e72e2b68cdaa4260 100644 --- a/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_presenter.py +++ b/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_presenter.py @@ -29,6 +29,9 @@ class InstrumentWidgetPresenter(HomeTabSubWidget): self._view.on_first_good_data_checkState_changed(self.handle_loaded_first_good_data_checkState_change) self._view.on_first_good_data_changed(self.handle_user_changes_first_good_data) + self._view.on_last_good_data_checkState_changed(self.handle_loaded_last_good_data_checkState_change) + self._view.on_last_good_data_changed(self.handle_user_changes_last_good_data) + self._view.on_fixed_rebin_edit_changed(self.handle_fixed_rebin_changed) self._view.on_variable_rebin_edit_changed(self.handle_variable_rebin_changed) @@ -44,6 +47,7 @@ class InstrumentWidgetPresenter(HomeTabSubWidget): self.handle_loaded_time_zero_checkState_change() self.handle_loaded_first_good_data_checkState_change() + self.handle_loaded_last_good_data_checkState_change() def show(self): self._view.show() @@ -56,6 +60,9 @@ class InstrumentWidgetPresenter(HomeTabSubWidget): first_good_data = self._model.get_user_first_good_data() self._view.set_first_good_data(first_good_data) + last_good_data = self._model.get_last_good_data() + self._view.set_last_good_data(last_good_data) + if self._view.time_zero_state(): time_zero = self._model.get_file_time_zero() self._view.set_time_zero(time_zero) @@ -68,6 +75,7 @@ class InstrumentWidgetPresenter(HomeTabSubWidget): def clear_view(self): self._view.set_time_zero(0.0) self._view.set_first_good_data(0.0) + self._view.set_last_good_data(0.0) self._view.set_combo_boxes_to_default() self._view.set_checkboxes_to_defualt() @@ -107,6 +115,20 @@ class InstrumentWidgetPresenter(HomeTabSubWidget): first_good_data = self._model.get_user_first_good_data() self._view.set_first_good_data(first_good_data) + def handle_user_changes_last_good_data(self): + last_good_data = self._view.get_last_good_data() + self._model.set_user_last_good_data(last_good_data) + + def handle_loaded_last_good_data_checkState_change(self): + if self._view.last_good_data_state(): + self._model.set_last_good_data_source(True) + last_good_data = self._model.get_last_good_data() + self._view.set_last_good_data(last_good_data) + else: + self._model.set_last_good_data_source(False) + last_good_data = self._model.get_last_good_data() + self._view.set_last_good_data(last_good_data) + # ------------------------------------------------------------------------------------------------------------------ # Rebin # ------------------------------------------------------------------------------------------------------------------ diff --git a/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_view.py b/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_view.py index 3d50ab0a9dc9467f0b1bcc0271e921bc90004c59..1e28ca9c1dbe2e150dcab9ab6241ab071523d8d0 100644 --- a/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_view.py +++ b/scripts/Muon/GUI/Common/home_instrument_widget/home_instrument_widget_view.py @@ -30,22 +30,25 @@ class InstrumentWidgetView(QtWidgets.QWidget): self.dead_time_file_loader_hidden(True) self.dead_time_other_file_hidden(True) - self.deadtime_selector.currentIndexChanged.connect( + self.dead_time_selector.currentIndexChanged.connect( self.on_dead_time_combo_changed) self.rebin_selector.currentIndexChanged.connect( self.on_rebin_combo_changed) - self.timezero_checkbox.stateChanged.connect( + self.time_zero_checkbox.stateChanged.connect( self.on_time_zero_checkbox_state_change) - self.firstgooddata_checkbox.stateChanged.connect( + self.first_good_data_checkbox.stateChanged.connect( self.on_first_good_data_checkbox_state_change) + self.last_good_data_checkbox.stateChanged.connect( + self.on_last_good_data_checkbox_state_change) self._on_dead_time_from_data_selected = None self._on_dead_time_from_other_file_selected = lambda: 0 - self.firstgooddata_checkbox.setChecked(True) - self.timezero_checkbox.setChecked(True) + self.first_good_data_checkbox.setChecked(True) + self.time_zero_checkbox.setChecked(True) self.time_zero_edit_enabled(True) self.first_good_data_edit_enabled(True) + self.last_good_data_edit_enabled(True) self._on_time_zero_changed = lambda: 0 self._on_first_good_data_changed = lambda: 0 @@ -53,11 +56,13 @@ class InstrumentWidgetView(QtWidgets.QWidget): self._on_dead_time_file_option_selected = lambda: 0 self._on_dead_time_unselected = lambda: 0 - self.timezero_edit.editingFinished.connect( + self.time_zero_edit.editingFinished.connect( lambda: self._on_time_zero_changed() if not self.is_time_zero_checked() else None) - self.firstgooddata_edit.editingFinished.connect( + self.first_good_data_edit.editingFinished.connect( lambda: self._on_first_good_data_changed() if not self.is_first_good_data_checked() else None) - self.deadtime_file_selector.currentIndexChanged.connect( + self.last_good_data_edit.editingFinished.connect( + lambda: self._on_last_good_data_changed() if not self.is_last_good_data_checked() else None) + self.dead_time_file_selector.currentIndexChanged.connect( self.on_dead_time_file_combo_changed) def setup_interface(self): @@ -66,6 +71,7 @@ class InstrumentWidgetView(QtWidgets.QWidget): self.setup_instrument_row() self.setup_time_zero_row() self.setup_first_good_data_row() + self.setup_last_good_data_row() self.setup_dead_time_row() self.setup_rebin_row() @@ -86,7 +92,7 @@ class InstrumentWidgetView(QtWidgets.QWidget): self.group2 = QtWidgets.QGroupBox("Rebin") self.group2.setFlat(False) - self.group2.setLayout(self.horizontal_layout_5) + self.group2.setLayout(self.rebin_layout) self.widget_layout = QtWidgets.QVBoxLayout(self) self.widget_layout.addWidget(self.group) @@ -94,7 +100,7 @@ class InstrumentWidgetView(QtWidgets.QWidget): self.setLayout(self.widget_layout) def show_file_browser_and_return_selection( - self, file_filter, search_directories, multiple_files=False): + self, file_filter, search_directories, multiple_files=False): default_directory = search_directories[0] if multiple_files: chosen_files = QtWidgets.QFileDialog.getOpenFileNames( @@ -109,13 +115,13 @@ class InstrumentWidgetView(QtWidgets.QWidget): self.rebin_selector.setCurrentIndex(0) self.rebin_fixed_hidden(True) self.rebin_variable_hidden(True) - self.deadtime_selector.setCurrentIndex(0) + self.dead_time_selector.setCurrentIndex(0) self.dead_time_data_info_hidden(True) self.dead_time_file_loader_hidden(True) def set_checkboxes_to_defualt(self): - self.timezero_checkbox.setChecked(True) - self.firstgooddata_checkbox.setChecked(True) + self.time_zero_checkbox.setChecked(True) + self.first_good_data_checkbox.setChecked(True) def warning_popup(self, message): warning(message, parent=self) @@ -138,15 +144,12 @@ class InstrumentWidgetView(QtWidgets.QWidget): self.instrument_selector.setSizePolicy( self._fixed_aspect_ratio_size_policy( self.instrument_selector)) - self.instrument_selector.setObjectName("instrumentSelector") self.instrument_selector.addItems(["None"] + allowed_instruments) self.instrument_label = QtWidgets.QLabel(self) - self.instrument_label.setObjectName("instrumentLabel") self.instrument_label.setText("Instrument : ") self.horizontal_layout = QtWidgets.QHBoxLayout() - self.horizontal_layout.setObjectName("horizontalLayout") self.horizontal_layout.addWidget(self.instrument_label) self.horizontal_layout.addWidget(self.instrument_selector) self.horizontal_layout.addStretch(0) @@ -197,66 +200,60 @@ class InstrumentWidgetView(QtWidgets.QWidget): # ------------------------------------------------------------------------------------------------------------------ def setup_time_zero_row(self): - self.timezero_label = QtWidgets.QLabel(self) - self.timezero_label.setObjectName("timeZeroLabel") - self.timezero_label.setText("Time Zero : ") + self.time_zero_label = QtWidgets.QLabel(self) + self.time_zero_label.setText("Time Zero : ") - self.timezero_edit = QtWidgets.QLineEdit(self) + self.time_zero_edit = QtWidgets.QLineEdit(self) timezero_validator = QtGui.QRegExpValidator( QtCore.QRegExp(valid_float_regex), - self.timezero_edit) - self.timezero_edit.setValidator(timezero_validator) - self.timezero_edit.setObjectName("timeZeroEdit") - self.timezero_edit.setText("") - - self.timezero_unit_label = QtWidgets.QLabel(self) - self.timezero_unit_label.setObjectName("timeZeroUnitLabel") - self.timezero_unit_label.setText(u"\u03BCs (From data file ") - - self.timezero_checkbox = QtWidgets.QCheckBox(self) - self.timezero_checkbox.setObjectName("timeZeroCheckbox") - self.timezero_checkbox.setChecked(True) - - self.timezero_label_2 = QtWidgets.QLabel(self) - self.timezero_label_2.setObjectName("timeZeroLabel") - self.timezero_label_2.setText(" )") - - self.horizontal_layout_2 = QtWidgets.QHBoxLayout() - self.horizontal_layout_2.setObjectName("horizontalLayout2") - self.horizontal_layout_2.addSpacing(10) - self.horizontal_layout_2.addWidget(self.timezero_unit_label) - self.horizontal_layout_2.addWidget(self.timezero_checkbox) - self.horizontal_layout_2.addWidget(self.timezero_label_2) - self.horizontal_layout_2.addStretch(0) - - self.layout.addWidget(self.timezero_label, 1, 0) - self.layout.addWidget(self.timezero_edit, 1, 1) - self.layout.addItem(self.horizontal_layout_2, 1, 2) + self.time_zero_edit) + self.time_zero_edit.setValidator(timezero_validator) + self.time_zero_edit.setText("") + + self.time_zero_unit_label = QtWidgets.QLabel(self) + self.time_zero_unit_label.setText(u"\u03BCs (From data file ") + + self.time_zero_checkbox = QtWidgets.QCheckBox(self) + self.time_zero_checkbox.setChecked(True) + + self.time_zero_label_2 = QtWidgets.QLabel(self) + self.time_zero_label_2.setText(" )") + + self.time_zero_layout = QtWidgets.QHBoxLayout() + self.time_zero_layout.addSpacing(10) + self.time_zero_layout.addWidget(self.time_zero_unit_label) + self.time_zero_layout.addWidget(self.time_zero_checkbox) + self.time_zero_layout.addWidget(self.time_zero_label_2) + self.time_zero_layout.addStretch(0) + + self.layout.addWidget(self.time_zero_label, 1, 0) + self.layout.addWidget(self.time_zero_edit, 1, 1) + self.layout.addItem(self.time_zero_layout, 1, 2) def set_time_zero(self, time_zero): - self.timezero_edit.setText( + self.time_zero_edit.setText( "{0:.3f}".format(round(float(time_zero), 3))) def get_time_zero(self): - return float(self.timezero_edit.text()) + return float(self.time_zero_edit.text()) def time_zero_edit_enabled(self, enabled): - self.timezero_edit.setEnabled(not enabled) + self.time_zero_edit.setEnabled(not enabled) def is_time_zero_checked(self): - return self.timezero_checkbox.isChecked() + return self.time_zero_checkbox.isChecked() def on_time_zero_changed(self, slot): self._on_time_zero_changed = slot def on_time_zero_checkState_changed(self, slot): - self.timezero_checkbox.stateChanged.connect(slot) + self.time_zero_checkbox.stateChanged.connect(slot) def time_zero_state(self): - return self.timezero_checkbox.isChecked() + return self.time_zero_checkbox.isChecked() def on_time_zero_checkbox_state_change(self): - self.time_zero_edit_enabled(self.timezero_checkbox.isChecked()) + self.time_zero_edit_enabled(self.time_zero_checkbox.isChecked()) # ------------------------------------------------------------------------------------------------------------------ # First good data @@ -264,126 +261,176 @@ class InstrumentWidgetView(QtWidgets.QWidget): def setup_first_good_data_row(self): - self.firstgooddata_label = QtWidgets.QLabel(self) - self.firstgooddata_label.setObjectName("firstgooddataLabel") - self.firstgooddata_label.setText("First Good Data : ") + self.first_good_data_label = QtWidgets.QLabel(self) + self.first_good_data_label.setText("First Good Data : ") - self.firstgooddata_edit = QtWidgets.QLineEdit(self) + self.first_good_data_edit = QtWidgets.QLineEdit(self) - firstgooddata_validator = QtGui.QRegExpValidator( + first_good_data_validator = QtGui.QRegExpValidator( QtCore.QRegExp(valid_float_regex), - self.timezero_edit) - self.firstgooddata_edit.setValidator(firstgooddata_validator) - self.firstgooddata_edit.setObjectName("firstgooddataEdit") - self.firstgooddata_edit.setText("") - - self.firstgooddata_unit_label = QtWidgets.QLabel(self) - self.firstgooddata_unit_label.setObjectName("firstgooddataUnitLabel") - self.firstgooddata_unit_label.setText(u" \u03BCs (From data file ") - - self.firstgooddata_checkbox = QtWidgets.QCheckBox(self) - self.firstgooddata_checkbox.setObjectName("firstgooddataCheckbox") - self.firstgooddata_checkbox.setChecked(True) - - self.firstgooddata_label_2 = QtWidgets.QLabel(self) - self.firstgooddata_label_2.setObjectName("timeZeroLabel") - self.firstgooddata_label_2.setText(" )") - - self.horizontal_layout_3 = QtWidgets.QHBoxLayout() - self.horizontal_layout_3.setObjectName("horizontalLayout3") - self.horizontal_layout_3.addSpacing(10) - self.horizontal_layout_3.addWidget(self.firstgooddata_unit_label) - self.horizontal_layout_3.addWidget(self.firstgooddata_checkbox) - self.horizontal_layout_3.addWidget(self.firstgooddata_label_2) - self.horizontal_layout_3.addStretch(0) - - self.layout.addWidget(self.firstgooddata_label, 2, 0) - self.layout.addWidget(self.firstgooddata_edit, 2, 1) - self.layout.addItem(self.horizontal_layout_3, 2, 2) + self.time_zero_edit) + self.first_good_data_edit.setValidator(first_good_data_validator) + self.first_good_data_edit.setText("") + + self.first_good_data_unit_label = QtWidgets.QLabel(self) + self.first_good_data_unit_label.setText(u" \u03BCs (From data file ") + + self.first_good_data_checkbox = QtWidgets.QCheckBox(self) + self.first_good_data_checkbox.setChecked(True) + + self.first_good_data_label_2 = QtWidgets.QLabel(self) + self.first_good_data_label_2.setText(" )") + + self.first_good_data_layout = QtWidgets.QHBoxLayout() + self.first_good_data_layout.addSpacing(10) + self.first_good_data_layout.addWidget(self.first_good_data_unit_label) + self.first_good_data_layout.addWidget(self.first_good_data_checkbox) + self.first_good_data_layout.addWidget(self.first_good_data_label_2) + self.first_good_data_layout.addStretch(0) + + self.layout.addWidget(self.first_good_data_label, 2, 0) + self.layout.addWidget(self.first_good_data_edit, 2, 1) + self.layout.addItem(self.first_good_data_layout, 2, 2) def on_first_good_data_changed(self, slot): self._on_first_good_data_changed = slot def set_first_good_data(self, first_good_data): - self.firstgooddata_edit.setText( + self.first_good_data_edit.setText( "{0:.3f}".format(round(float(first_good_data), 3))) def on_first_good_data_checkState_changed(self, slot): - self.firstgooddata_checkbox.stateChanged.connect(slot) + self.first_good_data_checkbox.stateChanged.connect(slot) def first_good_data_state(self): - return self.firstgooddata_checkbox.checkState() + return self.first_good_data_checkbox.checkState() def is_first_good_data_checked(self): - return self.firstgooddata_checkbox.checkState() + return self.first_good_data_checkbox.checkState() def on_first_good_data_checkbox_state_change(self): self.first_good_data_edit_enabled( - self.firstgooddata_checkbox.checkState()) + self.first_good_data_checkbox.checkState()) def first_good_data_edit_enabled(self, disabled): - self.firstgooddata_edit.setEnabled(not disabled) + self.first_good_data_edit.setEnabled(not disabled) def get_first_good_data(self): - return float(self.firstgooddata_edit.text()) + return float(self.first_good_data_edit.text()) + + # ------------------------------------------------------------------------------------------------------------------ + # Last Good Data + # ------------------------------------------------------------------------------------------------------------------- + + def setup_last_good_data_row(self): + + self.last_good_data_label = QtWidgets.QLabel(self) + self.last_good_data_label.setText("Last Good Data : ") + + self.last_good_data_edit = QtWidgets.QLineEdit(self) + + last_good_data_validator = QtGui.QRegExpValidator( + QtCore.QRegExp(valid_float_regex), + self.first_good_data_edit) + self.last_good_data_edit.setValidator(last_good_data_validator) + self.last_good_data_edit.setText("") + + self.last_good_data_unit_label = QtWidgets.QLabel(self) + self.last_good_data_unit_label.setText(u" \u03BCs (From data file ") + + self.last_good_data_checkbox = QtWidgets.QCheckBox(self) + self.last_good_data_checkbox.setChecked(True) + + self.last_good_data_label_2 = QtWidgets.QLabel(self) + self.last_good_data_label_2.setText(" )") + + self.last_good_data_layout = QtWidgets.QHBoxLayout() + self.last_good_data_layout.addSpacing(10) + self.last_good_data_layout.addWidget(self.last_good_data_unit_label) + self.last_good_data_layout.addWidget(self.last_good_data_checkbox) + self.last_good_data_layout.addWidget(self.last_good_data_label_2) + self.last_good_data_layout.addStretch(0) + + self.layout.addWidget(self.last_good_data_label, 3, 0) + self.layout.addWidget(self.last_good_data_edit, 3, 1) + self.layout.addItem(self.last_good_data_layout, 3, 2) + + def on_last_good_data_changed(self, slot): + self._on_last_good_data_changed = slot + + def set_last_good_data(self, last_good_data): + self.last_good_data_edit.setText( + "{0:.3f}".format(round(float(last_good_data), 3))) + + def on_last_good_data_checkState_changed(self, slot): + self.last_good_data_checkbox.stateChanged.connect(slot) + + def last_good_data_state(self): + return self.last_good_data_checkbox.checkState() + + def is_last_good_data_checked(self): + return self.last_good_data_checkbox.checkState() + + def on_last_good_data_checkbox_state_change(self): + self.last_good_data_edit_enabled( + self.last_good_data_checkbox.checkState()) + + def last_good_data_edit_enabled(self, disabled): + self.last_good_data_edit.setEnabled(not disabled) + + def get_last_good_data(self): + return float(self.last_good_data_edit.text()) # ------------------------------------------------------------------------------------------------------------------ # Dead time correction # ------------------------------------------------------------------------------------------------------------------ def setup_dead_time_row(self): - self.deadtime_label = QtWidgets.QLabel(self) - self.deadtime_label.setObjectName("deadTimeLabel") - self.deadtime_label.setText("Dead Time : ") + self.dead_time_label = QtWidgets.QLabel(self) + self.dead_time_label.setText("Dead Time : ") - self.deadtime_selector = QtWidgets.QComboBox(self) - self.deadtime_selector.setObjectName("deadTimeSelector") - self.deadtime_selector.addItems( + self.dead_time_selector = QtWidgets.QComboBox(self) + self.dead_time_selector.addItems( ["None", "From data file", "From table workspace", "From other file"]) - self.deadtime_label_2 = QtWidgets.QLabel(self) - self.deadtime_label_2.setObjectName("deadTimeFileLabel") - self.deadtime_label_2.setText("Dead Time Workspace : ") + self.dead_time_label_2 = QtWidgets.QLabel(self) + self.dead_time_label_2.setText("Dead Time Workspace : ") - self.deadtime_label_3 = QtWidgets.QLabel(self) - self.deadtime_label_3.setObjectName("deadTimeInfoLabel") - self.deadtime_label_3.setText("") + self.dead_time_label_3 = QtWidgets.QLabel(self) + self.dead_time_label_3.setText("") - self.deadtime_file_selector = QtWidgets.QComboBox(self) - self.deadtime_file_selector.setObjectName("deadTimeCombo") - self.deadtime_file_selector.addItem("None") - self.deadtime_file_selector.setToolTip( + self.dead_time_file_selector = QtWidgets.QComboBox(self) + self.dead_time_file_selector.addItem("None") + self.dead_time_file_selector.setToolTip( "Select a table which is loaded into the ADS.") - self.deadtime_browse_button = QtWidgets.QPushButton(self) - self.deadtime_browse_button.setObjectName("deadTimeBrowseButton") - self.deadtime_browse_button.setText("Browse") - self.deadtime_browse_button.setToolTip("Browse for a .nxs file to load dead times from. If valid, the " - "dead times will be saved as a table, and automatically selected " - "as the dead time for the current data.") + self.dead_time_browse_button = QtWidgets.QPushButton(self) + self.dead_time_browse_button.setText("Browse") + self.dead_time_browse_button.setToolTip("Browse for a .nxs file to load dead times from. If valid, the " + "dead times will be saved as a table, and automatically selected " + "as the dead time for the current data.") - self.horizontal_layout_4 = QtWidgets.QHBoxLayout() - self.horizontal_layout_4.setObjectName("horizontalLayout3") - self.horizontal_layout_4.addSpacing(10) - self.horizontal_layout_4.addWidget(self.deadtime_label_3) + self.dead_time_layout = QtWidgets.QHBoxLayout() + self.dead_time_layout.addSpacing(10) + self.dead_time_layout.addWidget(self.dead_time_label_3) self.dead_time_file_layout = QtWidgets.QHBoxLayout() - self.dead_time_file_layout.addWidget(self.deadtime_browse_button) + self.dead_time_file_layout.addWidget(self.dead_time_browse_button) self.dead_time_file_layout.addStretch(0) self.dead_time_other_file_label = QtWidgets.QLabel(self) self.dead_time_other_file_label.setText("From other file : ") - self.layout.addWidget(self.deadtime_label, 3, 0) - self.layout.addWidget(self.deadtime_selector, 3, 1) - self.layout.addItem(self.horizontal_layout_4, 3, 2) - self.layout.addWidget(self.deadtime_label_2, 4, 0) - self.layout.addWidget(self.deadtime_file_selector, 4, 1) - self.layout.addWidget(self.dead_time_other_file_label, 5, 0) - self.layout.addWidget(self.deadtime_browse_button, 5, 1) + self.layout.addWidget(self.dead_time_label, 4, 0) + self.layout.addWidget(self.dead_time_selector, 4, 1) + self.layout.addItem(self.dead_time_layout, 4, 2) + self.layout.addWidget(self.dead_time_label_2, 5, 0) + self.layout.addWidget(self.dead_time_file_selector, 5, 1) + self.layout.addWidget(self.dead_time_other_file_label, 6, 0) + self.layout.addWidget(self.dead_time_browse_button, 6, 1) def on_dead_time_file_option_changed(self, slot): self._on_dead_time_file_option_selected = slot @@ -395,63 +442,63 @@ class InstrumentWidgetView(QtWidgets.QWidget): self._on_dead_time_unselected = slot def on_dead_time_browse_clicked(self, slot): - self.deadtime_browse_button.clicked.connect(slot) + self.dead_time_browse_button.clicked.connect(slot) def on_dead_time_from_file_selected(self, slot): self._on_dead_time_from_file_selected = slot def populate_dead_time_combo(self, names): - self.deadtime_file_selector.blockSignals(True) - self.deadtime_file_selector.clear() - self.deadtime_file_selector.addItem("None") + self.dead_time_file_selector.blockSignals(True) + self.dead_time_file_selector.clear() + self.dead_time_file_selector.addItem("None") for name in names: - self.deadtime_file_selector.addItem(name) - self.deadtime_file_selector.blockSignals(False) + self.dead_time_file_selector.addItem(name) + self.dead_time_file_selector.blockSignals(False) def get_dead_time_file_selection(self): - return self.deadtime_file_selector.currentText() + return self.dead_time_file_selector.currentText() def set_dead_time_file_selection_text(self, text): - index = self.deadtime_file_selector.findText(text) + index = self.dead_time_file_selector.findText(text) if index >= 0: - self.deadtime_file_selector.setCurrentIndex(index) + self.dead_time_file_selector.setCurrentIndex(index) return True return False def set_dead_time_file_selection(self, index): - self.deadtime_file_selector.setCurrentIndex(index) + self.dead_time_file_selector.setCurrentIndex(index) def set_dead_time_selection(self, index): - self.deadtime_selector.setCurrentIndex(index) + self.dead_time_selector.setCurrentIndex(index) def dead_time_file_loader_hidden(self, hidden=True): if hidden: - self.deadtime_file_selector.hide() + self.dead_time_file_selector.hide() - self.deadtime_label_2.hide() + self.dead_time_label_2.hide() self.dead_time_data_info_hidden(hidden) if not hidden: - self.deadtime_file_selector.setVisible(True) - self.deadtime_label_2.setVisible(True) + self.dead_time_file_selector.setVisible(True) + self.dead_time_label_2.setVisible(True) self.dead_time_data_info_hidden(hidden) def dead_time_other_file_hidden(self, hidden): if hidden: self.dead_time_other_file_label.hide() - self.deadtime_browse_button.hide() + self.dead_time_browse_button.hide() if not hidden: - self.deadtime_browse_button.setVisible(True) + self.dead_time_browse_button.setVisible(True) self.dead_time_other_file_label.setVisible(True) def dead_time_data_info_hidden(self, hidden=True): if hidden: - self.deadtime_label_3.hide() + self.dead_time_label_3.hide() if not hidden: - self.deadtime_label_3.setVisible(True) + self.dead_time_label_3.setVisible(True) def set_dead_time_label(self, text): - self.deadtime_label_3.setText(text) + self.dead_time_label_3.setText(text) def on_dead_time_combo_changed(self, index): if index == 0: @@ -487,11 +534,9 @@ class InstrumentWidgetView(QtWidgets.QWidget): def setup_rebin_row(self): self.rebin_label = QtWidgets.QLabel(self) - self.rebin_label.setObjectName("rebinLabel") self.rebin_label.setText("Rebin : ") self.rebin_selector = QtWidgets.QComboBox(self) - self.rebin_selector.setObjectName("rebinSelector") self.rebin_selector.addItems(["None", "Fixed", "Variable"]) self.rebin_steps_label = QtWidgets.QLabel(self) @@ -517,19 +562,18 @@ class InstrumentWidgetView(QtWidgets.QWidget): QtCore.QRegExp('^(\s*-?\d+(\.\d+)?)(\s*,\s*-?\d+(\.\d+)?)*$')) self.rebin_variable_edit.setValidator(variable_validator) - self.horizontal_layout_5 = QtWidgets.QHBoxLayout() - self.horizontal_layout_5.setObjectName("horizontalLayout3") - self.horizontal_layout_5.addSpacing(10) + self.rebin_layout = QtWidgets.QHBoxLayout() + self.rebin_layout.addSpacing(10) - self.horizontal_layout_5.addWidget(self.rebin_label) - self.horizontal_layout_5.addWidget(self.rebin_selector) + self.rebin_layout.addWidget(self.rebin_label) + self.rebin_layout.addWidget(self.rebin_selector) - self.horizontal_layout_5.addWidget(self.rebin_steps_label) - self.horizontal_layout_5.addWidget(self.rebin_steps_edit) - self.horizontal_layout_5.addWidget(self.rebin_variable_label) - self.horizontal_layout_5.addWidget(self.rebin_variable_edit) - self.horizontal_layout_5.addStretch(0) - self.horizontal_layout_5.addSpacing(10) + self.rebin_layout.addWidget(self.rebin_steps_label) + self.rebin_layout.addWidget(self.rebin_steps_edit) + self.rebin_layout.addWidget(self.rebin_variable_label) + self.rebin_layout.addWidget(self.rebin_variable_edit) + self.rebin_layout.addStretch(0) + self.rebin_layout.addSpacing(10) self.rebin_steps_label.hide() self.rebin_steps_edit.hide() diff --git a/scripts/Muon/GUI/Common/observer_pattern.py b/scripts/Muon/GUI/Common/observer_pattern.py index 3b68cb09aca073275b9f4f30e38afc608a97f3b5..663ec3fa9806e919d63ee57ac117a5951b5b0866 100644 --- a/scripts/Muon/GUI/Common/observer_pattern.py +++ b/scripts/Muon/GUI/Common/observer_pattern.py @@ -51,3 +51,12 @@ class Observable(object): def notify_subscribers(self, arg=None, **kwargs): for observer in self._subscribers: observer.update(self, arg, **kwargs) + + +class GenericObserver(Observer): + def __init__(self, callback): + Observer.__init__(self) + self.callback = callback + + def update(self, observable, arg): + self.callback() diff --git a/scripts/Muon/GUI/Common/phase_table_widget/muon_phases_tab.ui b/scripts/Muon/GUI/Common/phase_table_widget/muon_phases_tab.ui index 3dfb46e85bda94ebf701e8211ae735b62faeac6b..81d54cce6ca4fc425a5eab09588084f14619154b 100644 --- a/scripts/Muon/GUI/Common/phase_table_widget/muon_phases_tab.ui +++ b/scripts/Muon/GUI/Common/phase_table_widget/muon_phases_tab.ui @@ -16,6 +16,9 @@ <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0" colspan="2"> <widget class="QTableWidget" name="phase_table_options_table"> + <property name="rowCount"> + <number>6</number> + </property> <attribute name="horizontalHeaderStretchLastSection"> <bool>true</bool> </attribute> @@ -47,6 +50,11 @@ <string>Last Good Data</string> </property> </row> + <row> + <property name="text"> + <string>Output fit information</string> + </property> + </row> <column> <property name="text"> <string>Property</string> diff --git a/scripts/Muon/GUI/Common/phase_table_widget/phase_table_presenter.py b/scripts/Muon/GUI/Common/phase_table_widget/phase_table_presenter.py index b418fd5d4a48c079d4b1ad552c7a598b692d18c5..c45687a92455ba98ca29e0efcd0519179be0bab9 100644 --- a/scripts/Muon/GUI/Common/phase_table_widget/phase_table_presenter.py +++ b/scripts/Muon/GUI/Common/phase_table_widget/phase_table_presenter.py @@ -2,8 +2,11 @@ from Muon.GUI.Common.thread_model_wrapper import ThreadModelWrapper from Muon.GUI.Common import thread_model from Muon.GUI.Common.utilities.algorithm_utils import run_CalMuonDetectorPhases, run_PhaseQuad from Muon.GUI.Common.observer_pattern import Observer, Observable -from mantid.api import AnalysisDataService import re +from Muon.GUI.Common.ADSHandler.workspace_naming import get_phase_table_workspace_name, \ + get_phase_table_workspace_group_name, \ + get_phase_quad_workspace_name, get_fitting_workspace_name, get_base_data_directory +from Muon.GUI.Common.ADSHandler.muon_workspace_wrapper import MuonWorkspaceWrapper import mantid @@ -27,6 +30,7 @@ class PhaseTablePresenter(object): self.instrument_changed_observer = GenericObserver(self.update_current_phase_tables) self.phase_table_calculation_complete_notifier = Observable() + self.phase_quad_calculation_complete_nofifier = Observable() self.update_current_phase_tables() @@ -47,7 +51,8 @@ class PhaseTablePresenter(object): self.calculation_thread = self.create_calculation_thread() - self.calculation_thread.threadWrapperSetUp(self.handle_phase_table_calculation_started, self.handle_calculation_success, + self.calculation_thread.threadWrapperSetUp(self.handle_phase_table_calculation_started, + self.handle_calculation_success, self.handle_calculation_error) self.calculation_thread.start() @@ -61,7 +66,8 @@ class PhaseTablePresenter(object): self.phasequad_calculation_thread = self.create_phase_quad_calculation_thread() - self.phasequad_calculation_thread.threadWrapperSetUp(self.handle_calculation_started, self.handle_calculation_success, + self.phasequad_calculation_thread.threadWrapperSetUp(self.handle_calculation_started, + self.handle_calculation_success, self.handle_calculation_error) self.phasequad_calculation_thread.start() @@ -77,7 +83,7 @@ class PhaseTablePresenter(object): phase_quad = run_PhaseQuad(parameters, self.current_alg) self.current_alg = None - self.add_phase_quad_to_ADS(parameters, phase_quad) + self.add_phase_quad_to_ADS(parameters['InputWorkspace'], parameters['PhaseTable'], phase_quad) def get_parameters_for_phase_quad(self): parameters = {} @@ -90,14 +96,18 @@ class PhaseTablePresenter(object): return parameters - def add_phase_quad_to_ADS(self, parameters, phase_quad): - phase_quad_name = parameters['InputWorkspace'].split('_')[0] + '_PhaseQuad_phase_table_'\ - + parameters['PhaseTable'].split('_')[0] + def add_phase_quad_to_ADS(self, input_workspace, input_phase_table, phase_quad): + run = re.search('[0-9]+', input_workspace).group() + phasequad_workspace_name = get_phase_quad_workspace_name(input_workspace, input_phase_table) + phase_table_group = get_phase_table_workspace_group_name(phasequad_workspace_name, + self.context.data_context.instrument) + directory = get_base_data_directory(self.context, run) + phase_table_group - AnalysisDataService.addOrReplace(phase_quad_name, phase_quad) + muon_workspace_wrapper = MuonWorkspaceWrapper(phase_quad, directory + phasequad_workspace_name) + muon_workspace_wrapper.show() - run = re.search('[0-9]+', parameters['InputWorkspace']).group() - AnalysisDataService.addToGroup(self.context.data_context._base_run_name(run), phase_quad_name) + self.context.phase_context.add_phase_quad(muon_workspace_wrapper) + self.phase_quad_calculation_complete_nofifier.notify_subscribers() def handle_calculation_started(self): self.view.disable_widget() @@ -114,6 +124,7 @@ class PhaseTablePresenter(object): self.current_alg = None def handle_calculation_success(self): + self.phase_table_calculation_complete_notifier.notify_subscribers() self.update_current_phase_tables() self.view.enable_widget() self.view.disable_cancel() @@ -123,18 +134,37 @@ class PhaseTablePresenter(object): parameters = self.create_parameters_for_cal_muon_phase_algorithm() self.current_alg = mantid.AlgorithmManager.create("CalMuonDetectorPhases") - detector_table = run_CalMuonDetectorPhases(parameters, self.current_alg) + detector_table, fitting_information = run_CalMuonDetectorPhases(parameters, self.current_alg) self.current_alg = None - self.add_phase_table_to_ADS(parameters, detector_table) + self.add_phase_table_to_ADS(parameters['DetectorTable'], detector_table) + self.add_fitting_info_to_ADS_if_required(parameters['DetectorTable'], fitting_information) return parameters['DetectorTable'] - def add_phase_table_to_ADS(self, parameters, detector_table): - AnalysisDataService.addOrReplace(parameters['DetectorTable'], detector_table) - run = re.search('[0-9]+', parameters['DetectorTable']).group() - AnalysisDataService.addToGroup(self.context.data_context._base_run_name(run), parameters['DetectorTable']) - self.context.phase_context.add_phase_table(parameters['DetectorTable']) + def add_phase_table_to_ADS(self, base_name, detector_table): + run = re.search('[0-9]+', base_name).group() + + phase_table_group = get_phase_table_workspace_group_name(base_name, + self.context.data_context.instrument) + directory = get_base_data_directory(self.context, run) + phase_table_group + muon_workspace_wrapper = MuonWorkspaceWrapper(detector_table, directory + base_name) + muon_workspace_wrapper.show() + + self.context.phase_context.add_phase_table(muon_workspace_wrapper) + + def add_fitting_info_to_ADS_if_required(self, base_name, fitting_information): + if not self.view.output_fit_information: + return + + run = re.search('[0-9]+', base_name).group() + phase_table_group = get_phase_table_workspace_group_name(base_name, + self.context.data_context.instrument) + fitting_workspace_name = get_fitting_workspace_name(base_name) + directory = get_base_data_directory(self.context, run) + phase_table_group + + muon_workspace_wrapper = MuonWorkspaceWrapper(fitting_information, directory + fitting_workspace_name) + muon_workspace_wrapper.show() def create_parameters_for_cal_muon_phase_algorithm(self): parameters = {} @@ -150,7 +180,10 @@ class PhaseTablePresenter(object): backward_group = self.context.phase_context.options_dict['backward_group'] parameters['BackwardSpectra'] = self.context.group_pair_context[backward_group].detectors - parameters['DetectorTable'] = parameters['InputWorkspace'].replace('_raw_data', '') + "_phase_table" + parameters['DetectorTable'] = parameters['InputWorkspace'].replace('_raw_data', '') + "; PhaseTable" + + parameters['DetectorTable'] = get_phase_table_workspace_name(parameters['InputWorkspace'], forward_group, + backward_group) return parameters diff --git a/scripts/Muon/GUI/Common/phase_table_widget/phase_table_view.py b/scripts/Muon/GUI/Common/phase_table_widget/phase_table_view.py index 6df0ec0d0b50428d90d88da06e31a765e30b159c..9a5dfeead9368be66523cd2aa71d2cd944894893 100644 --- a/scripts/Muon/GUI/Common/phase_table_widget/phase_table_view.py +++ b/scripts/Muon/GUI/Common/phase_table_widget/phase_table_view.py @@ -6,7 +6,7 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) -from qtpy import QtWidgets +from qtpy import QtWidgets, QtCore from Muon.GUI.Common.utilities import table_utils from Muon.GUI.Common.message_box import warning from mantidqt.utils.qt import load_ui @@ -91,6 +91,10 @@ class PhaseTableView(QtWidgets.QWidget, ui_muon_phases_tab): if index != -1: self.phase_quad_phase_table_combo.setCurrentIndex(index) + @property + def output_fit_information(self): + return self.output_fit_info_box.checkState() == QtCore.Qt.Checked + def set_input_combo_box(self, input_list): self.input_workspace_combo_box.clear() self.input_workspace_combo_box.addItems(input_list) @@ -190,6 +194,10 @@ class PhaseTableView(QtWidgets.QWidget, ui_muon_phases_tab): table_utils.setRowName(self.phase_table_options_table, 4, "Last Good Data") self.last_good_data_item = table_utils.addDoubleToTable(self.phase_table_options_table, 15.0, 4) + table_utils.setRowName(self.phase_table_options_table, 5, "Output fit information") + self.output_fit_info_box = table_utils.addCheckBoxToTable( + self.phase_table_options_table, False, 5) + self.phase_table_options_table.resizeRowsToContents() table_utils.setTableHeaders(self.phase_table_options_table) diff --git a/scripts/Muon/GUI/Common/test_helpers/general_test_helpers.py b/scripts/Muon/GUI/Common/test_helpers/general_test_helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..6d690120fda9d216efe83ffde7abd97e6eac0828 --- /dev/null +++ b/scripts/Muon/GUI/Common/test_helpers/general_test_helpers.py @@ -0,0 +1,7 @@ +from mantid.simpleapi import CreateWorkspace +from Muon.GUI.Common.ADSHandler.muon_workspace_wrapper import MuonWorkspaceWrapper + + +def create_workspace_wrapper_stub_object(name): + workspace = CreateWorkspace([0], [0]) + return MuonWorkspaceWrapper(workspace, name) diff --git a/scripts/Muon/GUI/Common/utilities/algorithm_utils.py b/scripts/Muon/GUI/Common/utilities/algorithm_utils.py index ddd127ddab1d89daa0dabdef27c2e3f81b8bd883..984fbd5affe4bbc2cc01706f0e4598ba3798c546 100644 --- a/scripts/Muon/GUI/Common/utilities/algorithm_utils.py +++ b/scripts/Muon/GUI/Common/utilities/algorithm_utils.py @@ -81,7 +81,7 @@ def run_CalMuonDetectorPhases(parameter_dict, alg): alg.setProperty("DataFitted", "__NotUsed") alg.setProperties(parameter_dict) alg.execute() - return alg.getProperty("DetectorTable").value + return alg.getProperty("DetectorTable").value, alg.getProperty('DataFitted').value def run_PhaseQuad(parameters_dict, alg): @@ -94,6 +94,42 @@ def run_PhaseQuad(parameters_dict, alg): return alg.getProperty("OutputWorkspace").value +def run_PaddingAndApodization(parameters_dict): + alg = mantid.AlgorithmManager.create("PaddingAndApodization") + alg.initialize() + alg.setAlwaysStoreInADS(False) + alg.setRethrows(True) + alg.setProperty("OutputWorkspace", "__NotUsed") + alg.setProperties(parameters_dict) + alg.execute() + return alg.getProperty("OutputWorkspace").value + + +def run_FFT(parameters_dict): + alg = mantid.AlgorithmManager.create("FFT") + alg.initialize() + alg.setAlwaysStoreInADS(False) + alg.setRethrows(True) + alg.setProperty("OutputWorkspace", "__NotUsed") + alg.setProperties(parameters_dict) + alg.execute() + return alg.getProperty("OutputWorkspace").value + + +def run_MuonMaxent(parameters_dict, alg): + alg.initialize() + alg.setAlwaysStoreInADS(False) + alg.setRethrows(True) + alg.setProperty("OutputWorkspace", "__NotUsed") + alg.setProperty("OutputPhaseTable", "__NotUsedPhase") + alg.setProperty("OutputDeadTimeTable", "__NotUsedDead") + alg.setProperty("ReconstructedSpectra", "__NotUsedRecon") + alg.setProperty("PhaseConvergenceTable", "__NotUsedConverge") + alg.setProperties(parameters_dict) + alg.execute() + return alg.getProperty("OutputWorkspace").value + + def run_AppendSpectra(ws1, ws2): """ Apply the AppendSpectra algorithm to two given workspaces (no checks made). diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_presenter_new.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_presenter_new.py index 80e4a79039724a330d74b5b15953585230e28797..fb7456b50248fa821b0e957a2313e642ccdca353 100644 --- a/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_presenter_new.py +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_presenter_new.py @@ -6,14 +6,18 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) - import mantid.simpleapi as mantid from Muon.GUI.Common import thread_model +from Muon.GUI.Common.utilities.algorithm_utils import run_PaddingAndApodization, run_FFT +from Muon.GUI.Common.thread_model_wrapper import ThreadModelWrapper +from Muon.GUI.Common.ADSHandler.workspace_naming import get_fft_workspace_name, get_fft_workspace_group_name, \ + get_base_data_directory +import re +from Muon.GUI.Common.ADSHandler.muon_workspace_wrapper import MuonWorkspaceWrapper class FFTPresenter(object): - """ This class links the FFT model to the GUI """ @@ -52,17 +56,17 @@ class FFTPresenter(object): self.view.deactivateButton() def getWorkspaceNames(self): - name = self.view.getInputWS() - final_options = self.load.get_workspace_names_for_FFT_analysis(self.view.isRaw()) + name = self.view.workspace + final_options = self.load.get_workspace_names_for_FFT_analysis(self.view.use_raw_data) self.view.addItems(final_options) self.view.removeRe('PhaseQuad') self.removePhaseFromIM(final_options) - self.view.setReTo(name) + self.view.workspace = name def handle_use_raw_data_changed(self): - if not self.view.isRaw() and not self.load._do_rebin(): + if not self.view.use_raw_data and not self.load._do_rebin(): self.view.set_raw_checkbox_state(True) self.view.warning_popup('No rebin options specified') return @@ -82,7 +86,7 @@ class FFTPresenter(object): self.view.setPhaseBox() def tableClicked(self, row, col): - if row == self.view.getImBoxRow() and col == 1 and "PhaseQuad" not in self.view.getWS(): + if row == self.view.getImBoxRow() and col == 1 and "PhaseQuad" not in self.view.workspace: self.view.changedHideUnTick( self.view.getImBox(), self.view.getImBoxRow() + 1) @@ -92,7 +96,8 @@ class FFTPresenter(object): self.view.getShiftBoxRow() + 1) def createThread(self): - return thread_model.ThreadModel(self.alg) + self._phasequad_calculation_model = ThreadModelWrapper(self.calculate_FFT) + return thread_model.ThreadModel(self._phasequad_calculation_model) # constructs the inputs for the FFT algorithms # then executes them (see fft_model to see the order @@ -100,112 +105,87 @@ class FFTPresenter(object): def handleButton(self): # put this on its own thread so not to freeze Mantid self.thread = self.createThread() - self.thread.threadWrapperSetUp(self.deactivate, self.handleFinished) - - inputs = self.create_algorithm_inputs() - - try: - self.thread.loadData(inputs) - self.thread.start() - self.view.setPhaseBox() - except Exception: - pass + self.thread.threadWrapperSetUp(self.deactivate, self.handleFinished, self.handle_error) - def create_algorithm_inputs(self): - # make some inputs - inputs = {} + self.thread.start() - inputs["Run"] = self.get_input_run() - # do apodization and padding to real data + def handle_error(self, error): + self.view.activateButton() + self.view.warning_popup(error) - inputs["preRe"] = self.get_pre_inputs() + def get_pre_inputs(self): + pre_inputs = self._get_generic_apodiazation_and_padding_inputs() + pre_inputs['InputWorkspace'] = self.view.workspace - if "PhaseQuad" in self.view.getWS(): - inputs['phaseTable'] = self.get_phase_table_inputs() + return pre_inputs - # do apodization and padding to complex data - if self.view.isComplex() and "PhaseQuad" not in self.view.getWS(): - inputs['preIm'] = self.get_imaginary_inputs() + def get_imaginary_inputs(self): + pre_inputs = self._get_generic_apodiazation_and_padding_inputs() - # do FFT to transformed data - inputs['FFT'] = self.get_fft_inputs() + pre_inputs['InputWorkspace'] = self.view.imaginary_workspace - return inputs + return pre_inputs - def get_input_run(self): - return self.getRun( - self.view.getInputWS().split(";", 1)[0].split("_", 1)[0]) + def _get_generic_apodiazation_and_padding_inputs(self): + pre_inputs = {} - def get_pre_inputs(self): - preInputs = self.view.initAdvanced() + pre_inputs['InputWorkspace'] = self.view.imaginary_workspace + pre_inputs["ApodizationFunction"] = self.view.apodization_function + pre_inputs["DecayConstant"] = self.view.decay_constant + pre_inputs["NegativePadding"] = self.view.negative_padding + pre_inputs["Padding"] = self.view.padding_value - if "PhaseQuad" in self.view.getWS(): - preInputs['InputWorkspace'] = "__phaseQuad__" - preInputs['OutputWorkspace'] = "__ReTmp__" - else: - preInputs['OutputWorkspace'] = "__ReTmp__" - preInputs["InputWorkspace"] = self.clean( - self.view.getInputWS()) + return pre_inputs - return preInputs + def get_fft_inputs(self, real_workspace, imaginary_workspace, imanginary=0): + FFTInputs = {} - def get_phase_table_inputs(self): - phaseTable = {} - phaseTable["newTable"] = self.view.isNewPhaseTable() - phaseTable["FirstGoodData"] = self.view.getFirstGoodData() - phaseTable["LastGoodData"] = self.view.getLastGoodData() - phaseTable["Instrument"] = self.load.data_context.instrument - phaseTable["InputWorkspace"] = self.clean( - self.view.getInputWS()) - phaseTable['MaskedDetectors'] = self.load.get_detectors_excluded_from_default_grouping_tables() + FFTInputs["AcceptXRoundingErrors"] = True + FFTInputs['Real'] = 0 + FFTInputs['InputWorkspace'] = real_workspace + FFTInputs['Transform'] = 'Forward' + FFTInputs['AutoShift'] = self.view.auto_shift - return phaseTable - - def get_imaginary_inputs(self): - ImPreInputs = self.view.initAdvanced() - ImPreInputs['OutputWorkspace'] = "__ImTmp__" - ImPreInputs["InputWorkspace"] = self.clean( - self.view.getInputImWS()) - - return ImPreInputs - - def get_fft_inputs(self): - FFTInputs = self.get_FFT_input() - if "PhaseQuad" in self.view.getWS(): - self.view.getFFTRePhase(FFTInputs) - if self.view.isComplex(): - self.view.getFFTImPhase(FFTInputs) - - FFTInputs["OutputWorkspace"] = self.getRun( - self.view.getInputWS()) + ";PhaseQuad;FFT" - else: - FFTInputs["OutputWorkspace"] = self.getRun( - self.view.getInputWS()) + ";FFT" + if self.view.imaginary_data: + FFTInputs['InputImagWorkspace'] = imaginary_workspace + FFTInputs['Imaginary'] = imanginary return FFTInputs # kills the thread at end of execution def handleFinished(self): self.activate() - self.thread.deleteLater() - self.thread = None - def get_FFT_input(self): - FFTInputs = self.view.initFFTInput( - self.clean(self.view.getInputWS())) + def calculate_FFT(self): + imaginary_workspace_index = 0 + real_workspace_padding_parameters = self.get_pre_inputs() + imaginary_workspace_padding_parameters = self.get_imaginary_inputs() + + real_workspace_input = run_PaddingAndApodization(real_workspace_padding_parameters) - if self.view.isAutoShift(): - FFTInputs["AutoShift"] = True + if self.view.imaginary_data: + if 'PhaseQuad' in self.view.workspace: + imaginary_workspace_input = real_workspace_input + imaginary_workspace_padding_parameters['InputWorkspace'] = real_workspace_padding_parameters['InputWorkspace'] + imaginary_workspace_index = 1 + else: + imaginary_workspace_input = run_PaddingAndApodization(imaginary_workspace_padding_parameters) else: - self.view.addFFTShift(FFTInputs) - if self.view.isComplex(): - self.view.addFFTComplex(FFTInputs) - return FFTInputs + imaginary_workspace_input = None + + fft_parameters = self.get_fft_inputs(real_workspace_input, imaginary_workspace_input, imaginary_workspace_index) + + frequency_domain_workspace = run_FFT(fft_parameters) + + self.add_fft_workspace_to_ADS(real_workspace_padding_parameters['InputWorkspace'], + imaginary_workspace_padding_parameters['InputWorkspace'], + frequency_domain_workspace) - def clean(self, name): - if "PhaseQuad" in name: - return self.getRun(name) - return name + def add_fft_workspace_to_ADS(self, input_workspace, imaginary_input_workspace, fft_workspace): + run = re.search('[0-9]+', input_workspace).group() + fft_workspace_name = get_fft_workspace_name(input_workspace, imaginary_input_workspace) + group = get_fft_workspace_group_name(fft_workspace_name, self.load.data_context.instrument) + directory = get_base_data_directory(self.load, run) + group - def getRun(self, name): - return name.split(" (PhaseQuad)", 1)[0] + muon_workspace_wrapper = MuonWorkspaceWrapper(fft_workspace, directory + fft_workspace_name) + muon_workspace_wrapper.show() diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_view_new.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_view_new.py new file mode 100644 index 0000000000000000000000000000000000000000..40d1dfe883fc149105995656dcda919011710b37 --- /dev/null +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_view_new.py @@ -0,0 +1,256 @@ +# Mantid Repository : https://github.com/mantidproject/mantid +# +# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +# NScD Oak Ridge National Laboratory, European Spallation Source +# & Institut Laue - Langevin +# SPDX - License - Identifier: GPL - 3.0 + +from __future__ import (absolute_import, division, print_function) + +from qtpy import QtWidgets, QtCore + +from Muon.GUI.Common.utilities import table_utils +from Muon.GUI.Common.message_box import warning + + +class FFTView(QtWidgets.QWidget): + + """ + creates the layout for the FFT GUI + """ + # signals + buttonSignal = QtCore.Signal() + tableClickSignal = QtCore.Signal(object, object) + phaseCheckSignal = QtCore.Signal() + + def __init__(self, parent=None): + super(FFTView, self).__init__(parent) + self.grid = QtWidgets.QGridLayout(self) + + # add splitter for resizing + splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical) + + # make table + self.FFTTable = QtWidgets.QTableWidget(self) + self.FFTTable.resize(800, 800) + self.FFTTable.setRowCount(6) + self.FFTTable.setColumnCount(2) + self.FFTTable.setColumnWidth(0, 300) + self.FFTTable.setColumnWidth(1, 300) + self.FFTTable.verticalHeader().setVisible(False) + self.FFTTable.horizontalHeader().setStretchLastSection(True) + self.FFTTable.setHorizontalHeaderLabels( + ("FFT Property;Value").split(";")) + # populate table + options = ['test'] + + table_utils.setRowName(self.FFTTable, 0, "Workspace") + self.ws = table_utils.addComboToTable(self.FFTTable, 0, options) + self.Im_box_row = 1 + table_utils.setRowName( + self.FFTTable, + self.Im_box_row, + "Imaginary Data") + self.Im_box = table_utils.addCheckBoxToTable( + self.FFTTable, True, self.Im_box_row) + + table_utils.setRowName(self.FFTTable, 2, "Imaginary Workspace") + self.Im_ws = table_utils.addComboToTable(self.FFTTable, 2, options) + + self.shift_box_row = 3 + table_utils.setRowName(self.FFTTable, self.shift_box_row, "Auto shift") + self.shift_box = table_utils.addCheckBoxToTable( + self.FFTTable, True, self.shift_box_row) + + table_utils.setRowName(self.FFTTable, 4, "Shift") + self.shift = table_utils.addDoubleToTable(self.FFTTable, 0.0, 4) + self.FFTTable.hideRow(4) + + table_utils.setRowName(self.FFTTable, 5, "Use Raw data") + self.Raw_box = table_utils.addCheckBoxToTable(self.FFTTable, True, 5) + + self.FFTTable.resizeRowsToContents() + # make advanced table options + self.advancedLabel = QtWidgets.QLabel("\n Advanced Options") + self.FFTTableA = QtWidgets.QTableWidget(self) + self.FFTTableA.resize(800, 800) + self.FFTTableA.setRowCount(4) + self.FFTTableA.setColumnCount(2) + self.FFTTableA.setColumnWidth(0, 300) + self.FFTTableA.setColumnWidth(1, 300) + self.FFTTableA.verticalHeader().setVisible(False) + self.FFTTableA.horizontalHeader().setStretchLastSection(True) + self.FFTTableA.setHorizontalHeaderLabels( + ("Advanced Property;Value").split(";")) + + table_utils.setRowName(self.FFTTableA, 0, "Apodization Function") + options = ["Lorentz", "Gaussian", "None"] + self.apodization = table_utils.addComboToTable( + self.FFTTableA, 0, options) + + table_utils.setRowName( + self.FFTTableA, + 1, + "Decay Constant (micro seconds)") + self.decay = table_utils.addDoubleToTable(self.FFTTableA, 4.4, 1) + + table_utils.setRowName(self.FFTTableA, 2, "Negative Padding") + self.negativePadding = table_utils.addCheckBoxToTable( + self.FFTTableA, True, 2) + + table_utils.setRowName(self.FFTTableA, 3, "Padding") + self.padding = table_utils.addSpinBoxToTable(self.FFTTableA, 1, 3) + self.FFTTableA.resizeRowsToContents() + + # make button + self.button = QtWidgets.QPushButton('Calculate FFT', self) + self.button.setStyleSheet("background-color:lightgrey") + # connects + self.FFTTable.cellClicked.connect(self.tableClick) + self.button.clicked.connect(self.buttonClick) + self.ws.currentIndexChanged.connect(self.phaseCheck) + # add to layout + self.FFTTable.setMinimumSize(40, 158) + self.FFTTableA.setMinimumSize(40, 127) + table_utils.setTableHeaders(self.FFTTable) + table_utils.setTableHeaders(self.FFTTableA) + + # add to layout + splitter.addWidget(self.FFTTable) + splitter.addWidget(self.advancedLabel) + splitter.addWidget(self.FFTTableA) + self.grid.addWidget(splitter) + self.grid.addWidget(self.button) + + def getLayout(self): + return self.grid + + def addItems(self, options): + self.ws.clear() + self.ws.addItems(options) + self.Im_ws.clear() + self.Im_ws.addItems(options) + self.phaseQuadChanged() + + def removeIm(self, pattern): + index = self.Im_ws.findText(pattern) + self.Im_ws.removeItem(index) + + def removeRe(self, pattern): + index = self.ws.findText(pattern) + self.ws.removeItem(index) + + # connect signals + def phaseCheck(self): + self.phaseCheckSignal.emit() + + def tableClick(self, row, col): + self.tableClickSignal.emit(row, col) + + def buttonClick(self): + self.buttonSignal.emit() + + # responses to commands + def activateButton(self): + self.button.setEnabled(True) + + def deactivateButton(self): + self.button.setEnabled(False) + + def setPhaseBox(self): + self.FFTTable.setRowHidden(8, "PhaseQuad" not in self.workspace) + + def changed(self, box, row): + self.FFTTable.setRowHidden(row, box.checkState() == QtCore.Qt.Checked) + + def changedHideUnTick(self, box, row): + self.FFTTable.setRowHidden(row, box.checkState() != QtCore.Qt.Checked) + + def phaseQuadChanged(self): + # hide complex ws + self.FFTTable.setRowHidden(2, "PhaseQuad" in self.workspace) + + def set_raw_checkbox_state(self, state): + if state: + self.Raw_box.setCheckState(QtCore.Qt.Checked) + else: + self.Raw_box.setCheckState(QtCore.Qt.Unchecked) + + def setup_raw_checkbox_changed(self, slot): + self.FFTTable.itemChanged.connect(self.raw_checkbox_changed) + self.signal_raw_option_changed = slot + + def raw_checkbox_changed(self, table_item): + if table_item == self.Raw_box: + self.signal_raw_option_changed() + + def getImBoxRow(self): + return self.Im_box_row + + def getShiftBoxRow(self): + return self.shift_box_row + + def getImBox(self): + return self.Im_box + + def getShiftBox(self): + return self.shift_box + + def warning_popup(self, message): + warning(message, parent=self) + + @property + def workspace(self): + return str(self.ws.currentText()) + + @workspace.setter + def workspace(self, name): + index = self.ws.findText(name) + if index == -1: + return + self.ws.setCurrentIndex(index) + + @property + def imaginary_workspace(self): + return str(self.Im_ws.currentText()) + + @imaginary_workspace.setter + def imaginary_workspace(self, name): + index = self.Im_ws.findText(name) + if index == -1: + return + self.Im_ws.setCurrentIndex(index) + + @property + def imaginary_data(self): + return self.Im_box.checkState() == QtCore.Qt.Checked + + @imaginary_data.setter + def imaginary_data(self, value): + if value: + self.Im_box.setCheckState(QtCore.Qt.Checked) + else: + self.Im_box.setCheckState(QtCore.Qt.Unchecked) + + @property + def auto_shift(self): + return self.shift_box.checkState() == QtCore.Qt.Checked + + @property + def use_raw_data(self): + return self.Raw_box.checkState() == QtCore.Qt.Checked + + @property + def apodization_function(self): + return str(self.apodization.currentText()) + + @property + def decay_constant(self): + return float(self.decay.text()) + + @property + def negative_padding(self): + return self.negativePadding.checkState() == QtCore.Qt.Checked + + @property + def padding_value(self): + return int(self.padding.text()) diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_widget_new.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_widget_new.py index e55e21ca773bb4352f31eae13dd1debb7afc32e5..b7eec18b60be66f4a2d90686e062d2dac90c68a4 100644 --- a/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_widget_new.py +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/FFT/fft_widget_new.py @@ -6,7 +6,7 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) -from Muon.GUI.FrequencyDomainAnalysis.FFT.fft_view import FFTView +from Muon.GUI.FrequencyDomainAnalysis.FFT.fft_view_new import FFTView from Muon.GUI.FrequencyDomainAnalysis.FFT.fft_presenter_new import FFTPresenter from Muon.GUI.FrequencyDomainAnalysis.FFT.fft_model import FFTModel, FFTWrapper diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_presenter_new.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_presenter_new.py index e7ad390f5d455ab0c3495857560a79a477549add..ace44bb15123c35ecfe3d8456828fed571619812 100644 --- a/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_presenter_new.py +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_presenter_new.py @@ -6,13 +6,25 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) - +import functools import math -from Muon.GUI.Common import thread_model +import re + import mantid.simpleapi as mantid +from Muon.GUI.Common import thread_model +from Muon.GUI.Common.ADSHandler.muon_workspace_wrapper import MuonWorkspaceWrapper +from Muon.GUI.Common.ADSHandler.workspace_naming import get_maxent_workspace_group_name, get_maxent_workspace_name, \ + get_base_data_directory +from Muon.GUI.Common.observer_pattern import GenericObserver +from Muon.GUI.Common.thread_model_wrapper import ThreadModelWrapper +from Muon.GUI.Common.utilities.algorithm_utils import run_MuonMaxent + raw_data = "_raw_data" +optional_output_suffixes = {'OutputPhaseTable': '_phase_table', 'OutputDeadTimeTable': '_dead_times', + 'ReconstructedSpectra': '_reconstructed_spectra', 'PhaseConvergenceTable': '_phase_convergence'} + class MaxEntPresenter(object): @@ -20,9 +32,8 @@ class MaxEntPresenter(object): This class links the MaxEnt model to the GUI """ - def __init__(self, view, alg, load): + def __init__(self, view, load): self.view = view - self.alg = alg self.load = load self.thread = None # set data @@ -30,7 +41,8 @@ class MaxEntPresenter(object): # connect self.view.maxEntButtonSignal.connect(self.handleMaxEntButton) self.view.cancelSignal.connect(self.cancel) - self.view.phaseSignal.connect(self.handlePhase) + + self.phase_table_observer = GenericObserver(self.update_phase_table_options) @property def widget(self): @@ -41,17 +53,12 @@ class MaxEntPresenter(object): def clear(self): self.view.addItems([]) - self.view.clearPhaseTables() + self.view.update_phase_table_combo([]) # functions def getWorkspaceNames(self): final_options = self.load.getGroupedWorkspaceNames() - # run = self.load.getRunName() - - self.view.setRun("") - # if run is not "None": - # final_options.append(run) self.view.addItems(final_options) start = int( math.ceil(math.log(self.load.data_context.num_points) / math.log(2.0))) @@ -59,8 +66,8 @@ class MaxEntPresenter(object): self.view.addNPoints(values) def cancel(self): - if self.thread is not None: - self.thread.cancel() + if self.maxent_alg is not None: + self.maxent_alg.cancel() # turn on button def activate(self): @@ -70,12 +77,11 @@ class MaxEntPresenter(object): def deactivate(self): self.view.deactivateCalculateButton() - def handlePhase(self, row, col): - if col == 1 and row == 4: - self.view.changedPhaseBox() - def createThread(self): - return thread_model.ThreadModel(self.alg) + self.maxent_alg = mantid.AlgorithmManager.create("MuonMaxent") + calculation_function = functools.partial(self.calculate_maxent, self.maxent_alg) + self._maxent_calculation_model = ThreadModelWrapper(calculation_function) + return thread_model.ThreadModel(self._maxent_calculation_model) # constructs the inputs for the MaxEnt algorithms # then executes them (see maxent_model to see the order @@ -83,87 +89,90 @@ class MaxEntPresenter(object): def handleMaxEntButton(self): # put this on its own thread so not to freeze Mantid self.thread = self.createThread() - self.thread.threadWrapperSetUp(self.deactivate, self.handleFinished) + self.thread.threadWrapperSetUp(self.deactivate, self.handleFinished, self.handle_error) - # make some inputs - inputs = {} + self.thread.start() - if self.view.usePhases() and self.view.calcPhases(): - inputs["phaseTable"] = self.get_phase_table_inputs() + # kills the thread at end of execution + def handleFinished(self): + self.activate() - inputs["maxent"] = self.getMaxEntInput() + def handle_error(self, error): + self.activate() + self.view.warning_popup(error) - inputs["Run"] = self.get_input_run() + def calculate_maxent(self, alg): + maxent_parameters = self.get_parameters_for_maxent_calculation() - self.thread.loadData(inputs) - self.thread.start() + maxent_workspace = run_MuonMaxent(maxent_parameters, alg) - def get_phase_table_inputs(self): - phaseTable = {} - phaseTable["FirstGoodData"] = self.view.getFirstGoodData() - phaseTable["LastGoodData"] = self.view.getLastGoodData() - phaseTable["InputWorkspace"] = self.view.getInputWS() - phaseTable["DetectorTable"] = "PhaseTable" - phaseTable["DataFitted"] = "fits" + self.add_maxent_workspace_to_ADS(maxent_parameters['InputWorkspace'], maxent_workspace, alg) - return phaseTable + def get_parameters_for_maxent_calculation(self): + inputs = {} - def get_input_run(self): - return self.view.getInputWS().split("_", 1)[0] + inputs['InputWorkspace'] = self.view.input_workspace + run = [float(re.search('[0-9]+', inputs['InputWorkspace']).group())] - # kills the thread at end of execution - def handleFinished(self): - self.activate() - self.thread.deleteLater() - self.thread = None - self.updatePhaseOptions() + if self.view.phase_table != 'Construct': + inputs['InputPhaseTable'] = self.view.phase_table - def updatePhaseOptions(self): - inputs = {} - self.view.addOutputPhases(inputs) - name = inputs['OutputPhaseTable'] - name = name[1:] + if self.load.dead_time_table(run): + inputs['InputDeadTimeTable'] = self.load.dead_time_table(run) - current_list = self.view.getPhaseTableOptions() - if self.phaseTableAdded(name) and name not in current_list: - index = self.view.getPhaseTableIndex() - self.view.addPhaseTableToGUI(name) - self.view.setPhaseTableIndex(index) + inputs['FirstGoodTime'] = self.load.first_good_data(run) - def phaseTableAdded(self, name): - return mantid.AnalysisDataService.doesExist(name) + inputs['LastGoodTime'] = self.load.last_good_data(run) - def getMaxEntInput(self): - inputs = self.view.initMaxEntInput() + inputs['Npts'] = self.view.num_points - if self.view.outputPhases(): - self.view.addOutputPhases(inputs) + inputs['InnerIterations'] = self.view.inner_iterations - if self.view.outputDeadTime(): - self.view.addOutputDeadTime(inputs) + inputs['OuterIterations'] = self.view.outer_iterations - if self.view.outputPhaseEvo(): - self.view.addOutputPhaseEvo(inputs) + inputs['DoublePulse'] = self.view.double_pulse - if self.view.outputTime(): - self.view.addOutputTime(inputs) + inputs['Factor'] = self.view.lagrange_multiplier - # for new version 2 of FDA - self.cleanOutputsForVersion2(inputs) + inputs['MaxField'] = self.view.maximum_field - if self.view.usePhases(): - self.view.addPhaseTable(inputs) + inputs['DefaultLevel'] = self.view.maximum_entropy_constant + + inputs['FitDeadTime'] = self.view.fit_dead_times return inputs - def cleanOutputsForVersion2(self, inputs): - inputs["InputWorkspace"] = self.view.getInputWS() - keys = [ - "OutputWorkspace", - "OutputPhaseTable", - "OutputDeadTimeTable", - "PhaseConvergenceTable", - "ReconstructedSpectra"] - for output in keys: - if output in inputs: - inputs[output] = inputs[output][1:] + def update_phase_table_options(self): + phase_table_list = self.load.phase_context.get_phase_table_list(self.load.data_context.instrument) + phase_table_list.insert(0, 'Construct') + + self.view.update_phase_table_combo(phase_table_list) + + def add_maxent_workspace_to_ADS(self, input_workspace, maxent_workspace, alg): + run = re.search('[0-9]+', input_workspace).group() + base_name = get_maxent_workspace_name(input_workspace) + group = get_maxent_workspace_group_name(base_name, self.load.data_context.instrument) + directory = get_base_data_directory(self.load, run) + group + + muon_workspace_wrapper = MuonWorkspaceWrapper(maxent_workspace, directory + base_name) + muon_workspace_wrapper.show() + + maxent_output_options = self.get_maxent_output_options() + + self.add_optional_outputs_to_ADS(alg, maxent_output_options, base_name, directory) + + def get_maxent_output_options(self): + output_options = {} + + output_options['OutputPhaseTable'] = self.view.output_phase_table + output_options['OutputDeadTimeTable'] = self.view.output_dead_times + output_options['ReconstructedSpectra'] = self.view.output_reconstructed_spectra + output_options['PhaseConvergenceTable'] = self.view.output_phase_convergence + + return output_options + + def add_optional_outputs_to_ADS(self, alg, output_options, base_name, directory): + for key in output_options: + if output_options[key]: + output = alg.getProperty(key).value + MuonWorkspaceWrapper(output, directory + base_name + optional_output_suffixes[key]).show() diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_view_new.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_view_new.py new file mode 100644 index 0000000000000000000000000000000000000000..189d75d3060f056f5ffc7a5bd44e6f4fd42f2970 --- /dev/null +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_view_new.py @@ -0,0 +1,239 @@ +# Mantid Repository : https://github.com/mantidproject/mantid +# +# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +# NScD Oak Ridge National Laboratory, European Spallation Source +# & Institut Laue - Langevin +# SPDX - License - Identifier: GPL - 3.0 + +from __future__ import (absolute_import, division, print_function) + +from qtpy import QtWidgets, QtCore + +from Muon.GUI.Common.utilities import table_utils +from Muon.GUI.Common.message_box import warning + + +class MaxEntView(QtWidgets.QWidget): + + """ + The view for the MaxEnt widget. This + creates the look of the widget + """ + # signals + maxEntButtonSignal = QtCore.Signal() + cancelSignal = QtCore.Signal() + + def __init__(self, parent=None): + super(MaxEntView, self).__init__(parent) + self.grid = QtWidgets.QVBoxLayout(self) + + # add splitter for resizing + splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical) + + self.run = None + # make table + self.table = QtWidgets.QTableWidget(self) + self.table.resize(800, 800) + + self.table.setRowCount(7) + self.table.setColumnCount(2) + self.table.setColumnWidth(0, 300) + self.table.setColumnWidth(1, 300) + self.table.verticalHeader().setVisible(False) + self.table.horizontalHeader().setStretchLastSection(True) + self.table.setHorizontalHeaderLabels( + ("MaxEnt Property;Value").split(";")) + table_utils.setTableHeaders(self.table) + + # populate table + options = [] + + table_utils.setRowName(self.table, 0, "Workspace") + self.ws = table_utils.addComboToTable(self.table, 0, options) + + table_utils.setRowName(self.table, 1, "Phase Table") + self.phase_table_combo = table_utils.addComboToTable(self.table, 1, options) + + table_utils.setRowName(self.table, 2, "Fit dead times") + self.dead_box = table_utils.addCheckBoxToTable(self.table, True, 2) + + table_utils.setRowName(self.table, 3, "Output phase table") + self.output_phase_box = table_utils.addCheckBoxToTable( + self.table, False, 3) + + table_utils.setRowName(self.table, 4, "Output deadtimes") + self.output_dead_box = table_utils.addCheckBoxToTable( + self.table, False, 4) + + table_utils.setRowName(self.table, 5, "Output reconstructed data") + self.output_data_box = table_utils.addCheckBoxToTable( + self.table, False, 5) + + table_utils.setRowName(self.table, 6, "Output phase convergence") + self.output_phase_evo_box = table_utils.addCheckBoxToTable( + self.table, False, 6) + + self.table.resizeRowsToContents() + + # advanced options table + self.advancedLabel = QtWidgets.QLabel("\n Advanced Options") + # make table + self.tableA = QtWidgets.QTableWidget(self) + self.tableA.resize(800, 800) + + self.tableA.setRowCount(7) + self.tableA.setColumnCount(2) + self.tableA.setColumnWidth(0, 300) + self.tableA.setColumnWidth(1, 300) + + self.tableA.verticalHeader().setVisible(False) + self.tableA.horizontalHeader().setStretchLastSection(True) + + self.tableA.setHorizontalHeaderLabels( + ("Advanced Property;Value").split(";")) + table_utils.setTableHeaders(self.tableA) + + table_utils.setRowName(self.tableA, 0, "Maximum entropy constant (A)") + self.AConst = table_utils.addDoubleToTable(self.tableA, 0.1, 0) + + table_utils.setRowName(self.tableA, 1, "Lagrange multiplier for chi^2") + self.factor = table_utils.addDoubleToTable(self.tableA, 1.04, 1) + + table_utils.setRowName(self.tableA, 2, "Inner Iterations") + self.inner_loop = table_utils.addSpinBoxToTable(self.tableA, 10, 2) + + table_utils.setRowName(self.tableA, 3, "Outer Iterations") + self.outer_loop = table_utils.addSpinBoxToTable(self.tableA, 10, 3) + + table_utils.setRowName(self.tableA, 4, "Double pulse data") + self.double_pulse_box = table_utils.addCheckBoxToTable( + self.tableA, False, 4) + + table_utils.setRowName(self.tableA, 5, "Number of data points") + self.N_points = table_utils.addComboToTable(self.tableA, 5, options) + + table_utils.setRowName(self.tableA, 6, "Maximum Field ") + self.max_field = table_utils.addDoubleToTable(self.tableA, 1000.0, 6) + + # layout + # this is if complex data is unhidden + self.table.setMinimumSize(40, 203) + self.tableA.setMinimumSize(40, 207) + + # make buttons + self.button = QtWidgets.QPushButton('Calculate MaxEnt', self) + self.button.setStyleSheet("background-color:lightgrey") + self.cancel = QtWidgets.QPushButton('Cancel', self) + self.cancel.setStyleSheet("background-color:lightgrey") + self.cancel.setEnabled(False) + # connects + self.button.clicked.connect(self.MaxEntButtonClick) + self.cancel.clicked.connect(self.cancelClick) + # button layout + self.buttonLayout = QtWidgets.QHBoxLayout() + self.buttonLayout.addWidget(self.button) + self.buttonLayout.addWidget(self.cancel) + # add to layout + splitter.addWidget(self.table) + splitter.addWidget(self.advancedLabel) + splitter.addWidget(self.tableA) + self.grid.addWidget(splitter) + self.grid.addLayout(self.buttonLayout) + + def getLayout(self): + return self.grid + + # add data to view + def addItems(self, options): + self.ws.clear() + self.ws.addItems(options) + + def addNPoints(self, options): + self.N_points.clear() + self.N_points.addItems(options) + + # send signal + def MaxEntButtonClick(self): + self.maxEntButtonSignal.emit() + + def cancelClick(self): + self.cancelSignal.emit() + + def warning_popup(self, message): + warning(message, parent=self) + + def activateCalculateButton(self): + self.button.setEnabled(True) + self.cancel.setEnabled(False) + + def deactivateCalculateButton(self): + self.button.setEnabled(False) + self.cancel.setEnabled(True) + + def update_phase_table_combo(self, phase_table_list): + name = self.phase_table_combo.currentText() + + self.phase_table_combo.clear() + self.phase_table_combo.addItems(phase_table_list) + + index = self.phase_table_combo.findText(name) + + if index != -1: + self.phase_table_combo.setCurrentIndex(index) + else: + self.phase_table_combo.setCurrentIndex(0) + + @property + def input_workspace(self): + return str(self.ws.currentText()) + + @property + def num_points(self): + return int(self.N_points.currentText()) + + @property + def maximum_field(self): + return float(self.max_field.text()) + + @property + def fit_dead_times(self): + return self.dead_box.checkState() == QtCore.Qt.Checked + + @property + def double_pulse(self): + return self.double_pulse_box.checkState() == QtCore.Qt.Checked + + @property + def outer_iterations(self): + return int(self.outer_loop.text()) + + @property + def inner_iterations(self): + return int(self.inner_loop.text()) + + @property + def maximum_entropy_constant(self): + return float(self.AConst.text()) + + @property + def lagrange_multiplier(self): + return float(self.factor.text()) + + @property + def phase_table(self): + return str(self.phase_table_combo.currentText()) + + @property + def output_phase_table(self): + return self.output_phase_box.checkState() == QtCore.Qt.Checked + + @property + def output_dead_times(self): + return self.output_dead_box.checkState() == QtCore.Qt.Checked + + @property + def output_phase_convergence(self): + return self.output_phase_evo_box.checkState() == QtCore.Qt.Checked + + @property + def output_reconstructed_spectra(self): + return self.output_data_box.checkState() == QtCore.Qt.Checked diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_widget_new.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_widget_new.py index 8d7c48e0b1a14ae916f21a8c106091b226bbb9de..aa39647bb848941057e595c17ed8dc0a8e6660aa 100644 --- a/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_widget_new.py +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/MaxEnt/maxent_widget_new.py @@ -6,9 +6,8 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) -from Muon.GUI.FrequencyDomainAnalysis.MaxEnt.maxent_view import MaxEntView +from Muon.GUI.FrequencyDomainAnalysis.MaxEnt.maxent_view_new import MaxEntView from Muon.GUI.FrequencyDomainAnalysis.MaxEnt.maxent_presenter_new import MaxEntPresenter -from Muon.GUI.FrequencyDomainAnalysis.MaxEnt.maxent_model import MaxEntModel, MaxEntWrapper from PyQt4 import QtGui @@ -18,10 +17,7 @@ class MaxEntWidget(QtGui.QWidget): def __init__(self, load, parent=None): super(MaxEntWidget, self).__init__(parent) view = MaxEntView(parent) - - maxEnt = MaxEntModel() - model = MaxEntWrapper(maxEnt) - self._presenter = MaxEntPresenter(view, model, load) + self._presenter = MaxEntPresenter(view, load) @property def presenter(self): diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/Transform/transform_widget.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/Transform/transform_widget.py index ced93eeb178e3e1e09af80d07c0854e0fe40db68..bc3ab9fe64dcf6eaba9dbe840780e8b916fe97d7 100644 --- a/scripts/Muon/GUI/FrequencyDomainAnalysis/Transform/transform_widget.py +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/Transform/transform_widget.py @@ -26,6 +26,7 @@ class TransformWidget(QtWidgets.QWidget): self.GroupPairObserver = GroupPairObserver(self) self.enable_observer = EnableObserver(self) self.disable_observer = DisableObserver(self) + self.phase_quad_observer = PhaseQuadObserver(self) groupedViews = self.getViews() @@ -120,3 +121,12 @@ class DisableObserver(Observer): def update(self, observable, arg): self.outer.disable_view() + + +class PhaseQuadObserver(Observer): + def __init__(self, outer): + Observer.__init__(self) + self.outer = outer + + def update(self, observable, arg): + self.outer.handle_new_data_loaded() diff --git a/scripts/Muon/GUI/FrequencyDomainAnalysis/frequency_domain_analysis_2.py b/scripts/Muon/GUI/FrequencyDomainAnalysis/frequency_domain_analysis_2.py index d17efc1de0980371fde31dbae4422a0a37f5d438..2643b265d7d01cd338c6ce86c0dca43a089d8913 100644 --- a/scripts/Muon/GUI/FrequencyDomainAnalysis/frequency_domain_analysis_2.py +++ b/scripts/Muon/GUI/FrequencyDomainAnalysis/frequency_domain_analysis_2.py @@ -111,6 +111,10 @@ class FrequencyAnalysisGui(QtWidgets.QMainWindow): self.setup_on_load_disabler() + self.setup_phase_quad_changed_notifer() + + self.setup_phase_table_changed_notifier() + self.context.data_context.message_notifier.add_subscriber(self.grouping_tab_widget.group_tab_presenter.message_observer) def setup_tabs(self): @@ -204,6 +208,14 @@ class FrequencyAnalysisGui(QtWidgets.QMainWindow): self.load_widget.load_widget.load_run_widget.disable_notifier.add_subscriber( self.transform.disable_observer) + def setup_phase_quad_changed_notifer(self): + self.phase_tab.phase_table_presenter.phase_quad_calculation_complete_nofifier.add_subscriber( + self.transform.phase_quad_observer) + + def setup_phase_table_changed_notifier(self): + self.phase_tab.phase_table_presenter.phase_table_calculation_complete_notifier.add_subscriber( + self.transform._maxent._presenter.phase_table_observer) + def closeEvent(self, event): self.tabs.closeEvent(event) super(FrequencyAnalysisGui, self).closeEvent(event) diff --git a/scripts/test/Muon/CMakeLists.txt b/scripts/test/Muon/CMakeLists.txt index ea2b9e67719f97547234ec951d5d22510eefb9a1..578ee77fd280d8fdac1518facaa5d8bbc4af4f5e 100644 --- a/scripts/test/Muon/CMakeLists.txt +++ b/scripts/test/Muon/CMakeLists.txt @@ -3,7 +3,6 @@ set ( TEST_PY_FILES FFTModel_test.py FFTPresenter_test.py - fft_presenter_new_test.py fft_presenter_context_interaction_test.py home_grouping_widget_test.py home_instrument_widget_test.py diff --git a/scripts/test/Muon/fft_presenter_context_interaction_test.py b/scripts/test/Muon/fft_presenter_context_interaction_test.py index c0de688e99e810beb92fc80ebf1aa1e9c51be99b..3300dbaa501fa847459e5e7f0b9e81ee57d47265 100644 --- a/scripts/test/Muon/fft_presenter_context_interaction_test.py +++ b/scripts/test/Muon/fft_presenter_context_interaction_test.py @@ -14,9 +14,9 @@ from Muon.GUI.Common.muon_pair import MuonPair from Muon.GUI.Common.test_helpers import mock_widget from Muon.GUI.Common.test_helpers.context_setup import setup_context_for_tests from Muon.GUI.Common.utilities import load_utils -from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_model from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_presenter_new -from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_view +from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_view_new +from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_model from Muon.GUI.FrequencyDomainAnalysis.frequency_context import FrequencyContext @@ -40,7 +40,7 @@ class FFTPresenterTest(unittest.TestCase): self.gui_context.update({'RebinType': 'None'}) - self.view = fft_view.FFTView(self.obj) + self.view = fft_view_new.FFTView(self.obj) self.model1 = fft_model.FFTModel() self.model = fft_model.FFTWrapper @@ -63,7 +63,7 @@ class FFTPresenterTest(unittest.TestCase): self.presenter.getWorkspaceNames() self.assertEqual(retrieve_combobox_info(self.view.ws), - ['MUSR22725_raw_data (PhaseQuad)', 'MUSR22725; Pair Asym; test_pair; #1', + ['MUSR22725; Pair Asym; test_pair; #1', 'MUSR22725; Group; top; Asymmetry; #1', 'MUSR22725; Group; bkwd; Asymmetry; #1', 'MUSR22725; Group; bottom; Asymmetry; #1', 'MUSR22725; Group; fwd; Asymmetry; #1']) @@ -77,7 +77,7 @@ class FFTPresenterTest(unittest.TestCase): self.view.set_raw_checkbox_state(False) self.assertEqual(retrieve_combobox_info(self.view.ws), - ['MUSR22725_raw_data (PhaseQuad)', 'MUSR22725; Pair Asym; test_pair; #1', + ['MUSR22725; Pair Asym; test_pair; #1', 'MUSR22725; Group; top; Asymmetry; #1', 'MUSR22725; Group; bkwd; Asymmetry; #1', 'MUSR22725; Group; bottom; Asymmetry; #1', 'MUSR22725; Group; fwd; Asymmetry; #1']) @@ -94,9 +94,10 @@ class FFTPresenterTest(unittest.TestCase): self.view.set_raw_checkbox_state(False) self.assertEqual(retrieve_combobox_info(self.view.ws), - ['MUSR22725_raw_data (PhaseQuad)', 'MUSR22725; Pair Asym; test_pair; Rebin; #1', + ['MUSR22725; Pair Asym; test_pair; Rebin; #1', 'MUSR22725; Group; top; Asymmetry; Rebin; #1', 'MUSR22725; Group; bkwd; Asymmetry; Rebin; #1', - 'MUSR22725; Group; bottom; Asymmetry; Rebin; #1', 'MUSR22725; Group; fwd; Asymmetry; Rebin; #1']) + 'MUSR22725; Group; bottom; Asymmetry; Rebin; #1', + 'MUSR22725; Group; fwd; Asymmetry; Rebin; #1']) self.assertEqual(retrieve_combobox_info(self.view.Im_ws), ['MUSR22725; Pair Asym; test_pair; Rebin; #1', 'MUSR22725; Group; top; Asymmetry; Rebin; #1', @@ -105,50 +106,101 @@ class FFTPresenterTest(unittest.TestCase): 'MUSR22725; Group; fwd; Asymmetry; Rebin; #1']) def test_get_pre_inputs_with_phase_quad(self): + workspace_wrapper = mock.MagicMock() + workspace_wrapper.workspace_name = 'MUSR22725_PhaseQuad_MUSR22725_phase_table' + self.context.phase_context.add_phase_quad(workspace_wrapper) self.presenter.getWorkspaceNames() self.assertEquals(self.presenter.get_pre_inputs(), {'ApodizationFunction': 'Lorentz', 'DecayConstant': 4.4, - 'InputWorkspace': '__phaseQuad__', 'NegativePadding': 2, - 'OutputWorkspace': '__ReTmp__', 'Padding': 1}) + 'InputWorkspace': 'MUSR22725_PhaseQuad_MUSR22725_phase_table', + 'NegativePadding': True, 'Padding': 1}) - def test_pre_inputs_without_phasequad(self): + def test_pre_inputs(self): self.presenter.getWorkspaceNames() self.view.ws.setCurrentIndex(1) self.assertEquals(self.presenter.get_pre_inputs(), {'ApodizationFunction': 'Lorentz', 'DecayConstant': 4.4, - 'InputWorkspace': u'MUSR22725; Pair Asym; test_pair; #1', - 'NegativePadding': 2, - 'OutputWorkspace': '__ReTmp__', 'Padding': 1}) + 'InputWorkspace': 'MUSR22725; Group; top; Asymmetry; #1', + 'NegativePadding': True, 'Padding': 1}) def test_get_imaginary_pre_inputs(self): self.presenter.getWorkspaceNames() self.assertEquals(self.presenter.get_imaginary_inputs(), {'ApodizationFunction': 'Lorentz', 'DecayConstant': 4.4, - 'InputWorkspace': u'MUSR22725; Pair Asym; test_pair; #1', - 'NegativePadding': 2, - 'OutputWorkspace': '__ImTmp__', 'Padding': 1}) + 'InputWorkspace': 'MUSR22725; Pair Asym; test_pair; #1', + 'NegativePadding': True, 'Padding': 1}) + + def test_get_fft_inputs_with_phase_quad_no_imag(self): + workspace_wrapper = mock.MagicMock() + workspace_wrapper.workspace_name = 'MUSR22725_PhaseQuad_MUSR22725_phase_table' + self.context.phase_context.add_phase_quad(workspace_wrapper) + self.presenter.getWorkspaceNames() + self.view.imaginary_data = False + + self.assertEquals( + self.presenter.get_fft_inputs(workspace_wrapper.workspace_name, workspace_wrapper.workspace_name), + {'AcceptXRoundingErrors': True, 'AutoShift': True, + 'InputWorkspace': workspace_wrapper.workspace_name, + 'Real': 0, 'Transform': 'Forward'}) def test_get_fft_inputs_with_phase_quad(self): + workspace_wrapper = mock.MagicMock() + phase_name = 'MUSR22725_PhaseQuad_MUSR22725_phase_table' + workspace_wrapper.workspace_name = phase_name + self.context.phase_context.add_phase_quad(workspace_wrapper) self.presenter.getWorkspaceNames() - self.assertEquals(self.presenter.get_fft_inputs(), - {'AcceptXRoundingErrors': True, 'AutoShift': True, 'Imaginary': 1, - 'InputImagWorkspace': '__ReTmp__', 'InputWorkspace': '__ReTmp__', - 'OutputWorkspace': u'MUSR22725_raw_data;PhaseQuad;FFT', 'Real': 0}) + self.assertEquals(self.presenter.get_fft_inputs(phase_name, phase_name, 1), + {'AcceptXRoundingErrors': True, 'AutoShift': True, + 'InputWorkspace': phase_name, 'InputImagWorkspace': phase_name, + 'Real': 0, 'Imaginary': 1, 'Transform': 'Forward'}) def test_get_fft_inputs_without_phase_quad(self): self.presenter.getWorkspaceNames() self.view.ws.setCurrentIndex(1) - self.assertEquals(self.presenter.get_fft_inputs(), + self.assertEquals(self.presenter.get_fft_inputs('input_workspace', 'imaginary_input_workspace'), {'AcceptXRoundingErrors': True, 'AutoShift': True, 'Imaginary': 0, - 'InputImagWorkspace': '__ImTmp__', 'InputWorkspace': '__ReTmp__', - 'OutputWorkspace': u'MUSR22725; Pair Asym; test_pair; #1;FFT', 'Real': 0}) + 'InputImagWorkspace': 'imaginary_input_workspace', 'InputWorkspace': 'input_workspace', + 'Real': 0, 'Transform': 'Forward'}) - def test_get_initial_input_run(self): + def test_get_fft_inputs_with_no_imaginary_workspace_specified(self): + self.presenter.getWorkspaceNames() + self.view.imaginary_data = False + + self.assertEquals(self.presenter.get_fft_inputs('input_workspace', 'imaginary_input_workspace'), + {'AcceptXRoundingErrors': True, 'AutoShift': True, + 'InputWorkspace': 'input_workspace', + 'Real': 0, 'Transform': 'Forward'}) + + @mock.patch('Muon.GUI.FrequencyDomainAnalysis.FFT.fft_presenter_new.run_PaddingAndApodization') + @mock.patch('Muon.GUI.FrequencyDomainAnalysis.FFT.fft_presenter_new.run_FFT') + def test_calculate_FFT_calls_correct_algorithm_sequence_for_imaginary_phase_quad(self, fft_mock, apodization_mock): + apodization_mock_return = mock.MagicMock() + fft_mock_return = mock.MagicMock() + fft_mock.return_value = fft_mock_return + apodization_mock.return_value = apodization_mock_return + self.presenter.add_fft_workspace_to_ADS = mock.MagicMock() + self.presenter.calculate_base_name_and_group = mock.MagicMock( + return_value=('MUSR22725_PhaseQuad_MUSR22725_phase_table', + 'MUSR22725 PhaseTable')) + workspace_wrapper = mock.MagicMock() + workspace_wrapper.workspace_name = 'MUSR22725_PhaseQuad_MUSR22725_phase_table' + self.context.phase_context.add_phase_quad(workspace_wrapper) self.presenter.getWorkspaceNames() - self.assertEquals(self.presenter.get_input_run(), 'MUSR22725') - self.view.ws.setCurrentIndex(1) - self.assertEquals(self.presenter.get_input_run(), 'MUSR22725') + self.presenter.calculate_FFT() + + apodization_mock.assert_called_once_with( + {'Padding': 1, 'ApodizationFunction': 'Lorentz', 'NegativePadding': True, + 'InputWorkspace': 'MUSR22725_PhaseQuad_MUSR22725_phase_table', 'DecayConstant': 4.4}) + + fft_mock.assert_called_once_with({'Real': 0, 'InputWorkspace': apodization_mock_return, 'Transform': 'Forward', + 'AcceptXRoundingErrors': True, 'AutoShift': True, + 'InputImagWorkspace': apodization_mock_return, + 'Imaginary': 1}) + + self.presenter.add_fft_workspace_to_ADS.assert_called_once_with('MUSR22725_PhaseQuad_MUSR22725_phase_table', + 'MUSR22725_PhaseQuad_MUSR22725_phase_table', + fft_mock_return) if __name__ == '__main__': diff --git a/scripts/test/Muon/fft_presenter_new_test.py b/scripts/test/Muon/fft_presenter_new_test.py deleted file mode 100644 index fc0f7a8889e7853da5a7d9c316548e4093e2c164..0000000000000000000000000000000000000000 --- a/scripts/test/Muon/fft_presenter_new_test.py +++ /dev/null @@ -1,270 +0,0 @@ -# Mantid Repository : https://github.com/mantidproject/mantid -# -# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, -# NScD Oak Ridge National Laboratory, European Spallation Source -# & Institut Laue - Langevin -# SPDX - License - Identifier: GPL - 3.0 + -import unittest - -from mantid.py3compat import mock -from Muon.GUI.Common.utilities import load_utils -from Muon.GUI.Common import thread_model -from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_presenter_new -from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_view -from Muon.GUI.FrequencyDomainAnalysis.FFT import fft_model -from Muon.GUI.Common.contexts.muon_context import MuonContext - - -class FFTPresenterTest(unittest.TestCase): - - def setUp(self): - self.load = mock.create_autospec(MuonContext, spec_set=True) - - self.view = mock.create_autospec(fft_view.FFTView, spec_set=True) - # signals - self.view.tableClickSignal = mock.Mock(return_value=[3, 1]) - self.view.phaseCheckSignal = mock.Mock(return_value=True) - # needed for connect in presenter - self.view.buttonSignal = mock.Mock() - self.view.tableClickSignal = mock.Mock() - self.view.phaseCheckSignal = mock.Mock() - self.view.changed = mock.MagicMock() - self.view.changedHideUnTick = mock.MagicMock() - self.view.initFFTInput = mock.Mock( - return_value={ - "InputWorkspace": "testWS", - "OutputWorkspace": "muon"}) - self.view.addFFTComplex = mock.Mock( - return_value={"InputImWorkspace": "MuonFFT"}) - self.view.addFFTShift = mock.Mock() - self.view.addRaw = mock.Mock() - self.view.getFFTRePhase = mock.Mock() - self.view.getFFTImPhase = mock.Mock() - self.view.getWS = mock.Mock(return_value="MUSR00023456") - self.view.getFirstGoodData = mock.Mock(return_value=0.1) - self.view.getLastGoodData = mock.Mock(return_value=15.) - self.view.getImBoxRow = mock.Mock(return_value=3) - self.view.getShiftBoxRow = mock.Mock(return_value=5) - self.view.isRaw = mock.Mock(return_value=True) - self.view.isComplex = mock.Mock(return_value=True) - self.view.isAutoShift = mock.Mock(return_value=True) - self.view.setPhaseBox = mock.Mock() - self.view.isNewPhaseTable = mock.Mock(return_value=True) - self.view.activateButton = mock.Mock() - self.view.deactivateButton = mock.Mock() - # setup model - self.model1 = mock.create_autospec(fft_model.FFTModel, spec_set=False) - self.model = mock.create_autospec(fft_model.FFTWrapper, spec_set=False) - - # set presenter - self.presenter = fft_presenter_new.FFTPresenter( - self.view, self.model, self.load) - - # mock thread - self.thread = mock.create_autospec(thread_model.ThreadModel) - self.thread.start = mock.Mock() - self.thread.started = mock.Mock() - self.thread.finished = mock.Mock() - self.thread.setInputs = mock.Mock() - self.thread.loadData = mock.Mock() - self.presenter.createThread = mock.Mock(return_value=self.thread) - - def sendSignal(self): - row, col = self.view.tableClickSignal() - self.presenter.tableClicked(row, col) - - def test_connects(self): - assert(self.view.tableClickSignal.connect.call_count==1) - self.view.tableClickSignal.connect.assert_called_with(self.presenter.tableClicked) - - assert(self.view.buttonSignal.connect.call_count==1) - self.view.buttonSignal.connect.assert_called_with(self.presenter.handleButton) - - assert(self.view.phaseCheckSignal.connect.call_count==1) - self.view.phaseCheckSignal.connect.assert_called_with(self.presenter.phaseCheck) - - def test_ImBox(self): - self.view.tableClickSignal = mock.Mock(return_value=[3, 1]) - self.sendSignal() - assert(self.view.changedHideUnTick.call_count == 1) - assert(self.view.changed.call_count == 0) - - def test_shiftBox(self): - self.view.tableClickSignal = mock.Mock(return_value=[5, 1]) - self.sendSignal() - assert(self.view.changed.call_count == 1) - assert(self.view.changedHideUnTick.call_count == 0) - - def test_buttonNotRawAndNoIm(self): - self.view.isAutoShift = mock.Mock(return_value=True) - self.view.isComplex = mock.Mock(return_value=False) - self.view.isRaw = mock.Mock(return_value=False) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 0) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonNotRawAndIm(self): - self.view.isAutoShift = mock.Mock(return_value=True) - self.view.isComplex = mock.Mock(return_value=True) - self.view.isRaw = mock.Mock(return_value=False) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 1) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonRawAndIm(self): - self.view.isAutoShift = mock.Mock(return_value=True) - self.view.isComplex = mock.Mock(return_value=True) - self.view.isRaw = mock.Mock(return_value=True) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 1) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonRawAndNoIm(self): - self.view.isAutoShift = mock.Mock(return_value=True) - self.view.isComplex = mock.Mock(return_value=False) - self.view.isRaw = mock.Mock(return_value=True) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 0) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonNoShiftNotRawAndNoIm(self): - self.view.isAutoShift = mock.Mock(return_value=False) - self.view.isComplex = mock.Mock(return_value=False) - self.view.isRaw = mock.Mock(return_value=False) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 0) - assert(self.view.addFFTShift.call_count == 1) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonNoShiftNotRawAndIm(self): - self.view.isAutoShift = mock.Mock(return_value=False) - self.view.isComplex = mock.Mock(return_value=True) - self.view.isRaw = mock.Mock(return_value=False) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 1) - assert(self.view.addFFTShift.call_count == 1) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonNoShiftRawAndIm(self): - self.view.isAutoShift = mock.Mock(return_value=False) - self.view.isComplex = mock.Mock(return_value=True) - self.view.isRaw = mock.Mock(return_value=True) - self.presenter.handleButton() - self.assertEquals(self.view.initFFTInput.call_count, 1) - self.assertEquals(self.view.addFFTComplex.call_count,1) - self.assertEquals(self.view.addFFTShift.call_count, 1) - self.assertEquals(self.view.setPhaseBox.call_count, 1) - self.assertEquals(self.view.getFirstGoodData.call_count, 0) - self.assertEquals(self.view.getLastGoodData.call_count, 0) - self.assertEquals(self.presenter.thread.start.call_count, 1) - - def test_buttonNoShiftRawAndNoIm(self): - self.view.isAutoShift = mock.Mock(return_value=False) - self.view.isComplex = mock.Mock(return_value=False) - self.view.isRaw = mock.Mock(return_value=True) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 0) - assert(self.view.addFFTShift.call_count == 1) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 0) - assert(self.view.getLastGoodData.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonPhaseQuad(self): - self.view.getWS = mock.Mock(return_value="PhaseQuad") - self.view.isComplex = mock.Mock(return_value=False) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 0) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 1) - assert(self.view.getLastGoodData.call_count == 1) - assert(self.view.getFFTRePhase.call_count == 1) - assert(self.view.getFFTImPhase.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonImPhaseQuad(self): - self.view.getWS = mock.Mock(return_value="PhaseQuad") - self.view.isComplex = mock.Mock(return_value=True) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 1) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 1) - assert(self.view.getLastGoodData.call_count == 1) - assert(self.view.getFFTRePhase.call_count == 1) - assert(self.view.getFFTImPhase.call_count == 1) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonPhaseQuadNoTable(self): - self.view.getWS = mock.Mock(return_value="PhaseQuad") - self.view.isComplex = mock.Mock(return_value=False) - self.view.isNewPhaseTable = mock.Mock(return_value=False) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 0) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 1) - assert(self.view.getLastGoodData.call_count == 1) - assert(self.view.getFFTRePhase.call_count == 1) - assert(self.view.getFFTImPhase.call_count == 0) - assert(self.presenter.thread.start.call_count == 1) - - def test_buttonImPhaseQuadNoTable(self): - self.view.getWS = mock.Mock(return_value="PhaseQuad") - self.view.isNewPhaseTable = mock.Mock(return_value=False) - self.view.isComplex = mock.Mock(return_value=True) - self.presenter.handleButton() - assert(self.view.initFFTInput.call_count == 1) - assert(self.view.addFFTComplex.call_count == 1) - assert(self.view.addFFTShift.call_count == 0) - assert(self.view.setPhaseBox.call_count == 1) - assert(self.view.getFirstGoodData.call_count == 1) - assert(self.view.getLastGoodData.call_count == 1) - assert(self.view.getFFTRePhase.call_count == 1) - assert(self.view.getFFTImPhase.call_count == 1) - assert(self.presenter.thread.start.call_count == 1) - - def test_activateButton(self): - self.presenter.activate() - assert(self.view.activateButton.call_count == 1) - - def test_deactivateButton(self): - self.presenter.deactivate() - assert(self.view.deactivateButton.call_count == 1) - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/scripts/test/Muon/home_instrument_widget_test.py b/scripts/test/Muon/home_instrument_widget_test.py index 04296c5e8be21a453fcd64d7a13c8b385501ee5e..9e5759b79ac0487a650e4fe6c12f5ae088f331b1 100644 --- a/scripts/test/Muon/home_instrument_widget_test.py +++ b/scripts/test/Muon/home_instrument_widget_test.py @@ -68,18 +68,18 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): def test_that_changeing_time_zero_updates_model(self): time_zero = 1.23456 - self.view.timezero_checkbox.setChecked(False) + self.view.time_zero_checkbox.setChecked(False) self.view.set_time_zero(time_zero) - self.view.timezero_edit.editingFinished.emit() + self.view.time_zero_edit.editingFinished.emit() self.assertEqual(self.model.get_user_time_zero(), round(time_zero, 3)) self.assertEqual(self.gui_variable_observer.update.call_count, 2) def test_that_changeing_time_zero_does_nothing_if_checkbox_is_checked(self): time_zero = 1.23456 - self.view.timezero_checkbox.setChecked(True) + self.view.time_zero_checkbox.setChecked(True) self.view.set_time_zero(time_zero) - self.view.timezero_edit.editingFinished.emit() + self.view.time_zero_edit.editingFinished.emit() self.assertEqual(self.model.get_user_time_zero(), 0.0) self.assertEqual(self.gui_variable_observer.update.call_count, 0) @@ -88,28 +88,28 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): user_time_zero = 1.234 self.model.set_user_time_zero(user_time_zero) - self.view.timezero_checkbox.setChecked(True) + self.view.time_zero_checkbox.setChecked(True) self.assertEqual(self.view.get_time_zero(), 0.0) self.assertEqual(self.gui_variable_observer.update.call_count, 1) - self.view.timezero_checkbox.setChecked(False) + self.view.time_zero_checkbox.setChecked(False) self.assertEqual(self.view.get_time_zero(), user_time_zero) self.assertEqual(self.gui_variable_observer.update.call_count, 2) def test_that_changeing_first_good_data_updates_model(self): time_zero = 1.23456 - self.view.firstgooddata_checkbox.setChecked(False) + self.view.first_good_data_checkbox.setChecked(False) self.view.set_first_good_data(time_zero) - self.view.firstgooddata_edit.editingFinished.emit() + self.view.first_good_data_edit.editingFinished.emit() self.assertEqual(self.model.get_user_first_good_data(), round(time_zero, 3)) self.assertEqual(self.gui_variable_observer.update.call_count, 2) def test_that_changeing_first_good_data_does_nothing_if_checkbox_is_checked(self): time_zero = 1.23456 - self.view.firstgooddata_checkbox.setChecked(True) + self.view.first_good_data_checkbox.setChecked(True) self.view.set_first_good_data(time_zero) - self.view.firstgooddata_edit.editingFinished.emit() + self.view.first_good_data_edit.editingFinished.emit() self.assertEqual(self.model.get_user_time_zero(), 0.0) self.assertEqual(self.gui_variable_observer.update.call_count, 0) @@ -118,11 +118,11 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): user_time_zero = 1.234 self.model.set_user_first_good_data(user_time_zero) - self.view.firstgooddata_checkbox.setChecked(True) + self.view.first_good_data_checkbox.setChecked(True) self.assertEqual(self.view.get_first_good_data(), 0.0) self.assertEqual(self.gui_variable_observer.update.call_count, 1) - self.view.firstgooddata_checkbox.setChecked(False) + self.view.first_good_data_checkbox.setChecked(False) self.assertEqual(self.view.get_first_good_data(), user_time_zero) self.assertEqual(self.gui_variable_observer.update.call_count, 2) @@ -174,17 +174,18 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): self.assertEqual(self.gui_variable_observer.update.call_count, 3) def test_that_on_dead_time_unselected_deadtime_model_set_to_none(self): - self.view.deadtime_selector.setCurrentIndex(1) - self.view.deadtime_selector.setCurrentIndex(0) + self.view.dead_time_selector.setCurrentIndex(1) + self.context.gui_context['DeadTimeSource'] = 'FromFile' + self.view.dead_time_selector.setCurrentIndex(0) - self.assertEqual(self.view.deadtime_label_3.text(), self.presenter.dead_time_from_data_text([0.0])) + self.assertEqual(self.view.dead_time_label_3.text(), self.presenter.dead_time_from_data_text([0.0])) self.assertEqual(self.model._data.current_data["DeadTimeTable"], None) self.gui_variable_observer.update.assert_called_once_with(self.gui_context.gui_variables_notifier, None) def test_that_on_deadtime_data_selected_updates_with_no_loaded_data(self): - self.view.deadtime_selector.setCurrentIndex(1) + self.view.dead_time_selector.setCurrentIndex(1) - self.assertEqual(self.view.deadtime_label_3.text(), "No loaded dead time") + self.assertEqual(self.view.dead_time_label_3.text(), "No loaded dead time") self.assertEqual(self.gui_variable_observer.update.call_count, 0) def test_that_on_deadtime_data_selected_updates_with_loaded_data(self): @@ -192,9 +193,9 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): dead_time_data.toDict.return_value = {'dead-time': [0.001, 0.002, 0.003]} self.presenter._model.get_dead_time_table_from_data = mock.MagicMock(return_value=dead_time_data) - self.view.deadtime_selector.setCurrentIndex(1) + self.view.dead_time_selector.setCurrentIndex(1) - self.assertEqual(self.view.deadtime_label_3.text(), 'From 0.001 to 0.003 (ave. 0.002)') + self.assertEqual(self.view.dead_time_label_3.text(), 'From 0.001 to 0.003 (ave. 0.002)') self.gui_variable_observer.update.assert_called_once_with(self.gui_context.gui_variables_notifier, None) @mock.patch( @@ -202,33 +203,34 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): def test_that_selecting_from_table_workspace_deadtime_option_enables_table_workspace_combo_box(self, get_table_names_mock): get_table_names_mock.return_value = ['table_1', 'table_2', 'table_3'] - self.assertTrue(self.view.deadtime_file_selector.isHidden()) + self.assertTrue(self.view.dead_time_file_selector.isHidden()) - self.view.deadtime_selector.setCurrentIndex(2) + self.view.dead_time_selector.setCurrentIndex(2) - self.assertEqual(self.view.deadtime_label_3.text(), "From 0.000 to 0.000 (ave. 0.000)") - self.assertFalse(self.view.deadtime_file_selector.isHidden()) - self.assertEqual(self.view.deadtime_file_selector.count(), 4) - self.assertEqual(self.view.deadtime_file_selector.itemText(0), 'None') - self.assertEqual(self.view.deadtime_file_selector.itemText(1), 'table_1') - self.assertEqual(self.view.deadtime_file_selector.itemText(2), 'table_2') - self.assertEqual(self.view.deadtime_file_selector.itemText(3), 'table_3') + self.assertEqual(self.view.dead_time_label_3.text(), "From 0.000 to 0.000 (ave. 0.000)") + self.assertFalse(self.view.dead_time_file_selector.isHidden()) + self.assertEqual(self.view.dead_time_file_selector.count(), 4) + self.assertEqual(self.view.dead_time_file_selector.itemText(0), 'None') + self.assertEqual(self.view.dead_time_file_selector.itemText(1), 'table_1') + self.assertEqual(self.view.dead_time_file_selector.itemText(2), 'table_2') + self.assertEqual(self.view.dead_time_file_selector.itemText(3), 'table_3') self.assertEqual(self.gui_variable_observer.update.call_count, 0) def test_that_returning_to_None_options_hides_table_workspace_selector(self): - self.view.deadtime_selector.setCurrentIndex(2) - self.view.deadtime_selector.setCurrentIndex(0) + self.view.dead_time_selector.setCurrentIndex(2) + self.context.gui_context['DeadTimeSource'] = 'FromADS' + self.view.dead_time_selector.setCurrentIndex(0) - self.assertEqual(self.view.deadtime_label_3.text(), "From 0.000 to 0.000 (ave. 0.000)") - self.assertTrue(self.view.deadtime_file_selector.isHidden()) + self.assertEqual(self.view.dead_time_label_3.text(), "From 0.000 to 0.000 (ave. 0.000)") + self.assertTrue(self.view.dead_time_file_selector.isHidden()) self.gui_variable_observer.update.assert_called_once_with(self.gui_context.gui_variables_notifier, None) def test_browse_button_displayed_when_from_other_file_selected(self): - self.assertTrue(self.view.deadtime_browse_button.isHidden()) + self.assertTrue(self.view.dead_time_browse_button.isHidden()) - self.view.deadtime_selector.setCurrentIndex(3) + self.view.dead_time_selector.setCurrentIndex(3) - self.assertFalse(self.view.deadtime_browse_button.isHidden()) + self.assertFalse(self.view.dead_time_browse_button.isHidden()) self.assertEqual(self.gui_variable_observer.update.call_count, 0) @mock.patch( @@ -236,9 +238,9 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): def test_browse_clicked_displays_warning_popup_if_file_does_not_contain_table(self, load_deadtime_mock): self.view.show_file_browser_and_return_selection = mock.MagicMock() load_deadtime_mock.return_value = '' - self.view.deadtime_selector.setCurrentIndex(3) + self.view.dead_time_selector.setCurrentIndex(3) - self.view.deadtime_browse_button.clicked.emit(True) + self.view.dead_time_browse_button.clicked.emit(True) self.view.show_file_browser_and_return_selection.assert_called_once_with('Files (*.nxs)', [''], multiple_files=False) @@ -250,9 +252,9 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): 'Muon.GUI.Common.home_instrument_widget.home_instrument_widget_presenter.load_utils.load_dead_time_from_filename') def test_browse_clicked_does_nothing_if_no_file_selected(self, load_deadtime_mock): self.view.show_file_browser_and_return_selection = mock.MagicMock(return_value=['']) - self.view.deadtime_selector.setCurrentIndex(3) + self.view.dead_time_selector.setCurrentIndex(3) - self.view.deadtime_browse_button.clicked.emit(True) + self.view.dead_time_browse_button.clicked.emit(True) load_deadtime_mock.assert_not_called() self.view.warning_popup.assert_not_called() @@ -263,11 +265,11 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): def test_browse_clicked_fails_if_table_not_loaded_into_ADS(self, load_deadtime_mock): self.view.show_file_browser_and_return_selection = mock.MagicMock(return_value=['filename']) load_deadtime_mock.return_value = 'dead_time_table_name' - self.view.deadtime_selector.setCurrentIndex(3) + self.view.dead_time_selector.setCurrentIndex(3) - self.view.deadtime_browse_button.clicked.emit(True) + self.view.dead_time_browse_button.clicked.emit(True) - self.assertEqual(self.view.deadtime_selector.currentIndex(), 2) + self.assertEqual(self.view.dead_time_selector.currentIndex(), 2) self.view.warning_popup.assert_called_once_with("Dead time table cannot be loaded") self.gui_variable_observer.update.assert_not_called() @@ -276,11 +278,11 @@ class HomeTabInstrumentPresenterTest(unittest.TestCase): self.view.show_file_browser_and_return_selection = mock.MagicMock(return_value=[filename]) self.model.check_dead_time_file_selection = mock.MagicMock(return_value=True) - self.view.deadtime_browse_button.clicked.emit(True) + self.view.dead_time_browse_button.clicked.emit(True) - self.assertEqual(self.view.deadtime_selector.currentIndex(), 2) + self.assertEqual(self.view.dead_time_selector.currentIndex(), 2) self.view.warning_popup.assert_not_called() - self.assertEqual(self.view.deadtime_file_selector.currentText(), 'MUSR00015196_deadTimes') + self.assertEqual(self.view.dead_time_file_selector.currentText(), 'MUSR00015196_deadTimes') self.gui_variable_observer.update.assert_called_once_with(self.gui_context.gui_variables_notifier, None) def test_validate_variable_rebin_string_allows_single_number(self): diff --git a/scripts/test/Muon/max_ent_presenter_load_interaction_test.py b/scripts/test/Muon/max_ent_presenter_load_interaction_test.py index af91c68aec93e9abf8a203f5b32f9a157850d20c..a90275f2764ff9f1c1be9599d383c57ec071281e 100644 --- a/scripts/test/Muon/max_ent_presenter_load_interaction_test.py +++ b/scripts/test/Muon/max_ent_presenter_load_interaction_test.py @@ -9,16 +9,19 @@ from __future__ import (absolute_import, division, print_function) import unittest from qtpy import QtWidgets -from mantid.api import FileFinder +from Muon.GUI.FrequencyDomainAnalysis.MaxEnt import maxent_view_new from mantid.py3compat import mock from Muon.GUI.Common.muon_pair import MuonPair +from mantid.api import FileFinder +from qtpy import QtCore from Muon.GUI.Common.test_helpers import mock_widget from Muon.GUI.Common.test_helpers.context_setup import setup_context_for_tests from Muon.GUI.Common.utilities import load_utils from Muon.GUI.FrequencyDomainAnalysis.MaxEnt import maxent_model from Muon.GUI.FrequencyDomainAnalysis.MaxEnt import maxent_presenter_new -from Muon.GUI.FrequencyDomainAnalysis.MaxEnt import maxent_view +from Muon.GUI.Common.test_helpers.general_test_helpers import create_workspace_wrapper_stub_object +from mantid.api import Workspace def retrieve_combobox_info(combo_box): @@ -41,9 +44,9 @@ class MaxEntPresenterTest(unittest.TestCase): self.gui_context.update({'RebinType': 'None'}) self.model = maxent_model.MaxEntModel() - self.view = maxent_view.MaxEntView(self.obj) + self.view = maxent_view_new.MaxEntView(self.obj) - self.presenter = maxent_presenter_new.MaxEntPresenter(self.view, self.model, self.context) + self.presenter = maxent_presenter_new.MaxEntPresenter(self.view, self.context) file_path = FileFinder.findRuns('MUSR00022725.nxs')[0] ws, run, filename = load_utils.load_workspace_from_filename(file_path) @@ -61,32 +64,75 @@ class MaxEntPresenterTest(unittest.TestCase): self.presenter.getWorkspaceNames() self.assertEquals(retrieve_combobox_info(self.view.ws), ['MUSR22725_raw_data']) - self.assertEquals(retrieve_combobox_info(self.view.N_points), ['2048', '4096', '8192', '16384', '32768', '65536', - '131072', '262144', '524288', '1048576']) + self.assertEquals(retrieve_combobox_info(self.view.N_points), + ['2048', '4096', '8192', '16384', '32768', '65536', + '131072', '262144', '524288', '1048576']) - def test_get_phase_table_inputs_returns_correctly(self): + def test_get_parameters_for_maxent_calculations(self): self.presenter.getWorkspaceNames() + self.context.dead_time_table = mock.MagicMock(return_value='deadtime_table_name') + self.context.first_good_data = mock.MagicMock(return_value=0.11) + self.context.last_good_data = mock.MagicMock(return_value=13.25) + self.context.phase_context.phase_tables = [create_workspace_wrapper_stub_object(x) for x in + ['MUSR22222_phase_table', 'MUSR33333_phase_table', + 'EMU22222_phase_table']] + self.presenter.update_phase_table_options() - self.assertEquals(self.presenter.get_phase_table_inputs(), {'DataFitted': 'fits', 'DetectorTable': 'PhaseTable', - 'FirstGoodData': 0.1, 'InputWorkspace': 'MUSR22725_raw_data', - 'LastGoodData': 15.0}) + parameters = self.presenter.get_parameters_for_maxent_calculation() - def test_get_input_run_returns_correctly(self): - self.presenter.getWorkspaceNames() + self.assertEquals(parameters, {'DefaultLevel': 0.1, 'DoublePulse': False, 'Factor': 1.04, 'FirstGoodTime': 0.11, + 'FitDeadTime': True, 'InnerIterations': 10, + 'InputDeadTimeTable': 'deadtime_table_name', + 'InputWorkspace': 'MUSR22725_raw_data', + 'LastGoodTime': 13.25, 'MaxField': 1000.0, 'Npts': 2048, 'OuterIterations': 10}) + + def test_update_phase_table_options_adds_correct_options_to_view_item(self): + phase_table_names = ['MUSR22222_phase_table', 'MUSR33333_phase_table', 'EMU22222_phase_table'] + self.context.phase_context.phase_tables = [create_workspace_wrapper_stub_object(x) for x in phase_table_names] + + self.presenter.update_phase_table_options() - self.assertEquals(self.presenter.get_input_run(), 'MUSR22725') + self.assertEquals(retrieve_combobox_info(self.view.phase_table_combo), + ['Construct', 'MUSR22222_phase_table', 'MUSR33333_phase_table']) - def test_get_max_ent_inputs_return_correctly(self): + @mock.patch('Muon.GUI.FrequencyDomainAnalysis.MaxEnt.maxent_presenter_new.MuonWorkspaceWrapper') + def test_add_maxent_workspace_to_ADS(self, workspace_wrapper_mock): self.presenter.getWorkspaceNames() + self.context.dead_time_table = mock.MagicMock(return_value='deadtime_table_name') + self.context.first_good_data = mock.MagicMock(return_value=0.11) + self.context.last_good_data = mock.MagicMock(return_value=13.25) + self.context.phase_context.phase_tables = [create_workspace_wrapper_stub_object(x) for x in + ['MUSR22222_phase_table', 'MUSR33333_phase_table', + 'EMU22222_phase_table']] + self.presenter.update_phase_table_options() + maxent_workspace = mock.MagicMock(spec=Workspace) + + self.presenter.add_maxent_workspace_to_ADS('MUSR22725_MaxEnt', maxent_workspace, mock.MagicMock()) + + workspace_wrapper_mock.assert_called_once_with(maxent_workspace, + 'Muon Data/MUSR22725/MUSR22725 Maxent/MUSR22725_MaxEnt; MaxEnt') + workspace_wrapper_mock.return_value.show.assert_called_once_with() + + def test_get_output_options_defaults_returns_correctly(self): + self.presenter.getWorkspaceNames() + + output_options = self.presenter.get_maxent_output_options() - self.assertEquals(self.presenter.getMaxEntInput(), {'DefaultLevel': 0.1, 'DoublePulse': False, 'Factor': 1.04, - 'FirstGoodTime': 0.1, 'FitDeadTime': True, 'InnerIterations': 10, - 'InputWorkspace': 'MUSR22725_raw_data', 'LastGoodTime': 15.0, - 'MaxField': 1000.0, 'Npts': 2048, 'OuterIterations': 10, - 'OutputWorkspace': 'MUSR22725_raw_data;FrequencyDomain;MaxEnt'}) + self.assertEquals(output_options, {'OutputDeadTimeTable': False, 'PhaseConvergenceTable': False, + 'OutputPhaseTable': False, 'ReconstructedSpectra': False}) + + def test_get_output_options_returns_correctly(self): + self.presenter.getWorkspaceNames() + self.view.output_dead_box.setCheckState(QtCore.Qt.Checked) + self.view.output_phase_box.setCheckState(QtCore.Qt.Checked) + self.view.output_phase_evo_box.setCheckState(QtCore.Qt.Checked) + self.view.output_data_box.setCheckState(QtCore.Qt.Checked) + output_options = self.presenter.get_maxent_output_options() + self.assertEquals(output_options, {'OutputDeadTimeTable': True, 'PhaseConvergenceTable': True, + 'OutputPhaseTable': True, 'ReconstructedSpectra': True}) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/scripts/test/Muon/muon_context_test.py b/scripts/test/Muon/muon_context_test.py index 9f93b17fc88494e7c6732cdfee3461b876b4a596..3e9920e967ea32faefd9f7bd4135f531dedc234b 100644 --- a/scripts/test/Muon/muon_context_test.py +++ b/scripts/test/Muon/muon_context_test.py @@ -113,6 +113,40 @@ class MuonContextTest(unittest.TestCase): self.assertEquals(AnalysisDataService.getObjectNames(), ['EMU19489', 'EMU19489 Raw Data', 'EMU19489_raw_data', 'Muon Data']) + def test_that_first_good_data_returns_correctly_when_from_file_chosen_option(self): + self.gui_context.update({'FirstGoodDataFromFile': True}) + + first_good_data = self.context.first_good_data([19489]) + + self.assertEquals(first_good_data, 0.11) + + def test_first_good_data_returns_correctly_when_manually_specified_used(self): + self.gui_context.update({'FirstGoodDataFromFile': False, 'FirstGoodData': 5}) + + first_good_data = self.context.first_good_data([19489]) + + self.assertEquals(first_good_data, 5) + + def test_that_last_good_data_returns_correctly_when_from_file_chosen_option(self): + self.gui_context.update({'LastGoodDataFromFile': True}) + + last_good_data = self.context.last_good_data([19489]) + + self.assertEquals(last_good_data, 31.76) + + def test_last_good_data_returns_correctly_when_manually_specified_used(self): + self.gui_context.update({'LastGoodDataFromFile': False, 'LastGoodData': 5}) + + last_good_data = self.context.last_good_data([19489]) + + self.assertEquals(last_good_data, 5) + + def test_that_dead_time_table_from_ADS_returns_table_name(self): + self.gui_context.update({'DeadTimeSource': 'FromADS', 'DeadTimeTable': 'deadtime_table_name'}) + + deadtime_table = self.context.dead_time_table([19489]) + + self.assertEquals(deadtime_table, 'deadtime_table_name') if __name__ == '__main__': unittest.main(buffer=False, verbosity=2) \ No newline at end of file diff --git a/scripts/test/Muon/phase_table_widget/phase_table_context_test.py b/scripts/test/Muon/phase_table_widget/phase_table_context_test.py index 23781068b57ba34c3597354cc72e85c7cfdc621d..f98f84d415657d171d3da1f13d367c25d6d27903 100644 --- a/scripts/test/Muon/phase_table_widget/phase_table_context_test.py +++ b/scripts/test/Muon/phase_table_widget/phase_table_context_test.py @@ -1,5 +1,7 @@ from Muon.GUI.Common.contexts.phase_table_context import PhaseTableContext, default_dict import unittest +from Muon.GUI.Common.test_helpers.general_test_helpers import create_workspace_wrapper_stub_object + class PhaseTableContextTest(unittest.TestCase): def setUp(self): @@ -9,22 +11,35 @@ class PhaseTableContextTest(unittest.TestCase): self.assertEquals(self.context.options_dict, default_dict) self.assertEquals(self.context.phase_tables, []) - def test_add_phase_table_adds_phase_table_name_to_dict_with_run_as_key(self): - name = 'MUSR22222_phase_table' + def test_add_phase_table_adds_phase_table_name_to_list(self): + name = create_workspace_wrapper_stub_object('MUSR22222_phase_table') self.context.add_phase_table(name) self.assertEquals(self.context.phase_tables, [name]) def test_get_phase_table_list_retrieves_all_tables_wth_correct_instrument(self): - name = 'MUSR22222_phase_table' + name = create_workspace_wrapper_stub_object('MUSR22222_phase_table') self.context.add_phase_table(name) - name = 'EMU22222_phase_table' + name = create_workspace_wrapper_stub_object('EMU22222_phase_table') self.context.add_phase_table(name) - name = 'MUSR33333_phase_table' + name = create_workspace_wrapper_stub_object('MUSR33333_phase_table') self.context.add_phase_table(name) self.assertEquals(self.context.get_phase_table_list('MUSR'), ['MUSR22222_phase_table', 'MUSR33333_phase_table']) + def test_add_phase_quad_adds_phase_quad_name_to_list(self): + name = create_workspace_wrapper_stub_object('MUSR22222_phase_quad') + + self.context.add_phase_quad(name) + + self.assertEquals(self.context.phase_quad, [name]) + + def test_get_phase_quad_returns_phase_quad_name_if_run_and_instrument_match(self): + name = create_workspace_wrapper_stub_object('MUSR22222_phase_quad') + self.context.add_phase_quad(name) + + self.assertEquals(self.context.get_phase_quad('MUSR', '22222'), ['MUSR22222_phase_quad']) + if __name__ == '__main__': unittest.main(buffer=False, verbosity=2) \ No newline at end of file diff --git a/scripts/test/Muon/phase_table_widget/phase_table_presenter_test.py b/scripts/test/Muon/phase_table_widget/phase_table_presenter_test.py index 83e45da4b015fcaaee64f18a10450354028bdf6f..56c03509b4e38453c57660a54f4d5cb95ccf627d 100644 --- a/scripts/test/Muon/phase_table_widget/phase_table_presenter_test.py +++ b/scripts/test/Muon/phase_table_widget/phase_table_presenter_test.py @@ -6,11 +6,11 @@ # SPDX - License - Identifier: GPL - 3.0 + import unittest -from mantid.py3compat import mock - -from Muon.GUI.Common.muon_group import MuonGroup from Muon.GUI.Common.phase_table_widget.phase_table_presenter import PhaseTablePresenter from Muon.GUI.Common.phase_table_widget.phase_table_view import PhaseTableView +from Muon.GUI.Common.muon_group import MuonGroup +from mantid.py3compat import mock +from qtpy import QtCore from Muon.GUI.Common.test_helpers import mock_widget from Muon.GUI.Common.test_helpers.context_setup import setup_context @@ -54,14 +54,14 @@ class PhaseTablePresenterTest(unittest.TestCase): self.assertEquals(self.context.phase_context.options_dict['input_workspace'], workspace_name) def test_create_parameters_for_cal_muon_phase_returns_correct_parameter_dict(self): - workspace_name = 'input_workspace_name' + workspace_name = 'input_workspace_name_raw_data' self.context.phase_context.options_dict['input_workspace'] = workspace_name result = self.presenter.create_parameters_for_cal_muon_phase_algorithm() self.assertEquals(result, {'BackwardSpectra': [2, 4, 6, 8, 10], 'FirstGoodData': 0.1, 'ForwardSpectra': [1, 3, 5, 7, 9], 'InputWorkspace': workspace_name, 'LastGoodData': 15, - 'DetectorTable': 'input_workspace_name_phase_table'}) + 'DetectorTable': 'input_workspace_name; PhaseTable; fwd, bwd'}) def test_correctly_retrieves_workspace_names_associsated_to_current_runs(self): self.view.set_input_combo_box = mock.MagicMock() @@ -78,16 +78,17 @@ class PhaseTablePresenterTest(unittest.TestCase): self.view.set_group_combo_boxes.assert_called_once_with(['fwd', 'bwd']) - @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.AnalysisDataService') - def test_that_phase_table_added_to_ADS_with_correct_name_and_group(self, mock_data_service): - self.context.phase_context.options_dict['input_workspace'] = 'MUSR22222_raw_data_period_1' - parameters = self.presenter.create_parameters_for_cal_muon_phase_algorithm() + @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper') + def test_that_phase_table_added_to_ADS_with_correct_name_and_group(self, mock_workspace_wrapper): + workspace_wrapper = mock.MagicMock() + mock_workspace_wrapper.return_value = workspace_wrapper mock_phase_table = mock.MagicMock() - self.presenter.add_phase_table_to_ADS(parameters, mock_phase_table) + self.presenter.add_phase_table_to_ADS('MUSR22222_period_1; PhaseTable', mock_phase_table) - mock_data_service.addOrReplace.assert_called_once_with(parameters['DetectorTable'], mock_phase_table) - mock_data_service.addToGroup.assert_called_once_with('MUSR22222', parameters['DetectorTable']) + mock_workspace_wrapper.assert_called_once_with(mock_phase_table, 'Muon Data/MUSR22222/MUSR22222 Phase Tab' + '/MUSR22222_period_1; PhaseTable') + workspace_wrapper.show.assert_called_once_with() @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases') def test_handle_calculate_phase_table_clicked_behaves_correctly_for_succesful_calculation(self, run_algorith_mock): @@ -95,14 +96,13 @@ class PhaseTablePresenterTest(unittest.TestCase): self.view.set_input_combo_box(['MUSR22222_raw_data_period_1']) self.context.phase_context.options_dict['input_workspace'] = 'MUSR22222_raw_data_period_1' self.presenter.update_view_from_model() - parameters = self.presenter.create_parameters_for_cal_muon_phase_algorithm() - run_algorith_mock.return_value = detector_table_mock + run_algorith_mock.return_value = (detector_table_mock, mock.MagicMock()) self.presenter.add_phase_table_to_ADS = mock.MagicMock() self.presenter.handle_calulate_phase_table_clicked() self.wait_for_thread(self.presenter.calculation_thread) - self.presenter.add_phase_table_to_ADS.assert_called_once_with(parameters, detector_table_mock) + self.presenter.add_phase_table_to_ADS.assert_called_once_with('MUSR22222; PhaseTable_period_1; fwd, bwd', detector_table_mock) self.assertTrue(self.view.isEnabled()) @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_CalMuonDetectorPhases') @@ -111,6 +111,7 @@ class PhaseTablePresenterTest(unittest.TestCase): self.presenter.update_view_from_model() run_algorith_mock.side_effect = RuntimeError('CalMuonDetectorPhases has failed') self.presenter.add_phase_table_to_ADS = mock.MagicMock() + self.presenter.calculate_base_name_and_group = mock.MagicMock(return_value=('MUSR22222_raw_data_period_1', 'MUSR22222 PhaseTable')) self.presenter.handle_calulate_phase_table_clicked() self.wait_for_thread(self.presenter.calculation_thread) @@ -140,15 +141,16 @@ class PhaseTablePresenterTest(unittest.TestCase): self.assertEquals(parameters, {'InputWorkspace': 'MUSR22222_raw_data_period_1', 'PhaseTable': 'created_phase_table'}) - @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.AnalysisDataService') - def test_add_phase_quad_to_ADS_does_so_in_correct_location_with_correct_name(self, mock_data_service): - parameters = {'InputWorkspace': 'MUSR22222_raw_data_period_1', 'PhaseTable': 'MUSR22222_period_1_phase_table'} + @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper') + def test_add_phase_quad_to_ADS_does_so_in_correct_location_with_correct_name(self, mock_workspace_wrapper): phase_quad = mock.MagicMock() - self.presenter.add_phase_quad_to_ADS(parameters, phase_quad) + self.presenter.add_phase_quad_to_ADS('MUSR22222_PhaseQuad_phase_table_MUSR22222', 'MUSR22222 PhaseTable', + phase_quad) - mock_data_service.addOrReplace.assert_called_once_with('MUSR22222_PhaseQuad_phase_table_MUSR22222', phase_quad) - mock_data_service.addToGroup.assert_called_once_with('MUSR22222', 'MUSR22222_PhaseQuad_phase_table_MUSR22222') + mock_workspace_wrapper.assert_called_once_with(phase_quad, 'Muon Data/MUSR22222/MUSR22222 Phase Tab/MUSR22222_' + 'PhaseQuad_phase_table_MUSR22222 MUSR22222 PhaseTable') + mock_workspace_wrapper.return_value.show.assert_called_once_with() @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_PhaseQuad') @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.mantid') @@ -158,6 +160,8 @@ class PhaseTablePresenterTest(unittest.TestCase): mantid_mock.AlgorithmManager.create.return_value = alg_mock run_algorithm_mock.return_value = phase_quad_mock self.presenter.add_phase_quad_to_ADS = mock.MagicMock() + self.presenter.calculate_base_name_and_group = mock.MagicMock(return_value=('MUSR22222_period_1_phase_table', + 'MUSR22222 PhaseTable')) self.view.set_input_combo_box(['MUSR22222_raw_data_period_1']) self.view.set_phase_table_combo_box(['MUSR22222_period_1_phase_table']) self.presenter.update_model_from_view() @@ -167,10 +171,10 @@ class PhaseTablePresenterTest(unittest.TestCase): self.assertTrue(self.view.isEnabled()) run_algorithm_mock.assert_called_once_with({'PhaseTable': 'MUSR22222_period_1_phase_table', + 'InputWorkspace': 'MUSR22222_raw_data_period_1'}, alg_mock) - self.presenter.add_phase_quad_to_ADS.assert_called_once_with({'PhaseTable': 'MUSR22222_period_1_phase_table', - 'InputWorkspace': 'MUSR22222_raw_data_period_1'}, - phase_quad_mock) + self.presenter.add_phase_quad_to_ADS.assert_called_once_with('MUSR22222_raw_data_period_1', + 'MUSR22222_period_1_phase_table', phase_quad_mock) @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.run_PhaseQuad') def test_handle_phase_quad_calculation_behaves_correctly_on_error(self, run_algorithm_mock): @@ -185,7 +189,9 @@ class PhaseTablePresenterTest(unittest.TestCase): def test_update_current_phase_table_list_retrieves_all_correct_tables(self): self.view.set_phase_table_combo_box = mock.MagicMock() - self.context.phase_context.add_phase_table('MUSR22222_phase_table') + workspace_wrapper = mock.MagicMock() + workspace_wrapper.workspace_name = 'MUSR22222_phase_table' + self.context.phase_context.add_phase_table(workspace_wrapper) self.presenter.update_current_phase_tables() @@ -205,6 +211,23 @@ class PhaseTablePresenterTest(unittest.TestCase): self.presenter.handle_calculation_error.assert_not_called() self.presenter.calculate_phase_table.assert_called_once_with() + @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper') + def test_add_fitting_info_to_ADS_does_nothing_if_output_fitting_info_is_false(self, workspace_wrapper_mock): + self.presenter.add_fitting_info_to_ADS_if_required('MUSR22222_PhaseTable', mock.MagicMock()) + + workspace_wrapper_mock.assert_not_called() + + @mock.patch('Muon.GUI.Common.phase_table_widget.phase_table_presenter.MuonWorkspaceWrapper') + def test_add_fitting_info_to_ADS_adds_fitting_info_to_ADS_if_option_selected(self, workspace_wrapper_mock): + self.view.output_fit_info_box.setCheckState(QtCore.Qt.Checked) + fit_information = mock.MagicMock() + + self.presenter.add_fitting_info_to_ADS_if_required('MUSR22222_PhaseTable',fit_information) + + workspace_wrapper_mock.assert_called_once_with(fit_information, 'Muon Data/MUSR22222/MUSR22222 Phase Tab/' + 'MUSR22222_PhaseTable; fit_information') + workspace_wrapper_mock.return_value.show.assert_called_once_with() + if __name__ == '__main__': unittest.main(buffer=False, verbosity=2) \ No newline at end of file diff --git a/scripts/test/Muon/utilities/muon_workspace_wrapper_test.py b/scripts/test/Muon/utilities/muon_workspace_wrapper_test.py index 8ce3a1f844d788560024251407ac30e6f8d83da9..988ab4c9464ebae74087fb86d281889c5b0a77e1 100644 --- a/scripts/test/Muon/utilities/muon_workspace_wrapper_test.py +++ b/scripts/test/Muon/utilities/muon_workspace_wrapper_test.py @@ -90,13 +90,6 @@ class MuonWorkspaceTest(unittest.TestCase): MuonWorkspaceWrapper(workspace=table_workspace) - def test_that_cannot_initialize_with_WorkspaceGroup_object(self): - group_workspace = api.WorkspaceGroup() - assert isinstance(group_workspace, WorkspaceGroup) - - with self.assertRaises(AttributeError): - MuonWorkspaceWrapper(workspace=group_workspace) - def test_that_cannot_initialize_with_non_workspace_objects(self): with self.assertRaises(AttributeError): MuonWorkspaceWrapper(workspace="string") @@ -220,16 +213,6 @@ class MuonWorkspaceTest(unittest.TestCase): workspace_handle.workspace = workspace2 self.assertFalse(simpleapi.mtd.doesExist("name1")) - def test_that_setting_a_new_workspace_resets_the_name_to_empty_string(self): - workspace_handle = MuonWorkspaceWrapper(workspace=self.workspace) - workspace_handle.show("name1") - - workspace2 = create_simple_workspace(data_x=[5, 6, 7, 8], data_y=[20, 20, 20, 20]) - - self.assertEqual(workspace_handle.name, "name1") - workspace_handle.workspace = workspace2 - self.assertEqual(workspace_handle.name, "") - class MuonWorkspaceAddDirectoryTest(unittest.TestCase): """