Example #1
0
def _spectra_from_string(fit_mode, spectra):
    if fit_mode == 'bank':
        return _parse_spectra_bank(spectra)
    else:
        if spectra == "forward":
            return "{0}-{1}".format(*VESUVIO().forward_spectra)
        elif spectra == "backward":
            return "{0}-{1}".format(*VESUVIO().backward_spectra)
        else:
            return spectra
Example #2
0
def _parse_spectra_bank(spectra_bank):
    if spectra_bank == "forward":
        bank_ranges = VESUVIO().forward_banks
    elif spectra_bank == "backward":
        bank_ranges = VESUVIO()._instrument.backward_banks
    else:
        raise ValueError("Fitting by bank requires selecting either 'forward' or 'backward' "
                         "for the spectra to load")
    bank_ranges = ["{0}-{1}".format(x, y) for x, y in bank_ranges]
    return ";".join(bank_ranges)
Example #3
0
 def __init__(self, diff_mode, fit_mode, param_file, rebin_params=None, load_log_files=True):
     self.fit_mode = fit_mode
     self._diff_mode = self._parse_diff_mode(diff_mode)
     self._param_file = param_file
     self._rebin_params = rebin_params
     self._load_log_files = load_log_files
     self._instrument = VESUVIO()
Example #4
0
    def PyExec(self):
        """PyExec is defined by base. It sets the instrument and calls this method
        """
        self._INST = VESUVIO()
        tof_data = self.getProperty("InputWorkspace").value

        reduced_chi_square, fit_params, fit_data = self._fit_tof(tof_data)
        self.setProperty("OutputWorkspace", fit_data)
        self.setProperty("FitParameters", fit_params)
        self.setProperty("Chi2", reduced_chi_square)
Example #5
0
def load_and_crop_data(runs, spectra, ip_file, diff_mode='single',
                       fit_mode='spectra', rebin_params=None):
    """
    @param runs The string giving the runs to load
    @param spectra A list of spectra to load
    @param ip_file A string denoting the IP file
    @param diff_mode Either 'double' or 'single'
    @param fit_mode If bank then the loading is changed to summing each bank to a separate spectrum
    @param rebin_params Rebin parameter string to rebin data by (no rebin if None)
    """
    instrument = VESUVIO()
    load_banks = (fit_mode == 'bank')
    output_name = _create_tof_workspace_suffix(runs, spectra)

    if load_banks:
        sum_spectra = True
        if spectra == "forward":
            bank_ranges = instrument.forward_banks
        elif spectra == "backward":
            bank_ranges = instrument.backward_banks
        else:
            raise ValueError("Fitting by bank requires selecting either 'forward' or 'backward' "
                             "for the spectra to load")
        bank_ranges = ["{0}-{1}".format(x, y) for x, y in bank_ranges]
        spectra = ";".join(bank_ranges)
    else:
        sum_spectra = False
        if spectra == "forward":
            spectra = "{0}-{1}".format(*instrument.forward_spectra)
        elif spectra == "backward":
            spectra = "{0}-{1}".format(*instrument.backward_spectra)

    if diff_mode == "double":
        diff_mode = "DoubleDifference"
    else:
        diff_mode = "SingleDifference"

    kwargs = {"Filename": runs,
              "Mode": diff_mode, "InstrumentParFile": ip_file,
              "SpectrumList": spectra, "SumSpectra": sum_spectra,
              "OutputWorkspace": output_name}
    full_range = ms.LoadVesuvio(**kwargs)
    tof_data = ms.CropWorkspace(InputWorkspace=full_range,
                                XMin=instrument.tof_range[0],
                                XMax=instrument.tof_range[1],
                                OutputWorkspace=output_name)

    if rebin_params is not None:
        tof_data = ms.Rebin(InputWorkspace=tof_data,
                            OutputWorkspace=output_name,
                            Params=rebin_params)

    return tof_data
 def _get_properties(self):
     self._input_ws = self.getProperty("InputWorkspace").value
     self._container_ws = self.getPropertyValue("ContainerWorkspace")
     self._spec_idx = self.getProperty("WorkspaceIndex").value
     self._output_ws = self.getPropertyValue("OutputWorkspace")
     self._correction_wsg = self.getPropertyValue("CorrectionWorkspaces")
     self._corrected_wsg = self.getPropertyValue("CorrectedWorkspaces")
     self._linear_fit_table = self.getPropertyValue("LinearFitResult")
     self._masses = self.getProperty("Masses").value
     self._index_to_symbol_map = self.getProperty(
         "MassIndexToSymbolMap").value
     self._hydrogen_constraints = self.getProperty(
         "HydrogenConstraints").value
     spec_no = self._input_ws.getSpectrum(self._spec_idx).getSpectrumNo()
     back_spectra = VESUVIO().backward_spectra
     self._back_scattering = back_spectra[0] <= spec_no <= back_spectra[1]
Example #7
0
def is_back_scattering_spectra(spectra):
    """
    Checks whether the specified spectra denotes back scattering spectra.

    :param spectra: The spectra to check.
    :return:        True if the specified spectra denotes back scattering
                    spectra.
    """
    if spectra == 'forward':
        return False
    elif spectra == 'backward':
        return True
    else:
        try:
            first_spectrum = int(spectra.split("-")[0])
            return any([lower <= first_spectrum <= upper for lower, upper in VESUVIO().backward_banks])
        except:
            raise RuntimeError("Invalid value given for spectrum range: Range must "
                               "either be 'forward', 'backward' or specified with "
                               "the syntax 'a-b'.")
Example #8
0
def fit_tof(runs, flags, iterations=1, convergence_threshold=None):
    """
    The main entry point for user scripts fitting in TOF.

    :param runs: A string specifying the runs to process, or a workspace containing
                 the loaded runs
    :param flags: A dictionary of flags to control the processing
    :param iterations: Maximum number of iterations to perform
    :param convergence_threshold: Maximum difference in the cost
                                  function at which the parameters are accepted
                                  to have converged
    :return: Tuple of (fitted workspace, fitted params, number of iterations
             performed)
    """
    if iterations < 1:
        raise ValueError('Must perform at least one iteration')

    # Load
    fit_mode = flags['fit_mode']
    back_banks = VESUVIO().backward_banks

    if isinstance(runs, MatrixWorkspace):
        sample_data = runs
        flags['runs'] = runs.getName()
        flags['spectra'] = sample_data.getAxis(0).extractValues()
        flags['back_scattering'] = any([
            lower <= flags['spectra'][0] <= upper
            for lower, upper in back_banks
        ])
    else:
        spectra = flags['spectra']
        sample_data = load_and_crop_data(runs, spectra, flags['ip_file'],
                                         flags['diff_mode'], fit_mode,
                                         flags.get('bin_parameters', None))
        flags['runs'] = runs
        if spectra == 'backward' or spectra == 'forward':
            flags['back_scattering'] = spectra == 'backward'
        else:
            try:
                first_spec = int(spectra.split("-")[0])
                flags['back_scattering'] = any([
                    lower <= first_spec <= upper for lower, upper in back_banks
                ])
            except:
                raise RuntimeError(
                    "Invalid value given for spectrum range: Range must either be 'forward', "
                    "'backward' or specified with the syntax 'a-b'.")

    # Load container runs if provided
    container_data = None
    if flags.get('container_runs', None) is not None:

        if isinstance(flags['container_runs'], MatrixWorkspace):
            container_data = flags['container_runs']
        else:
            container_data = load_and_crop_data(
                flags['container_runs'], spectra,
                flags['ip_file'], flags['diff_mode'], fit_mode,
                flags.get('bin_parameters', None))

    return fit_tof_impl(sample_data, container_data, flags, iterations,
                        convergence_threshold)
Example #9
0
def fit_tof(runs, flags, iterations=1, convergence_threshold=None):
    """
    The main entry point for user scripts fitting in TOF.

    :param runs: A string specifying the runs to process
    :param flags: A dictionary of flags to control the processing
    :param iterations: Maximum number of iterations to perform
    :param convergence_threshold: Maximum difference in the cost
                                  function at which the parameters are accepted
                                  to have converged
    :return: Tuple of (fitted workspace, fitted params, number of iterations
             performed)
    """
    if iterations < 1:
        raise ValueError('Must perform at least one iteration')

    # Load
    spectra = flags['spectra']
    fit_mode = flags['fit_mode']
    sample_data = load_and_crop_data(runs, spectra, flags['ip_file'],
                                     flags['diff_mode'], fit_mode,
                                     flags.get('bin_parameters', None))

    # Load container runs if provided
    container_data = None
    if flags.get('container_runs', None) is not None:
        container_data = load_and_crop_data(flags['container_runs'], spectra,
                                            flags['ip_file'],
                                            flags['diff_mode'], fit_mode,
                                            flags.get('bin_parameters', None))

    # Check if multiple scattering flags have been defined
    if 'ms_flags' in flags:

        # Check if hydrogen constraints have been defined
        if 'HydrogenConstraints' in flags['ms_flags']:
            flags['ms_flags']['HydrogenConstraints'] = \
                _parse_ms_hydrogen_constraints(flags['ms_flags']['HydrogenConstraints'])
        else:
            flags['ms_flags']['HydrogenConstraints'] = dict()
    else:
        raise RuntimeError(
            "Multiple scattering flags not provided. Set the ms_flag, 'ms_enabled' "
            "to false, in order to disable multiple scattering corrections.")

    if spectra == 'backward' or spectra == 'forward':
        flags['back_scattering'] = spectra == 'backward'
    else:
        try:
            first_spec = int(spectra.split("-")[0])
            back_banks = VESUVIO().backward_banks
            flags['back_scattering'] = any(
                [lower <= first_spec <= upper for lower, upper in back_banks])
        except:
            raise RuntimeError(
                "Invalid value given for spectrum range: Range must either be 'forward', "
                "'backward' or specified with the syntax 'a-b'.")

    last_results = None

    exit_iteration = 0

    index_to_symbol_map = filter(lambda x: 'symbol' in x[1],
                                 enumerate(flags['masses']))
    index_to_symbol_map = {str(k): v['symbol'] for k, v in index_to_symbol_map}

    hydrogen_indices = set()
    if flags['back_scattering']:
        hydrogen_indices = {
            int(k)
            for k, _ in filter(lambda x: x[1] == 'H',
                               index_to_symbol_map.items())
        }

        symbols = set()
        for symbol in flags['ms_flags']['HydrogenConstraints']:
            symbols.add(symbol)
        for symbol in index_to_symbol_map.values():
            symbols.discard(symbol)

        if symbols:
            raise RuntimeError(
                "HydrogenConstraints contains references to the following,"
                " undefined masses: " + ','.join(symbols))
    flags['index_to_symbol_map'] = index_to_symbol_map

    for iteration in range(1, iterations + 1):
        iteration_flags = copy.deepcopy(flags)
        iteration_flags['iteration'] = iteration

        if last_results is not None:
            iteration_flags['masses'] = _update_masses_from_params(
                copy.deepcopy(flags['masses']),
                last_results[2],
                ignore_indices=hydrogen_indices)

        print("=== Iteration {0} out of a possible {1}".format(
            iteration, iterations))
        results = fit_tof_iteration(sample_data, container_data, runs,
                                    iteration_flags)
        exit_iteration += 1

        if last_results is not None and convergence_threshold is not None:
            last_chi2 = np.array(last_results[3])
            chi2 = np.array(results[3])
            chi2_delta = last_chi2 - chi2
            max_chi2_delta = np.abs(np.max(chi2_delta))
            print("Cost function change: {0}".format(max_chi2_delta))

            if max_chi2_delta <= convergence_threshold:
                print(
                    "Stopped at iteration {0} due to minimal change in cost function"
                    .format(exit_iteration))
                last_results = results
                break

        last_results = results

    return last_results[0], last_results[2], last_results[3], exit_iteration