Esempio n. 1
0
    def __init__(self, model, view):
        self.model = model
        self.view = view
        self.worker = None
        self.calibration_notifier = self.CalibrationNotifier(self)

        self.current_calibration = CalibrationInfo()

        self.connect_view_signals()

        # Main Window State Variables
        self.instrument = "ENGINX"
        self.rb_num = None

        # Cropping Options
        self.cropping_widget = CroppingPresenter(parent=self.view, view=self.view.get_cropping_widget())
        self.show_cropping(False)
    def test_calibrate_clicked_new_valid_calibration_with_plotting(self, mock_validate, mock_start_worker):
        self.view.get_new_checked.return_value = True
        self.view.get_plot_output.return_value = True
        mock_validate.return_value = True
        self.presenter.current_calibration = mock.create_autospec(CalibrationInfo())

        self.presenter.on_calibrate_clicked()

        mock_start_worker.assert_called_once_with(mock_validate())
    def test_calibrate_clicked_new_invalid_calibration(self, mock_validate, mock_start_worker):
        self.view.get_new_checked.return_value = True
        self.view.get_plot_output.return_value = True
        self.view.get_load_checked.return_value = False
        mock_validate.return_value = False
        self.presenter.current_calibration = mock.create_autospec(CalibrationInfo())

        self.presenter.on_calibrate_clicked()

        mock_start_worker.assert_not_called()  # called if created new one
        self.model.load_existing_calibration_files.assert_not_called()  # called if loaded calibration
    def test_calibrate_clicked_load_invalid_path(self, mock_valid_path, mock_setting):
        self.presenter.calibration_notifier = MagicMock()
        self.view.get_new_checked.return_value = False
        self.view.get_load_checked.return_value = True
        mock_valid_path.return_value = False
        self.presenter.current_calibration = mock.create_autospec(CalibrationInfo())

        self.presenter.on_calibrate_clicked()

        self.presenter.current_calibration.set_calibration_from_prm_fname.assert_not_called()
        self.presenter.calibration_notifier.notify_subscribers.assert_not_called()
        mock_setting.assert_not_called()
Esempio n. 5
0
    def test_create_output_files_makes_savdir_and_saves_both_banks(
            self, mock_write_prm, mock_save_nxs, mock_exists, mock_mkdir,
            mock_copy):
        mock_exists.return_value = False  # make new directory
        calibration = CalibrationInfo(
        )  # easier to work with real calibration info object here
        prm_name = "ENGINX_193749_all_banks.prm"
        calibration.set_calibration_from_prm_fname(prm_name)
        calibration.set_calibration_table("cal_table")
        save_dir = "savedir"

        create_output_files(save_dir, calibration, "ws")

        mock_mkdir.assert_called_once_with(save_dir)
        self.calibration.save_grouping_workspace.assert_not_called(
        )  # only called if not bank data
        prm_fpath = path.join(save_dir, prm_name)
        write_prm_calls = [
            call("ws", prm_fpath),
            call("ws", prm_fpath.replace("all_banks", "bank_1"),
                 spec_nums=[0]),
            call("ws", prm_fpath.replace("all_banks", "bank_2"), spec_nums=[1])
        ]
        mock_write_prm.assert_has_calls(write_prm_calls)
        nxs_fpath = prm_fpath.replace(".prm", ".nxs")
        mock_save_nxs.assert_called_once_with(InputWorkspace="cal_table",
                                              Filename=nxs_fpath)
        copy_calls = [
            call(nxs_fpath, nxs_fpath.replace("all_banks", "bank_1")),
            call(nxs_fpath, nxs_fpath.replace("all_banks", "bank_2"))
        ]
        mock_copy.assert_has_calls(copy_calls)
    def test_update_calibration_from_view_no_cropping(self):
        self.view.get_load_checked.return_value = False
        self.view.get_crop_checked.return_value = False
        self.presenter.instrument = "ENGINX"
        self.view.get_sample_filename.return_value = "193749"
        self.presenter.current_calibration = mock.create_autospec(CalibrationInfo())

        self.presenter.update_calibration_from_view()

        self.presenter.current_calibration.set_calibration_paths.assert_called_once_with("ENGINX", "193749")
        self.presenter.current_calibration.set_group.assert_called_once_with(GROUP.BOTH)
        self.presenter.current_calibration.set_cal_file.assert_not_called()
        self.presenter.current_calibration.set_spectra_list.assert_not_called()
Esempio n. 7
0
    def __init__(self,
                 vanadium_run: str,
                 focus_runs: Sequence[str],
                 save_dir: str,
                 full_inst_calib_path: str,
                 prm_path: Optional[str] = None,
                 ceria_run: Optional[str] = None,
                 group: Optional[GROUP] = None,
                 calfile_path: Optional[str] = None,
                 spectrum_num: Optional[str] = None) -> None:

        # init attributes
        self.calibration = CalibrationInfo()
        self.van_run = vanadium_run
        self.focus_runs = focus_runs
        self.save_dir = save_dir
        # Load custom full inst calib if supplied (needs to be in ADS)
        try:
            self.full_calib_ws = Load(full_inst_calib_path,
                                      OutputWorkspace="full_inst_calib")
        except ValueError as e:
            logger.error("Unable to load calibration file " +
                         full_inst_calib_path + ". Error: " + str(e))

        # setup CalibrationInfo object
        if prm_path:
            self.calibration.set_calibration_from_prm_fname(
                prm_path)  # to load existing calibration
        elif ceria_run and group:
            # make new calibration
            self.calibration.set_group(group)
            self.calibration.set_calibration_paths("ENGINX", ceria_run)
            if group == GROUP.CUSTOM and calfile_path:
                self.calibration.set_cal_file(calfile_path)
            elif group == GROUP.CROPPED and spectrum_num:
                self.calibration.set_spectra_list(spectrum_num)
Esempio n. 8
0
    def __init__(self, model, view):
        self.model = model
        self.view = view
        self.worker = None
        self.calibration_observer = CalibrationObserver(self)

        # Observable Setup
        self.focus_run_notifier = GenericObservable()

        # Connect view signals to local methods.
        self.view.set_on_focus_clicked(self.on_focus_clicked)
        self.view.set_enable_controls_connection(
            self.set_focus_controls_enabled)

        # Variables from other GUI tabs.
        self.current_calibration = CalibrationInfo()
        self.instrument = "ENGINX"
        self.rb_num = None

        last_van_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP,
                                    output_settings.ENGINEERING_PREFIX,
                                    "last_vanadium_run")
        if last_van_path:
            self.view.set_van_file_text_with_search(last_van_path)
    def test_calibrate_clicked_load_valid_path(self, mock_valid_path, mock_setting):
        self.presenter.calibration_notifier = MagicMock()
        self.view.get_new_checked.return_value = False
        self.view.get_load_checked.return_value = True
        prm_filepath = "path/to/prm.prm"
        self.view.get_path_filename.return_value = prm_filepath
        mock_valid_path.return_value = True
        self.presenter.current_calibration = mock.create_autospec(CalibrationInfo())

        self.presenter.on_calibrate_clicked()

        self.model.load_existing_calibration_files.assert_called_with(self.presenter.current_calibration)
        self.presenter.current_calibration.set_calibration_from_prm_fname.assert_called_with(prm_filepath)
        self.presenter.calibration_notifier.notify_subscribers.assert_called_once()
        mock_setting.assert_called_once()
Esempio n. 10
0
 def setUp(self):
     self.calibration = create_autospec(CalibrationInfo())
     self.calibration.is_valid.return_value = True
     self.calibration.get_instrument.return_value = "ENGINX"
     self.calibration.get_group_suffix.return_value = "all_banks"
     self.calibration.get_foc_ws_suffix.return_value = "bank"
Esempio n. 11
0
class CalibrationPresenter(object):
    def __init__(self, model, view):
        self.model = model
        self.view = view
        self.worker = None
        self.calibration_notifier = self.CalibrationNotifier(self)

        self.current_calibration = CalibrationInfo()

        self.connect_view_signals()

        # Main Window State Variables
        self.instrument = "ENGINX"
        self.rb_num = None

        # Cropping Options
        self.cropping_widget = CroppingPresenter(parent=self.view, view=self.view.get_cropping_widget())
        self.show_cropping(False)

    def connect_view_signals(self):
        self.view.set_on_calibrate_clicked(self.on_calibrate_clicked)
        self.view.set_enable_controls_connection(self.set_calibrate_controls_enabled)
        self.view.set_update_field_connection(self.set_field_value)
        self.view.set_on_radio_new_toggled(self.set_create_new_enabled)
        self.view.set_on_radio_existing_toggled(self.set_load_existing_enabled)
        self.view.set_on_check_cropping_state_changed(self.show_cropping)

    def update_calibration_from_view(self):
        self.current_calibration.clear()
        if self.view.get_load_checked():
            # loading calibration from path to .prm
            self.current_calibration.set_calibration_from_prm_fname(self.view.get_path_filename())
        else:
            # make a new calibration
            sample_file = self.view.get_sample_filename()
            self.current_calibration.set_calibration_paths(self.instrument, sample_file)
            # set group and any additional parameters needed
            if self.view.get_crop_checked():
                self.current_calibration.set_group(self.cropping_widget.get_group())
                if self.current_calibration.group == GROUP.CUSTOM:
                    self.current_calibration.set_cal_file(self.cropping_widget.get_custom_calfile())
                elif self.current_calibration.group == GROUP.CROPPED:
                    self.current_calibration.set_spectra_list(self.cropping_widget.get_custom_spectra())
            else:
                # default if no cropping
                self.current_calibration.set_group(GROUP.BOTH)

    def on_calibrate_clicked(self):
        if self.view.get_new_checked() and self._validate():
            self.update_calibration_from_view()
            self.start_calibration_worker(self.view.get_plot_output())
        elif self.view.get_load_checked() and self.validate_path():
            self.update_calibration_from_view()
            self.model.load_existing_calibration_files(self.current_calibration)
            self._notify_updated_calibration()

    def start_calibration_worker(self, plot_output):
        """
        Calibrate the data in a separate thread so as to not freeze the GUI.
        """
        self.worker = AsyncTask(self.model.create_new_calibration,
                                (self.current_calibration, self.rb_num, plot_output),
                                error_cb=self._on_error,
                                success_cb=self._on_success)
        self.set_calibrate_controls_enabled(False)
        self.worker.start()

    def _on_error(self, error_info):
        logger.error(str(error_info))
        self.emit_enable_button_signal()

    def _on_success(self, success_info):
        self._notify_updated_calibration()
        self.emit_enable_button_signal()

    def _notify_updated_calibration(self):
        self.calibration_notifier.notify_subscribers(self.current_calibration)
        set_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX,
                    "last_calibration_path", self.current_calibration.get_prm_filepath())

    def set_field_value(self):
        self.view.set_sample_text(self.current_calibration.get_sample())

    def load_last_calibration(self) -> None:
        """
        Loads the most recently created or loaded calibration into the interface instance. To be used on interface
        startup.
        """
        last_cal_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX,
                                    "last_calibration_path")
        if last_cal_path:
            self.view.set_load_checked(True)
            self.view.set_file_text_with_search(last_cal_path)

    def set_instrument_override(self, instrument):
        instrument = INSTRUMENT_DICT[instrument]
        self.view.set_instrument_override(instrument)
        self.instrument = instrument

    def set_rb_num(self, rb_num):
        self.rb_num = rb_num

    def _validate(self):
        # Do nothing if run numbers are invalid or view is searching.
        if self.view.is_searching():
            create_error_message(self.view, "Mantid is searching for data files. Please wait.")
            return False
        if not self.view.get_sample_valid():
            create_error_message(self.view, "Check run numbers/path is valid.")
            return False
        if self.view.get_crop_checked():
            if self.cropping_widget.get_custom_calfile_enabled() and not self.cropping_widget.is_calfile_valid():
                create_error_message(self.view, "Check custom calfile path is valid.")
                return False
            if self.cropping_widget.get_custom_spectra_enabled() and not self.cropping_widget.is_spectra_valid():
                create_error_message(self.view, "Check custom spectra are valid.")
                return False
        return True

    def validate_path(self):
        return self.view.get_path_valid()

    def emit_enable_button_signal(self):
        self.view.sig_enable_controls.emit(True)

    def set_calibrate_controls_enabled(self, enabled):
        self.view.set_calibrate_button_enabled(enabled)

    def set_create_new_enabled(self, enabled):
        self.view.set_sample_enabled(enabled)
        if enabled:
            self.set_calibrate_button_text("Calibrate")
            self.view.set_check_plot_output_enabled(True)
            self.view.set_check_cropping_enabled(True)
            self.find_files()

    def set_load_existing_enabled(self, enabled):
        self.view.set_path_enabled(enabled)
        if enabled:
            self.set_calibrate_button_text("Load")
            self.view.set_check_plot_output_enabled(False)
            self.view.set_check_cropping_enabled(False)
            self.view.set_check_cropping_checked(False)

    def set_calibrate_button_text(self, text):
        self.view.set_calibrate_button_text(text)

    def find_files(self):
        self.view.find_sample_files()

    def show_cropping(self, show):
        self.view.set_cropping_widget_visibility(show)

    # -----------------------
    # Observers / Observables
    # -----------------------
    class CalibrationNotifier(Observable):
        def __init__(self, outer):
            Observable.__init__(self)
            self.outer = outer

        def notify_subscribers(self, *args, **kwargs):
            Observable.notify_subscribers(self, *args)
Esempio n. 12
0
 def setUp(self):
     self.model = CalibrationModel()
     self.calibration_info = create_autospec(CalibrationInfo())
     mock.NonCallableMock.assert_any_call_partial = assert_any_call_partial
Esempio n. 13
0
class EnginX:
    def __init__(self,
                 vanadium_run: str,
                 focus_runs: Sequence[str],
                 save_dir: str,
                 full_inst_calib_path: str,
                 prm_path: Optional[str] = None,
                 ceria_run: Optional[str] = None,
                 group: Optional[GROUP] = None,
                 calfile_path: Optional[str] = None,
                 spectrum_num: Optional[str] = None) -> None:

        # init attributes
        self.calibration = CalibrationInfo()
        self.van_run = vanadium_run
        self.focus_runs = focus_runs
        self.save_dir = save_dir
        # Load custom full inst calib if supplied (needs to be in ADS)
        try:
            self.full_calib_ws = Load(full_inst_calib_path,
                                      OutputWorkspace="full_inst_calib")
        except ValueError as e:
            logger.error("Unable to load calibration file " +
                         full_inst_calib_path + ". Error: " + str(e))

        # setup CalibrationInfo object
        if prm_path:
            self.calibration.set_calibration_from_prm_fname(
                prm_path)  # to load existing calibration
        elif ceria_run and group:
            # make new calibration
            self.calibration.set_group(group)
            self.calibration.set_calibration_paths("ENGINX", ceria_run)
            if group == GROUP.CUSTOM and calfile_path:
                self.calibration.set_cal_file(calfile_path)
            elif group == GROUP.CROPPED and spectrum_num:
                self.calibration.set_spectra_list(spectrum_num)

    def calibrate(self, plot_output: bool) -> None:
        if self.calibration.get_prm_filepath():
            self.calibration.load_relevant_calibration_files(
            )  # loading existing calibration files
        else:
            create_new_calibration(self.calibration,
                                   rb_num=None,
                                   plot_output=plot_output,
                                   save_dir=self.save_dir,
                                   full_calib=self.full_calib_ws)

    def focus(self, plot_output: bool) -> None:
        if self.calibration.is_valid() and self.van_run:
            focus_run(self.focus_runs,
                      self.van_run,
                      plot_output,
                      rb_num=None,
                      calibration=self.calibration,
                      save_dir=self.save_dir,
                      full_calib=self.full_calib_ws)

    def main(self, plot_cal: bool = False, plot_foc: bool = False):
        self.calibrate(plot_cal)
        self.focus(plot_foc)
Esempio n. 14
0
class FocusPresenter(object):
    def __init__(self, model, view):
        self.model = model
        self.view = view
        self.worker = None
        self.calibration_observer = CalibrationObserver(self)

        # Observable Setup
        self.focus_run_notifier = GenericObservable()

        # Connect view signals to local methods.
        self.view.set_on_focus_clicked(self.on_focus_clicked)
        self.view.set_enable_controls_connection(
            self.set_focus_controls_enabled)

        # Variables from other GUI tabs.
        self.current_calibration = CalibrationInfo()
        self.instrument = "ENGINX"
        self.rb_num = None

        last_van_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP,
                                    output_settings.ENGINEERING_PREFIX,
                                    "last_vanadium_run")
        if last_van_path:
            self.view.set_van_file_text_with_search(last_van_path)

    def add_focus_subscriber(self, obs):
        self.focus_run_notifier.add_subscriber(obs)

    def on_focus_clicked(self):
        if not self._validate():
            return
        focus_paths = self.view.get_focus_filenames()
        van_path = self.view.get_vanadium_filename()
        if self._number_of_files_warning(focus_paths):
            self.start_focus_worker(focus_paths, van_path,
                                    self.view.get_plot_output(), self.rb_num,
                                    self.current_calibration)
        van_run = self.view.get_vanadium_run()
        set_setting(output_settings.INTERFACES_SETTINGS_GROUP,
                    output_settings.ENGINEERING_PREFIX, "last_vanadium_run",
                    van_run)

    def start_focus_worker(self, focus_paths: list, van_path: str,
                           plot_output: bool, rb_num: str,
                           calibration: CalibrationInfo) -> None:
        """
        Focus data in a separate thread to stop the main GUI from hanging.
        :param focus_paths: List of paths to the files containing the data to focus.
        :param plot_output: True if the output should be plotted.
        :param rb_num: The RB Number from the main window (often an experiment id)
        :param regions_dict: Dictionary containing the regions to focus over, mapping region_name -> grouping_ws_name
        """
        self.worker = AsyncTask(
            self.model.focus_run,
            (focus_paths, van_path, plot_output, rb_num, calibration),
            error_cb=self._on_worker_error,
            finished_cb=self._on_worker_success)
        self.set_focus_controls_enabled(False)
        self.worker.start()

    def _on_worker_success(self):
        self.emit_enable_button_signal()
        self.focus_run_notifier.notify_subscribers(
            self.model.get_last_focused_files())

    def set_instrument_override(self, instrument):
        instrument = INSTRUMENT_DICT[instrument]
        self.view.set_instrument_override(instrument)
        self.instrument = instrument

    def set_rb_num(self, rb_num):
        self.rb_num = rb_num

    def _validate(self):
        """
        Ensure that the worker is ready to be started.
        :return: True if the worker can be started safely.
        """
        if self.view.is_searching():
            create_error_message(
                self.view, "Mantid is searching for data files. Please wait.")
            return False
        if not self.view.get_focus_valid():
            create_error_message(self.view, "Check run numbers/path is valid.")
            return False
        if not self.view.get_vanadium_valid():
            create_error_message(self.view,
                                 "Check vanadium run number/path is valid.")
            return False
        if not self.current_calibration.is_valid():
            create_error_message(
                self.view,
                "Create or Load a calibration via the Calibration tab before focusing."
            )
            return False
        if self.current_calibration.get_instrument() != self.instrument:
            create_error_message(
                self.view,
                "Please make sure the selected instrument matches instrument for the current calibration.\n"
                "The instrument for the current calibration is: " +
                self.current_calibration.get_instrument())
            return False
        return True

    def _number_of_files_warning(self, paths):
        if len(
                paths
        ) > 10:  # Just a guess on the warning for now. May change in future.
            response = QMessageBox.warning(
                self.view, 'Engineering Diffraction - Warning',
                'You are attempting to focus {} workspaces. This may take some time.\n\n Would you like to continue?'
                .format(len(paths)), QMessageBox.Ok | QMessageBox.Cancel)
            return response == QMessageBox.Ok
        else:
            return True

    def _on_worker_error(self, error_info):
        logger.error(str(error_info))
        self.emit_enable_button_signal()

    def set_focus_controls_enabled(self, enabled):
        self.view.set_focus_button_enabled(enabled)
        self.view.set_plot_output_enabled(enabled)

    def emit_enable_button_signal(self):
        self.view.sig_enable_controls.emit(True)

    def update_calibration(self, calibration):
        """
        Update the current calibration following an call from a CalibrationNotifier
        :param calibration: The new current calibration.
        """
        self.current_calibration = calibration
        region_text = calibration.get_group_description()
        self.view.set_region_display_text(region_text)