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
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)
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()
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)
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]
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'.")
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)
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