Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
abstract_inst.py 9.68 KiB
from __future__ import (absolute_import, division, print_function)

import os
from abc import ABCMeta, abstractmethod

from six import add_metaclass

from isis_powder.routines import calibrate, focus, common


# This class provides common hooks for instruments to override
# if they want to define the behaviour of the hook. Otherwise it
# returns the object passed in without manipulating it as a default


@add_metaclass(ABCMeta)
class AbstractInst(object):
    def __init__(self, user_name=None, calibration_dir=None, output_dir=None):
        # ----- Properties common to ALL instruments -------- #
        if user_name is None:
            raise ValueError("A user name must be specified")
        self._user_name = user_name
        self._calibration_dir = calibration_dir
        self._output_dir = output_dir

    @property
    def calibration_dir(self):
        return self._calibration_dir

    @property
    def raw_data_dir(self):
        return self._raw_data_dir

    @property
    def output_dir(self):
        return self._output_dir

    @property
    def user_name(self):
        return self._user_name

    def _create_calibration_vanadium(self, vanadium_runs, empty_runs,
                                     do_absorb_corrections=True, gen_absorb_correction=False):
        """
        Creates a vanadium calibration - should be called by the concrete instrument
        :param vanadium_runs: The vanadium run or run in range (depending on instrument) to process
        :param empty_runs: The empty run to process
        :param do_absorb_corrections: Set to true if absorption corrections should be applied
        :param gen_absorb_correction: Set to true if absorption corrections should be recalculated
        :return: d_spacing focused vanadium group
        """
        return calibrate.create_van(instrument=self, van=vanadium_runs, empty=empty_runs,
                                    absorb=do_absorb_corrections, gen_absorb=gen_absorb_correction)

    def _focus(self, run_number, input_batching, do_van_normalisation):
        """
        Focuses the user specified run - should be called by the concrete instrument
        :param run_number: The run number(s) to be processed
        :param input_batching: How to process the runs specified if a range. E.g. Individual/Batched. See common enums.
        :param do_van_normalisation: True to divide by the vanadium run, false to not.
        :return:
        """
        return focus.focus(run_number=run_number, input_batching=input_batching,
                           perform_vanadium_norm=do_van_normalisation, instrument=self)

    # Mandatory overrides

    @abstractmethod
    def get_run_details(self, run_number_string):
        """
        Returns a RunDetails object with various properties related to the current run set
        :param run_number_string: The run number to look up the properties of
        :return: A RunDetails object containing attributes relevant to that run_number_string
        """
        pass

    @staticmethod
    @abstractmethod
    def generate_input_file_name(run_number):
        """
        Generates a name which Mantid uses within Load to find the file.
        :param run_number: The run number to convert into a valid format for Mantid
        :return: A filename that will allow Mantid to find the correct run for that instrument.
        """
        pass

    @abstractmethod
    def generate_output_file_name(self, run_number_string):
        """
        Generates the filename which is used to uniquely identify and save the workspace. This should include any
        distinguishing properties such as if absorption corrections were performed.
        :param run_number_string: The run string to uniquely identify the run
        :return: The file name which identifies the run and appropriate parameter settings
        """
        raise NotImplementedError("Output names not implemented")

    @abstractmethod
    def spline_vanadium_ws(self, focused_vanadium_banks):
        """
        Takes a background spline of the list of processed vanadium banks
        :param focused_vanadium_banks: The list processed (and cropped) vanadium banks to take a spline of
        :return: The splined vanadium workspaces as a list
        """
        return None

    # Optional overrides


    @abstractmethod
    def apply_absorb_corrections(self, run_details, van_ws, gen_absorb=False):
        """
        Generates vanadium absorption corrections to compensate for the container
        :param van_ws: A reference vanadium workspace to match the binning of or correct
        :return: A workspace containing the corrections
        """
        raise NotImplementedError("Not implemented for this instrument yet")

    def attenuate_workspace(self, input_workspace):
        """
        Applies an attenuation correction to the workspace
        :param input_workspace: The workspace to correct
        :return: The corrected workspace
        """
        return input_workspace

    @staticmethod
    def can_auto_gen_vanadium_cal():
        """
        Can be overridden and returned true by instruments who can automatically run generate vanadium calculation
        if the splines cannot be found during the focus routine
        :return: False by default, True by instruments who can automatically generate these
        """
        return False

    def crop_banks_to_user_tof(self, focused_banks):
        """
        Crops to a user specified TOF range on a bank-by-bank basis. This is called after focusing a sample and
        performing the various corrections required
        :param focused_banks: The processed banks as a list to be cropped
        :return: A list of cropped banks
        """
        return focused_banks

    def crop_raw_to_expected_tof_range(self, ws_to_crop):
        """
        Crops the raw data to a sensible TOF range before processing. This is so that instruments (e.g. PEARL)
        who capture double the data only process one 'window' of data at a time.
        :param ws_to_crop: The raw workspace to crop in TOF
        :return: The cropped workspace ready for processing
        """
        return ws_to_crop

    def crop_van_to_expected_tof_range(self, van_ws_to_crop):
        """
        Crops the vanadium workspace to a user specified TOF, this is to prevent the b-spline being affected by
        values after diffraction which are set to 0 as there was no data for that TOF.
        :param van_ws_to_crop: A list of focused vanadium banks to crop
        :return: A list of cropped vanadium workspace banks
        """
        return van_ws_to_crop

    def generate_auto_vanadium_calibration(self, run_details):
        """
        Used by focus if a vanadium spline was not found to automatically generate said spline if the instrument
        has indicated support by overriding can_auto_gen_vanadium_cal
        :param run_details: The run details of the current run
        :return: None
        """
        # If the instrument overrides can_auto_gen_vanadium_cal it needs to implement this method to perform the
        # automatic calibration
        raise NotImplementedError("Automatic vanadium corrections have not been implemented for this instrument.")

    def get_monitor_spectra_index(self, run_number):
        """
        Returns the spectra number a monitor is located at
        :param run_number: The run number to locate the monitor spectra of
        :return: The monitor spectra for the current workspace
        """
        return str()

    def normalise_ws_current(self, ws_to_correct, run_details=None):
        """
        Normalises the workspace by the beam current at the time it was taken
        :param ws_to_correct: The workspace to normalise the current of
        :param run_details: The run details associated to the run
        :return: The normalised workspace
        """
        return None

    def output_focused_ws(self, processed_spectra, run_details, output_mode=None):
        """
        Takes a list of focused workspace banks and saves them out in an instrument appropriate format.
        :param processed_spectra: The list of workspace banks to save out
        :param run_details: The run details associated with this run
        :param output_mode: Optional - Sets additional saving/grouping behaviour depending on the instrument
        :return: d-spacing group of the processed output workspaces
        """
        return None

    # Steps applicable to all instruments

    def generate_out_file_paths(self, run_details, output_directory=None):
        """
        Generates the various output paths and file names to be used during saving or as workspace names
        :param run_details: The run details associated with this run
        :param output_directory: The output directory to use as part of the output path
        :return: A dictionary containing the various output paths and generated output name
        """
        if not output_directory:
            output_directory = os.path.join(self._output_dir, run_details.label, self._user_name)
        file_name = str(self.generate_output_file_name(run_number_string=run_details.run_number))
        nxs_file = os.path.join(output_directory, (file_name + ".nxs"))
        gss_file = os.path.join(output_directory, (file_name + ".gsas"))
        tof_xye_file = os.path.join(output_directory, (file_name + "_tof_xye.dat"))
        d_xye_file = os.path.join(output_directory, (file_name + "_d_xye.dat"))
        out_name = file_name

        out_file_names = {"nxs_filename": nxs_file,
                          "gss_filename": gss_file,
                          "tof_xye_filename": tof_xye_file,
                          "dspacing_xye_filename": d_xye_file,
                          "output_name": out_name,
                          "output_folder": output_directory}

        return out_file_names