-
Tom Titcombe authored
Remove optional flag for moving workspace. Always move workspace Refs #23960
Tom Titcombe authoredRemove optional flag for moving workspace. Always move workspace Refs #23960
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
batch_execution.py 65.51 KiB
# 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 copy import deepcopy
from mantid.api import AnalysisDataService, WorkspaceGroup
from sans.common.general_functions import (create_managed_non_child_algorithm, create_unmanaged_algorithm,
get_output_name, get_base_name_from_multi_period_name, get_transmission_output_name)
from sans.common.enums import (SANSDataType, SaveType, OutputMode, ISISReductionMode, DataType)
from sans.common.constants import (TRANS_SUFFIX, SANS_SUFFIX, ALL_PERIODS,
LAB_CAN_SUFFIX, LAB_CAN_COUNT_SUFFIX, LAB_CAN_NORM_SUFFIX,
HAB_CAN_SUFFIX, HAB_CAN_COUNT_SUFFIX, HAB_CAN_NORM_SUFFIX,
LAB_SAMPLE_SUFFIX, HAB_SAMPLE_SUFFIX,
REDUCED_HAB_AND_LAB_WORKSPACE_FOR_MERGED_REDUCTION,
CAN_COUNT_AND_NORM_FOR_OPTIMIZATION,
CAN_AND_SAMPLE_WORKSPACE)
from sans.common.file_information import (get_extension_for_file_type, SANSFileInformationFactory)
from sans.state.data import StateData
try:
import mantidplot
except (Exception, Warning):
mantidplot = None
# this should happen when this is called from outside Mantidplot and only then,
# the result is that attempting to plot will raise an exception
# ----------------------------------------------------------------------------------------------------------------------
# Functions for the execution of a single batch iteration
# ----------------------------------------------------------------------------------------------------------------------
def single_reduction_for_batch(state, use_optimizations, output_mode, plot_results, output_graph, save_can=False):
"""
Runs a single reduction.
This function creates reduction packages which essentially contain information for a single valid reduction, run it
and store the results according to the user specified setting (output_mode). Although this is considered a single
reduction it can contain still several reductions since the SANSState object can at this point contain slice
settings which require on reduction per time slice.
:param state: a SANSState object
:param use_optimizations: if true then the optimizations of child algorithms are enabled.
:param output_mode: the output mode
:param save_can: bool. whether or not to save out can workspaces
"""
# ------------------------------------------------------------------------------------------------------------------
# Load the data
# ------------------------------------------------------------------------------------------------------------------
workspace_to_name = {SANSDataType.SampleScatter: "SampleScatterWorkspace",
SANSDataType.SampleTransmission: "SampleTransmissionWorkspace",
SANSDataType.SampleDirect: "SampleDirectWorkspace",
SANSDataType.CanScatter: "CanScatterWorkspace",
SANSDataType.CanTransmission: "CanTransmissionWorkspace",
SANSDataType.CanDirect: "CanDirectWorkspace"}
workspace_to_monitor = {SANSDataType.SampleScatter: "SampleScatterMonitorWorkspace",
SANSDataType.CanScatter: "CanScatterMonitorWorkspace"}
workspaces, monitors = provide_loaded_data(state, use_optimizations, workspace_to_name, workspace_to_monitor)
# ------------------------------------------------------------------------------------------------------------------
# Get reduction settings
# Split into individual bundles which can be reduced individually. We split here if we have multiple periods or
# sliced times for example.
# ------------------------------------------------------------------------------------------------------------------
reduction_packages = get_reduction_packages(state, workspaces, monitors)
# ------------------------------------------------------------------------------------------------------------------
# Run reductions (one at a time)
# ------------------------------------------------------------------------------------------------------------------
single_reduction_name = "SANSSingleReduction"
single_reduction_options = {"UseOptimizations": use_optimizations,
"SaveCan": save_can}
reduction_alg = create_managed_non_child_algorithm(single_reduction_name, **single_reduction_options)
reduction_alg.setChild(False)
# Perform the data reduction
for reduction_package in reduction_packages:
# -----------------------------------
# Set the properties on the algorithm
# -----------------------------------
set_properties_for_reduction_algorithm(reduction_alg, reduction_package,
workspace_to_name, workspace_to_monitor)
# -----------------------------------
# Run the reduction
# -----------------------------------
reduction_alg.execute()
# -----------------------------------
# Get the output of the algorithm
# -----------------------------------
reduction_package.reduced_lab = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceLAB")
reduction_package.reduced_hab = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceHAB")
reduction_package.reduced_merged = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceMerged")
reduction_package.reduced_lab_can = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceLABCan")
reduction_package.reduced_lab_can_count = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceLABCanCount")
reduction_package.reduced_lab_can_norm = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceLABCanNorm")
reduction_package.reduced_hab_can = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceHABCan")
reduction_package.reduced_hab_can_count = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceHABCanCount")
reduction_package.reduced_hab_can_norm = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceHABCanNorm")
reduction_package.calculated_transmission = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceCalculatedTransmission")
reduction_package.unfitted_transmission = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceUnfittedTransmission")
reduction_package.calculated_transmission_can = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceCalculatedTransmissionCan")
reduction_package.unfitted_transmission_can = get_workspace_from_algorithm(reduction_alg,
"OutputWorkspaceUnfittedTransmissionCan")
reduction_package.reduced_lab_sample = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceLABSample")
reduction_package.reduced_hab_sample = get_workspace_from_algorithm(reduction_alg, "OutputWorkspaceHABSample")
reduction_package.out_scale_factor = reduction_alg.getProperty("OutScaleFactor").value
reduction_package.out_shift_factor = reduction_alg.getProperty("OutShiftFactor").value
if plot_results and mantidplot:
plot_workspace(reduction_package, output_graph)
# -----------------------------------
# The workspaces are already on the ADS, but should potentially be grouped
# -----------------------------------
group_workspaces_if_required(reduction_package, output_mode, save_can)
# --------------------------------
# Perform output of all workspaces
# --------------------------------
# We have three options here
# 1. PublishToADS:
# * This means we can leave it as it is
# 2. SaveToFile:
# * This means we need to save out the reduced data
# * Then we need to delete the reduced data from the ADS
# 3. Both:
# * This means that we need to save out the reduced data
# * The data is already on the ADS, so do nothing
if output_mode is OutputMode.SaveToFile:
save_to_file(reduction_packages, save_can)
delete_reduced_workspaces(reduction_packages)
elif output_mode is OutputMode.Both:
save_to_file(reduction_packages, save_can)
# -----------------------------------------------------------------------
# Clean up other workspaces if the optimizations have not been turned on.
# -----------------------------------------------------------------------
if not use_optimizations:
delete_optimization_workspaces(reduction_packages, workspaces, monitors, save_can)
out_scale_factors = [reduction_package.out_scale_factor for reduction_package in reduction_packages]
out_shift_factors = [reduction_package.out_shift_factor for reduction_package in reduction_packages]
return out_scale_factors, out_shift_factors
def load_workspaces_from_states(state):
workspace_to_name = {SANSDataType.SampleScatter: "SampleScatterWorkspace",
SANSDataType.SampleTransmission: "SampleTransmissionWorkspace",
SANSDataType.SampleDirect: "SampleDirectWorkspace",
SANSDataType.CanScatter: "CanScatterWorkspace",
SANSDataType.CanTransmission: "CanTransmissionWorkspace",
SANSDataType.CanDirect: "CanDirectWorkspace"}
workspace_to_monitor = {SANSDataType.SampleScatter: "SampleScatterMonitorWorkspace",
SANSDataType.CanScatter: "CanScatterMonitorWorkspace"}
workspaces, monitors = provide_loaded_data(state, True, workspace_to_name, workspace_to_monitor)
# ----------------------------------------------------------------------------------------------------------------------
# Function for plotting
# ----------------------------------------------------------------------------------------------------------------------
def plot_workspace(reduction_package, output_graph):
if reduction_package.reduction_mode == ISISReductionMode.All:
graph_handle = mantidplot.plotSpectrum([reduction_package.reduced_hab, reduction_package.reduced_lab], 0,
window=mantidplot.graph(output_graph), clearWindow=True)
graph_handle.activeLayer().logLogAxes()
elif reduction_package.reduction_mode == ISISReductionMode.HAB:
graph_handle = mantidplot.plotSpectrum(reduction_package.reduced_hab, 0, window=mantidplot.graph(output_graph), clearWindow=True)
graph_handle.activeLayer().logLogAxes()
elif reduction_package.reduction_mode == ISISReductionMode.LAB:
graph_handle = mantidplot.plotSpectrum(reduction_package.reduced_lab, 0, window=mantidplot.graph(output_graph), clearWindow=True)
graph_handle.activeLayer().logLogAxes()
elif reduction_package.reduction_mode == ISISReductionMode.Merged:
graph_handle = mantidplot.plotSpectrum([reduction_package.reduced_merged,
reduction_package.reduced_hab, reduction_package.reduced_lab], 0,
window=mantidplot.graph(output_graph), clearWindow=True)
graph_handle.activeLayer().logLogAxes()
# ----------------------------------------------------------------------------------------------------------------------
# Functions for Data Loading
# ----------------------------------------------------------------------------------------------------------------------
def get_expected_workspace_names(file_information, is_transmission, period, get_base_name_only=False):
"""
Creates the expected names for SANS workspaces.
SANS scientists expect the load workspaces to have certain, typical names. For example, the file SANS2D00022024.nxs
which is used as a transmission workspace translates into 22024_trans_nxs.
:param file_information: a file information object
:param is_transmission: if the file information is for a transmission or not
:param period: the period of interest
:param get_base_name_only: if we only want the base name and not the name with the period information
:return: a list of workspace names
"""
suffix_file_type = get_extension_for_file_type(file_information)
if is_transmission:
suffix_data = TRANS_SUFFIX
else:
suffix_data = SANS_SUFFIX
run_number = file_information.get_run_number()
# Three possibilities:
# 1. No period data => 22024_sans_nxs
# 2. Period data, but wants all => 22025p1_sans_nxs, 22025p2_sans_nxs, ...
# 3. Period data, select particular period => 22025p3_sans_nxs
if file_information.get_number_of_periods() == 1:
workspace_name = "{0}_{1}_{2}".format(run_number, suffix_data, suffix_file_type)
names = [workspace_name]
elif file_information.get_number_of_periods() > 1 and period is StateData.ALL_PERIODS:
workspace_names = []
if get_base_name_only:
workspace_names.append("{0}_{1}_{2}".format(run_number, suffix_data, suffix_file_type))
else:
for period in range(1, file_information.get_number_of_periods() + 1):
workspace_names.append("{0}p{1}_{2}_{3}".format(run_number, period, suffix_data, suffix_file_type))
names = workspace_names
elif file_information.get_number_of_periods() > 1 and period is not StateData.ALL_PERIODS:
workspace_name = "{0}p{1}_{2}_{3}".format(run_number, period, suffix_data, suffix_file_type)
names = [workspace_name]
else:
raise RuntimeError("SANSLoad: Cannot create workspace names.")
return names
def set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options, load_workspace_name, file_name, period,
is_transmission, file_info_factory,
load_monitor_name=None):
file_info = file_info_factory.create_sans_file_information(file_name)
workspace_names = get_expected_workspace_names(file_info, is_transmission=is_transmission, period=period,
get_base_name_only=True)
count = 0
# Now we set the load options if we are dealing with multi-period data, then we need to
for workspace_name in workspace_names:
if count == 0:
load_options.update({load_workspace_name: workspace_name})
if load_monitor_name is not None:
monitor_name = workspace_name + "_monitors"
load_options.update({load_monitor_name: monitor_name})
else:
load_workspace_name_for_period = load_workspace_name + "_" + str(count)
load_options.update({load_workspace_name_for_period: workspace_name})
if load_monitor_name is not None:
load_monitor_name_for_period = load_monitor_name + "_" + str(count)
monitor_name = workspace_name + "_monitors"
load_options.update({load_monitor_name_for_period: monitor_name})
count += 1
def set_output_workspaces_on_load_algorithm(load_options, state):
data = state.data
file_information_factory = SANSFileInformationFactory()
# SampleScatter and SampleScatterMonitor
set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options=load_options,
load_workspace_name="SampleScatterWorkspace",
file_name=data.sample_scatter,
period=data.sample_scatter_period,
is_transmission=False,
file_info_factory=file_information_factory,
load_monitor_name="SampleScatterMonitorWorkspace")
# SampleTransmission
sample_transmission = data.sample_transmission
if sample_transmission:
set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options=load_options,
load_workspace_name="SampleTransmissionWorkspace",
file_name=sample_transmission,
period=data.sample_transmission_period,
is_transmission=True,
file_info_factory=file_information_factory)
# SampleDirect
sample_direct = data.sample_direct
if sample_direct:
set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options=load_options,
load_workspace_name="SampleDirectWorkspace",
file_name=sample_direct,
period=data.sample_direct_period,
is_transmission=True,
file_info_factory=file_information_factory)
# CanScatter + CanMonitor
can_scatter = data.can_scatter
if can_scatter:
set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options=load_options,
load_workspace_name="CanScatterWorkspace",
file_name=can_scatter,
period=data.can_scatter_period,
is_transmission=False,
file_info_factory=file_information_factory,
load_monitor_name="CanScatterMonitorWorkspace")
# CanTransmission
can_transmission = data.can_transmission
if can_transmission:
set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options=load_options,
load_workspace_name="CanTransmissionWorkspace",
file_name=can_transmission,
period=data.can_transmission_period,
is_transmission=True,
file_info_factory=file_information_factory)
# CanDirect
can_direct = data.can_direct
if can_direct:
set_output_workspace_on_load_algorithm_for_one_workspace_type(load_options=load_options,
load_workspace_name="CanDirectWorkspace",
file_name=can_direct,
period=data.can_direct_period,
is_transmission=True,
file_info_factory=file_information_factory)
def provide_loaded_data(state, use_optimizations, workspace_to_name, workspace_to_monitor):
"""
Provide the data for reduction.
:param state: a SANSState object.
:param use_optimizations: if optimizations are enabled, then the load mechanism will search for workspaces on the
ADS.
:param workspace_to_name: a map of SANSDataType vs output-property name of SANSLoad for workspaces
:param workspace_to_monitor: a map of SANSDataType vs output-property name of SANSLoad for monitor workspaces
:return: a list fo workspaces and a list of monitor workspaces
"""
# Load the data
state_serialized = state.property_manager
load_name = "SANSLoad"
load_options = {"SANSState": state_serialized,
"PublishToCache": use_optimizations,
"UseCached": use_optimizations}
# Set the output workspaces
set_output_workspaces_on_load_algorithm(load_options, state)
load_alg = create_managed_non_child_algorithm(load_name, **load_options)
load_alg.execute()
# Retrieve the data
workspace_to_count = {SANSDataType.SampleScatter: "NumberOfSampleScatterWorkspaces",
SANSDataType.SampleTransmission: "NumberOfSampleTransmissionWorkspaces",
SANSDataType.SampleDirect: "NumberOfSampleDirectWorkspaces",
SANSDataType.CanScatter: "NumberOfCanScatterWorkspaces",
SANSDataType.CanTransmission: "NumberOfCanTransmissionWorkspaces",
SANSDataType.CanDirect: "NumberOfCanDirectWorkspaces"}
workspaces = get_workspaces_from_load_algorithm(load_alg, workspace_to_count, workspace_to_name)
monitors = get_workspaces_from_load_algorithm(load_alg, workspace_to_count, workspace_to_monitor)
for key, workspace_type in workspaces.items():
for workspace in workspace_type:
add_to_group(workspace, 'sans_interface_raw_data')
for key, monitor_workspace_type in monitors.items():
for monitor_workspace in monitor_workspace_type:
add_to_group(monitor_workspace, 'sans_interface_raw_data')
return workspaces, monitors
def add_loaded_workspace_to_ads(load_alg, workspace_property_name, workspace):
"""
Adds a workspace with the name that was set on the output of the load algorithm to the ADS
:param load_alg: a handle to the load algorithm
:param workspace_property_name: the workspace property name
:param workspace: the workspace
"""
workspace_name = load_alg.getProperty(workspace_property_name).valueAsStr
AnalysisDataService.addOrReplace(workspace_name, workspace)
def get_workspaces_from_load_algorithm(load_alg, workspace_to_count, workspace_name_dict):
"""
Reads the workspaces from SANSLoad
:param load_alg: a handle to the load algorithm
:param workspace_to_count: a map from SANSDataType to the output-number property name of SANSLoad for workspaces
:param workspace_name_dict: a map of SANSDataType vs output-property name of SANSLoad for (monitor) workspaces
:return: a map of SANSDataType vs list of workspaces (to handle multi-period data)
"""
workspace_output = {}
for workspace_type, workspace_name in list(workspace_name_dict.items()):
count_id = workspace_to_count[workspace_type]
number_of_workspaces = load_alg.getProperty(count_id).value
workspaces = []
if number_of_workspaces > 1:
workspaces = get_multi_period_workspaces(load_alg, workspace_name_dict[workspace_type],
number_of_workspaces)
else:
workspace_id = workspace_name_dict[workspace_type]
workspace = get_workspace_from_algorithm(load_alg, workspace_id)
if workspace is not None:
workspaces.append(workspace)
# Add the workspaces to the to the output
workspace_output.update({workspace_type: workspaces})
return workspace_output
def get_multi_period_workspaces(load_alg, workspace_name, number_of_workspaces):
# Create an output name for each workspace and retrieve it from the load algorithm
workspaces = []
workspace_names = []
for index in range(1, number_of_workspaces + 1):
output_property_name = workspace_name + "_" + str(index)
output_workspace_name = load_alg.getProperty(output_property_name).valueAsStr
workspace_names.append(output_workspace_name)
workspace = get_workspace_from_algorithm(load_alg, output_property_name)
workspaces.append(workspace)
# Group the workspaces
base_name = get_base_name_from_multi_period_name(workspace_names[0])
group_name = "GroupWorkspaces"
group_options = {"InputWorkspaces": workspace_names,
"OutputWorkspace": base_name}
group_alg = create_unmanaged_algorithm(group_name, **group_options)
group_alg.setChild(False)
group_alg.execute()
return workspaces
# ----------------------------------------------------------------------------------------------------------------------
# Functions for reduction packages
# ----------------------------------------------------------------------------------------------------------------------
def get_reduction_packages(state, workspaces, monitors):
"""
This function creates a set of reduction packages which contain the necessary state for a single reduction
as well as the required workspaces.
There are several reasons why a state can (and should) split up:
1. Multi-period files were loaded. This means that we need to perform one reduction per (loaded) period
2. Event slices were specified. This means that we need to perform one reduction per event slice.
:param state: A single state which potentially needs to be split up into several states
:param workspaces: The workspaces contributing to the reduction
:param monitors: The monitors contributing to the reduction
:return: A set of "Reduction packages" where each reduction package defines a single reduction.
"""
# First: Split the state on a per-period basis
reduction_packages = create_initial_reduction_packages(state, workspaces, monitors)
# Second: Split resulting reduction packages on a per-event-slice basis
# Note that at this point all reduction packages will have the same state information. They only differ in the
# workspaces that they use.
if reduction_packages_require_splitting_for_event_slices(reduction_packages):
reduction_packages = split_reduction_packages_for_event_slice_packages(reduction_packages)
if reduction_packages_require_splitting_for_wavelength_range(reduction_packages):
reduction_packages = split_reduction_packages_for_wavelength_range(reduction_packages)
return reduction_packages
def reduction_packages_require_splitting_for_event_slices(reduction_packages):
"""
Creates reduction packages from a list of reduction packages by splitting up event slices.
The SANSSingleReduction algorithm can handle only a single time slice. For each time slice, we require an individual
reduction. Hence we split the states up at this point.
:param reduction_packages: a list of reduction packages.
:return: a list of reduction packages which has at least the same length as the input
"""
# Determine if the event slice sub-state object contains multiple event slice requests. This is given
# by the number of elements in start_tof
reduction_package = reduction_packages[0]
state = reduction_package.state
slice_event_info = state.slice
start_time = slice_event_info.start_time
if start_time is not None and len(start_time) > 1:
requires_split = True
else:
requires_split = False
return requires_split
def reduction_packages_require_splitting_for_wavelength_range(reduction_packages):
"""
Creates reduction packages from a list of reduction packages by splitting up wavelength ranges.
The SANSSingleReduction algorithm can handle only a single wavelength range. For each wavelength range, we require an individual
reduction. Hence we split the states up at this point.
:param reduction_packages: a list of reduction packages.
:return: a list of reduction packages which has at least the same length as the input
"""
# Determine if the event slice sub-state object contains multiple event slice requests. This is given
# by the number of elements in start_tof
reduction_package = reduction_packages[0]
state = reduction_package.state
wavelength_info = state.wavelength
start_wavelength = wavelength_info.wavelength_low
if start_wavelength is not None and len(start_wavelength) > 1:
requires_split = True
else:
requires_split = False
return requires_split
def split_reduction_packages_for_wavelength_range(reduction_packages):
reduction_packages_split = []
for reduction_package in reduction_packages:
state = reduction_package.state
wavelength_info = state.wavelength
start_wavelength = wavelength_info.wavelength_low
end_wavelength = wavelength_info.wavelength_high
states = []
for start, end in zip(start_wavelength, end_wavelength):
state_copy = deepcopy(state)
state_copy.wavelength.wavelength_low = [start]
state_copy.wavelength.wavelength_high = [end]
state_copy.adjustment.normalize_to_monitor.wavelength_low = [start]
state_copy.adjustment.normalize_to_monitor.wavelength_high = [end]
state_copy.adjustment.calculate_transmission.wavelength_low = [start]
state_copy.adjustment.calculate_transmission.wavelength_high = [end]
state_copy.adjustment.wavelength_and_pixel_adjustment.wavelength_low = [start]
state_copy.adjustment.wavelength_and_pixel_adjustment.wavelength_high = [end]
states.append(state_copy)
workspaces = reduction_package.workspaces
monitors = reduction_package.monitors
is_part_of_multi_period_reduction = reduction_package.is_part_of_multi_period_reduction
is_part_of_event_slice_reduction = reduction_package.is_part_of_event_slice_reduction
for state in states:
new_state = deepcopy(state)
new_reduction_package = ReductionPackage(state=new_state,
workspaces=workspaces,
monitors=monitors,
is_part_of_multi_period_reduction=is_part_of_multi_period_reduction,
is_part_of_event_slice_reduction=is_part_of_event_slice_reduction,
is_part_of_wavelength_range_reduction=True)
reduction_packages_split.append(new_reduction_package)
return reduction_packages_split
def split_reduction_packages_for_event_slice_packages(reduction_packages):
"""
Splits a reduction package object into several reduction package objects if it contains several event slice settings
We want to split this up here since each event slice is a full reduction cycle in itself.
:param reduction_packages: a list of reduction packages
:return: a list of reduction packages where each reduction setting contains only one event slice.
"""
# Since the state is the same for all reduction packages at this point we only need to create the split state once
# for the first package and the apply to all the other packages. If we have 5 reduction packages and the user
# requests 6 event slices, then we end up with 60 reductions!
reduction_packages_split = []
for reduction_package in reduction_packages:
state = reduction_package.state
slice_event_info = state.slice
start_time = slice_event_info.start_time
end_time = slice_event_info.end_time
states = []
for start, end in zip(start_time, end_time):
state_copy = deepcopy(state)
slice_event_info = state_copy.slice
slice_event_info.start_time = [start]
slice_event_info.end_time = [end]
states.append(state_copy)
workspaces = reduction_package.workspaces
monitors = reduction_package.monitors
is_part_of_multi_period_reduction = reduction_package.is_part_of_multi_period_reduction
for state in states:
new_state = deepcopy(state)
new_reduction_package = ReductionPackage(state=new_state,
workspaces=workspaces,
monitors=monitors,
is_part_of_multi_period_reduction=is_part_of_multi_period_reduction,
is_part_of_event_slice_reduction=True)
reduction_packages_split.append(new_reduction_package)
return reduction_packages_split
def create_initial_reduction_packages(state, workspaces, monitors):
"""
This provides the initial split of the workspaces.
If the data stems from multi-period data, then we need to split up the workspaces. The state object is valid
for each one of these workspaces. Hence we need to create a deep copy of them for each reduction package.
The way multi-period files are handled over the different workspaces input types is:
1. The sample scatter period determines all other periods, i.e. if the sample scatter workspace is has only
one period, but the sample transmission has two, then only the first period is used.
2. If the sample scatter period is not available on an other workspace type, then the last period on that
workspace type is used.
For the cases where the periods between the different workspaces types does not match, an information is logged.
:param state: A single state which potentially needs to be split up into several states
:param workspaces: The workspaces contributing to the reduction
:param monitors: The monitors contributing to the reduction
:return: A set of "Reduction packages" where each reduction package defines a single reduction.
"""
# For loaded peri0d we create a package
packages = []
data_info = state.data
sample_scatter_period = data_info.sample_scatter_period
requires_new_period_selection = len(workspaces[SANSDataType.SampleScatter]) > 1 \
and sample_scatter_period == ALL_PERIODS # noqa
is_multi_period = len(workspaces[SANSDataType.SampleScatter]) > 1
for index in range(0, len(workspaces[SANSDataType.SampleScatter])):
workspaces_for_package = {}
# For each workspace type, i.e sample scatter, can transmission, etc. find the correct workspace
for workspace_type, workspace_list in list(workspaces.items()):
workspace = get_workspace_for_index(index, workspace_list)
workspaces_for_package.update({workspace_type: workspace})
# For each monitor type, find the correct workspace
monitors_for_package = {}
for workspace_type, workspace_list in list(monitors.items()):
workspace = get_workspace_for_index(index, workspace_list)
monitors_for_package.update({workspace_type: workspace})
state_copy = deepcopy(state)
# Set the period on the state
if requires_new_period_selection:
state_copy.data.sample_scatter_period = index + 1
packages.append(ReductionPackage(state=state_copy,
workspaces=workspaces_for_package,
monitors=monitors_for_package,
is_part_of_multi_period_reduction=is_multi_period,
is_part_of_event_slice_reduction=False))
return packages
def get_workspace_for_index(index, workspace_list):
"""
Extracts the workspace from the list of workspaces. The index is set by the nth ScatterSample workspace.
There might be situation where there is no corresponding CanXXX workspace or SampleTransmission workspace etc,
since they are optional.
:param index: The index of the workspace from which to extract.
:param workspace_list: A list of workspaces.
:return: The workspace corresponding to the index or None
"""
if workspace_list:
if index < len(workspace_list):
workspace = workspace_list[index]
else:
workspace = None
else:
workspace = None
return workspace
def set_properties_for_reduction_algorithm(reduction_alg, reduction_package, workspace_to_name, workspace_to_monitor):
"""
Sets up everything necessary on the reduction algorithm.
:param reduction_alg: a handle to the reduction algorithm
:param reduction_package: a reduction package object
:param workspace_to_name: the workspace to name map
:param workspace_to_monitor: a workspace to monitor map
"""
def _set_output_name(_reduction_alg, _reduction_package, _is_group, _reduction_mode, _property_name,
_attr_out_name, _atrr_out_name_base, multi_reduction_type, _suffix=None, transmission=False):
if not transmission:
_out_name, _out_name_base = get_output_name(_reduction_package.state, _reduction_mode, _is_group,
multi_reduction_type=multi_reduction_type)
else:
_out_name, _out_name_base = get_transmission_output_name(_reduction_package.state, _reduction_mode
, multi_reduction_type=multi_reduction_type)
if _suffix is not None:
_out_name += _suffix
_out_name_base += _suffix
_reduction_alg.setProperty(_property_name, _out_name)
setattr(_reduction_package, _attr_out_name, _out_name)
setattr(_reduction_package, _atrr_out_name_base, _out_name_base)
def _set_output_name_from_string(reduction_alg, reduction_package, algorithm_property_name, workspace_name,
workspace_name_base ,package_attribute_name, package_attribute_name_base):
reduction_alg.setProperty(algorithm_property_name, workspace_name)
setattr(reduction_package, package_attribute_name, workspace_name)
setattr(reduction_package, package_attribute_name_base, workspace_name_base)
def _set_lab(_reduction_alg, _reduction_package, _is_group):
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.LAB,
"OutputWorkspaceLABCan", "reduced_lab_can_name", "reduced_lab_can_base_name",
multi_reduction_type, LAB_CAN_SUFFIX)
# Lab Can Count workspace - this is a partial workspace
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.LAB,
"OutputWorkspaceLABCanCount", "reduced_lab_can_count_name", "reduced_lab_can_count_base_name",
multi_reduction_type, LAB_CAN_COUNT_SUFFIX)
# Lab Can Norm workspace - this is a partial workspace
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.LAB,
"OutputWorkspaceLABCanNorm", "reduced_lab_can_norm_name", "reduced_lab_can_norm_base_name",
multi_reduction_type, LAB_CAN_NORM_SUFFIX)
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.LAB,
"OutputWorkspaceLABSample", "reduced_lab_sample_name", "reduced_lab_sample_base_name",
multi_reduction_type, LAB_SAMPLE_SUFFIX)
def _set_hab(_reduction_alg, _reduction_package, _is_group):
# Hab Can Workspace
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.HAB,
"OutputWorkspaceHABCan", "reduced_hab_can_name", "reduced_hab_can_base_name",
multi_reduction_type, HAB_CAN_SUFFIX)
# Hab Can Count workspace - this is a partial workspace
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.HAB,
"OutputWorkspaceHABCanCount", "reduced_hab_can_count_name", "reduced_hab_can_count_base_name",
multi_reduction_type, HAB_CAN_COUNT_SUFFIX)
# Hab Can Norm workspace - this is a partial workspace
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.HAB,
"OutputWorkspaceHABCanNorm", "reduced_hab_can_norm_name", "reduced_hab_can_norm_base_name",
multi_reduction_type, HAB_CAN_NORM_SUFFIX)
_set_output_name(_reduction_alg, _reduction_package, _is_group, ISISReductionMode.HAB,
"OutputWorkspaceHABSample", "reduced_hab_sample_name", "reduced_hab_sample_base_name",
multi_reduction_type, HAB_SAMPLE_SUFFIX)
# Go through the elements of the reduction package and set them on the reduction algorithm
# Set the SANSState
state = reduction_package.state
state_dict = state.property_manager
reduction_alg.setProperty("SANSState", state_dict)
# Set the input workspaces
workspaces = reduction_package.workspaces
for workspace_type, workspace in list(workspaces.items()):
if workspace is not None:
reduction_alg.setProperty(workspace_to_name[workspace_type], workspace)
# Set the monitors
monitors = reduction_package.monitors
for workspace_type, monitor in list(monitors.items()):
if monitor is not None:
reduction_alg.setProperty(workspace_to_monitor[workspace_type], monitor)
# ------------------------------------------------------------------------------------------------------------------
# Set the output workspaces for LAB, HAB and Merged
# ------------------------------------------------------------------------------------------------------------------
is_part_of_multi_period_reduction = reduction_package.is_part_of_multi_period_reduction
is_part_of_event_slice_reduction = reduction_package.is_part_of_event_slice_reduction
is_part_of_wavelength_range_reduction = reduction_package.is_part_of_wavelength_range_reduction
is_group = is_part_of_multi_period_reduction or is_part_of_event_slice_reduction or is_part_of_wavelength_range_reduction
multi_reduction_type = {"period": is_part_of_multi_period_reduction, "event_slice": is_part_of_event_slice_reduction,
"wavelength_range": is_part_of_wavelength_range_reduction}
reduction_mode = reduction_package.reduction_mode
if reduction_mode is ISISReductionMode.Merged:
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.Merged,
"OutputWorkspaceMerged", "reduced_merged_name", "reduced_merged_base_name", multi_reduction_type)
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.LAB,
"OutputWorkspaceLAB", "reduced_lab_name", "reduced_lab_base_name", multi_reduction_type)
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.HAB,
"OutputWorkspaceHAB", "reduced_hab_name", "reduced_hab_base_name", multi_reduction_type)
elif reduction_mode is ISISReductionMode.LAB:
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.LAB,
"OutputWorkspaceLAB", "reduced_lab_name", "reduced_lab_base_name", multi_reduction_type)
elif reduction_mode is ISISReductionMode.HAB:
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.HAB,
"OutputWorkspaceHAB", "reduced_hab_name", "reduced_hab_base_name", multi_reduction_type)
elif reduction_mode is ISISReductionMode.All:
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.LAB,
"OutputWorkspaceLAB", "reduced_lab_name", "reduced_lab_base_name", multi_reduction_type)
_set_output_name(reduction_alg, reduction_package, is_group, ISISReductionMode.HAB,
"OutputWorkspaceHAB", "reduced_hab_name", "reduced_hab_base_name", multi_reduction_type)
else:
raise RuntimeError("The reduction mode {0} is not known".format(reduction_mode))
# ------------------------------------------------------------------------------------------------------------------
# Set the output workspaces for the can reduction and the partial can reductions
# ------------------------------------------------------------------------------------------------------------------
# Set the output workspaces for the can reductions -- note that these will only be set if optimizations
# are enabled
# Lab Can Workspace
if reduction_mode is ISISReductionMode.Merged:
_set_lab(reduction_alg, reduction_package, is_group)
_set_hab(reduction_alg, reduction_package, is_group)
elif reduction_mode is ISISReductionMode.LAB:
_set_lab(reduction_alg, reduction_package, is_group)
elif reduction_mode is ISISReductionMode.HAB:
_set_hab(reduction_alg, reduction_package, is_group)
elif reduction_mode is ISISReductionMode.All:
_set_lab(reduction_alg, reduction_package, is_group)
_set_hab(reduction_alg, reduction_package, is_group)
else:
raise RuntimeError("The reduction mode {0} is not known".format(reduction_mode))
#-------------------------------------------------------------------------------------------------------------------
# Set the output workspaces for the calculated and unfitted transmission
#-------------------------------------------------------------------------------------------------------------------
if state.adjustment.show_transmission:
sample_calculated_transmission,\
sample_calculated_transmission_base = get_transmission_output_name(reduction_package.state, DataType.Sample,
multi_reduction_type, True)
can_calculated_transmission,\
can_calculated_transmission_base = get_transmission_output_name(reduction_package.state, DataType.Can,
multi_reduction_type, True)
sample_unfitted_transmission,\
sample_unfitted_transmission_base = get_transmission_output_name(reduction_package.state, DataType.Sample,
multi_reduction_type, False)
can_unfitted_transmission,\
can_unfitted_transmission_base = get_transmission_output_name(reduction_package.state, DataType.Can,
multi_reduction_type, False)
_set_output_name_from_string(reduction_alg, reduction_package, "OutputWorkspaceCalculatedTransmission",
sample_calculated_transmission, sample_calculated_transmission_base
,"calculated_transmission_name", "calculated_transmission_base_name")
_set_output_name_from_string(reduction_alg, reduction_package, "OutputWorkspaceUnfittedTransmission",
sample_unfitted_transmission, sample_unfitted_transmission_base
, "unfitted_transmission_name", "unfitted_transmission_base_name")
_set_output_name_from_string(reduction_alg, reduction_package, "OutputWorkspaceCalculatedTransmissionCan",
can_calculated_transmission, can_calculated_transmission_base
, "calculated_transmission_can_name", "calculated_transmission_can_base_name")
_set_output_name_from_string(reduction_alg, reduction_package, "OutputWorkspaceUnfittedTransmissionCan",
can_unfitted_transmission, can_unfitted_transmission_base
, "unfitted_transmission_can_name", "unfitted_transmission_can_base_name")
def get_workspace_from_algorithm(alg, output_property_name):
"""
Gets the output workspace from an algorithm. Since we don't run this as a child we need to get it from the
ADS.
:param alg: a handle to the algorithm from which we want to take the output workspace property.
:param output_property_name: the name of the output property.
:return the workspace or None
"""
output_workspace_name = alg.getProperty(output_property_name).valueAsStr
if not output_workspace_name:
return None
if AnalysisDataService.doesExist(output_workspace_name):
return AnalysisDataService.retrieve(output_workspace_name)
else:
return None
# ----------------------------------------------------------------------------------------------------------------------
# Functions for outputs to the ADS and saving the file
# ----------------------------------------------------------------------------------------------------------------------
def group_workspaces_if_required(reduction_package, output_mode, save_can):
"""
The output workspaces have already been published to the ADS by the algorithm. Now we might have to
bundle them into a group if:
* They are part of a multi-period workspace or a sliced reduction
* They are reduced LAB and HAB workspaces of a Merged reduction
* They are can workspaces - they are all grouped into a single group
:param reduction_package: a list of reduction packages
:param output_mode: one of OutputMode. SaveToFile, PublishToADS, Both.
:param save_can: a bool. If true save out can and sample workspaces.
"""
is_part_of_multi_period_reduction = reduction_package.is_part_of_multi_period_reduction
is_part_of_event_slice_reduction = reduction_package.is_part_of_event_slice_reduction
is_part_of_wavelength_range_reduction = reduction_package.is_part_of_wavelength_range_reduction
requires_grouping = is_part_of_multi_period_reduction or is_part_of_event_slice_reduction\
or is_part_of_wavelength_range_reduction
reduced_lab = reduction_package.reduced_lab
reduced_hab = reduction_package.reduced_hab
reduced_merged = reduction_package.reduced_merged
is_merged_reduction = reduced_merged is not None
# Add the reduced workspaces to groups if they require this
if is_merged_reduction:
if requires_grouping:
add_to_group(reduced_merged, reduction_package.reduced_merged_base_name)
add_to_group(reduced_lab, REDUCED_HAB_AND_LAB_WORKSPACE_FOR_MERGED_REDUCTION)
add_to_group(reduced_hab, REDUCED_HAB_AND_LAB_WORKSPACE_FOR_MERGED_REDUCTION)
else:
add_to_group(reduced_lab, REDUCED_HAB_AND_LAB_WORKSPACE_FOR_MERGED_REDUCTION)
add_to_group(reduced_hab, REDUCED_HAB_AND_LAB_WORKSPACE_FOR_MERGED_REDUCTION)
else:
if requires_grouping:
add_to_group(reduced_lab, reduction_package.reduced_lab_base_name)
add_to_group(reduced_hab, reduction_package.reduced_hab_base_name)
# Can group workspace depends on if save_can is checked and output_mode
# Logic table for which group to save CAN into
# CAN | FILE | In OPTIMIZATION group
# ----------------------------------
# Y | Y | YES
# N | Y | YES
# Y | N | NO
# N | N | YES
if save_can and output_mode is not OutputMode.SaveToFile:
CAN_WORKSPACE_GROUP = CAN_AND_SAMPLE_WORKSPACE
else:
CAN_WORKSPACE_GROUP = CAN_COUNT_AND_NORM_FOR_OPTIMIZATION
# Add the can workspaces (used for optimizations) to a Workspace Group (if they exist)
add_to_group(reduction_package.reduced_lab_can, CAN_WORKSPACE_GROUP)
add_to_group(reduction_package.reduced_lab_can_count, CAN_COUNT_AND_NORM_FOR_OPTIMIZATION)
add_to_group(reduction_package.reduced_lab_can_norm, CAN_COUNT_AND_NORM_FOR_OPTIMIZATION)
add_to_group(reduction_package.reduced_hab_can, CAN_WORKSPACE_GROUP)
add_to_group(reduction_package.reduced_hab_can_count, CAN_COUNT_AND_NORM_FOR_OPTIMIZATION)
add_to_group(reduction_package.reduced_hab_can_norm, CAN_COUNT_AND_NORM_FOR_OPTIMIZATION)
add_to_group(reduction_package.reduced_lab_sample, CAN_AND_SAMPLE_WORKSPACE)
add_to_group(reduction_package.reduced_hab_sample, CAN_AND_SAMPLE_WORKSPACE)
if reduction_package.state.adjustment.show_transmission:
add_to_group(reduction_package.calculated_transmission, reduction_package.calculated_transmission_base_name)
add_to_group(reduction_package.calculated_transmission_can,
reduction_package.calculated_transmission_can_base_name)
add_to_group(reduction_package.unfitted_transmission, reduction_package.unfitted_transmission_base_name)
add_to_group(reduction_package.unfitted_transmission_can, reduction_package.unfitted_transmission_can_base_name)
def add_to_group(workspace, name_of_group_workspace):
"""
Creates a group workspace with the base name for the workspace
:param workspace: the workspace to add to the WorkspaceGroup
:param name_of_group_workspace: the name of the WorkspaceGroup
"""
if workspace is None:
return
name_of_workspace = workspace.name()
if AnalysisDataService.doesExist(name_of_group_workspace):
group_workspace = AnalysisDataService.retrieve(name_of_group_workspace)
if type(group_workspace) is WorkspaceGroup:
if not group_workspace.contains(name_of_workspace):
group_workspace.add(name_of_workspace)
else:
group_name = "GroupWorkspaces"
group_options = {"InputWorkspaces": [name_of_workspace],
"OutputWorkspace": name_of_group_workspace}
group_alg = create_unmanaged_algorithm(group_name, **group_options)
group_alg.setAlwaysStoreInADS(True)
group_alg.execute()
else:
group_name = "GroupWorkspaces"
group_options = {"InputWorkspaces": [name_of_workspace],
"OutputWorkspace": name_of_group_workspace}
group_alg = create_unmanaged_algorithm(group_name, **group_options)
group_alg.setAlwaysStoreInADS(True)
group_alg.execute()
def save_to_file(reduction_packages, save_can):
"""
Extracts all workspace names which need to be saved and saves them into a file.
@param reduction_packages: a list of reduction packages which contain all the relevant information for saving
@param save_can: a bool. When true save the unsubtracted can and sample workspaces
"""
workspaces_names_to_save = get_all_names_to_save(reduction_packages, save_can=save_can)
state = reduction_packages[0].state
save_info = state.save
file_formats = save_info.file_format
for name_to_save in workspaces_names_to_save:
save_workspace_to_file(name_to_save, file_formats, name_to_save)
def delete_reduced_workspaces(reduction_packages):
"""
Deletes all workspaces which would have been generated from a list of reduction packages.
@param reduction_packages: a list of reduction package
"""
def _delete_workspaces(_delete_alg, _workspaces):
for _workspace in _workspaces:
if _workspace is not None:
_delete_alg.setProperty("Workspace", _workspace.name())
_delete_alg.execute()
# Get all names which were saved out to workspaces
# Delete each workspace
delete_name = "DeleteWorkspace"
delete_options = {}
delete_alg = create_unmanaged_algorithm(delete_name, **delete_options)
for reduction_package in reduction_packages:
reduced_lab = reduction_package.reduced_lab
reduced_hab = reduction_package.reduced_hab
reduced_merged = reduction_package.reduced_merged
# Remove samples
reduced_lab_sample = reduction_package.reduced_lab_sample
reduced_hab_sample = reduction_package.reduced_hab_sample
# Remove transmissions
calculated_transmission = reduction_package.calculated_transmission
unfitted_transmission = reduction_package.unfitted_transmission
calculated_transmission_can = reduction_package.calculated_transmission_can
unfitted_transmission_can = reduction_package.unfitted_transmission_can
workspaces_to_delete = [reduced_lab, reduced_hab, reduced_merged,
reduced_lab_sample, reduced_hab_sample,
calculated_transmission, unfitted_transmission,
calculated_transmission_can, unfitted_transmission_can]
_delete_workspaces(delete_alg, workspaces_to_delete)
def delete_optimization_workspaces(reduction_packages, workspaces, monitors, save_can):
"""
Deletes all workspaces which are used for optimizations. This can be loaded workspaces or can optimizations
:param reduction_packages: a list of reductioin packages.
"""
def _delete_workspaces(_delete_alg, _workspaces):
_workspace_names_to_delete = set([_workspace.name() for _workspace in _workspaces if _workspace is not None])
for _workspace_name_to_delete in _workspace_names_to_delete:
if _workspace_name_to_delete and AnalysisDataService.doesExist(_workspace_name_to_delete):
_delete_alg.setProperty("Workspace", _workspace_name_to_delete)
_delete_alg.execute()
def _delete_workspaces_from_dict(_delete_alg, workspaces):
_workspace_names_to_delete = []
for key, workspace_list in workspaces.items():
for workspace in workspace_list:
if workspace and workspace.name():
_workspace_names_to_delete.append(workspace.name())
for _workspace_name_to_delete in _workspace_names_to_delete:
if _workspace_name_to_delete and AnalysisDataService.doesExist(_workspace_name_to_delete):
_delete_alg.setProperty("Workspace", _workspace_name_to_delete)
_delete_alg.execute()
delete_name = "DeleteWorkspace"
delete_options = {}
delete_alg = create_unmanaged_algorithm(delete_name, **delete_options)
_delete_workspaces_from_dict(delete_alg, workspaces)
_delete_workspaces_from_dict(delete_alg, monitors)
for reduction_package in reduction_packages:
# Delete can optimizations
optimizations_to_delete = [reduction_package.reduced_lab_can_count,
reduction_package.reduced_lab_can_norm,
reduction_package.reduced_hab_can_count,
reduction_package.reduced_hab_can_norm]
if not save_can:
optimizations_to_delete.extend([reduction_package.reduced_lab_can,
reduction_package.reduced_hab_can])
_delete_workspaces(delete_alg, optimizations_to_delete)
def get_all_names_to_save(reduction_packages, save_can):
"""
Extracts all the output names from a list of reduction packages. The main
@param reduction_packages: a list of reduction packages
@param save_can: a bool, whether or not to save unsubtracted can workspace
@return: a list of workspace names to save.
"""
names_to_save = []
for reduction_package in reduction_packages:
reduced_lab = reduction_package.reduced_lab
reduced_hab = reduction_package.reduced_hab
reduced_merged = reduction_package.reduced_merged
reduced_lab_can = reduction_package.reduced_lab_can
reduced_hab_can = reduction_package.reduced_hab_can
reduced_lab_sample = reduction_package.reduced_lab_sample
reduced_hab_sample = reduction_package.reduced_hab_sample
if save_can:
if reduced_merged:
names_to_save.append(reduced_merged.name())
if reduced_lab:
names_to_save.append(reduced_lab.name())
if reduced_hab:
names_to_save.append(reduced_hab.name())
if reduced_lab_can:
names_to_save.append(reduced_lab_can.name())
if reduced_hab_can:
names_to_save.append(reduced_hab_can.name())
if reduced_lab_sample:
names_to_save.append(reduced_lab_sample.name())
if reduced_hab_sample:
names_to_save.append(reduced_hab_sample.name())
# If we have merged reduction then store the
elif reduced_merged:
names_to_save.append(reduced_merged.name())
else:
if reduced_lab:
names_to_save.append(reduced_lab.name())
if reduced_hab:
names_to_save.append(reduced_hab.name())
# We might have some workspaces as duplicates (the group workspaces), so make them unique
return set(names_to_save)
def save_workspace_to_file(workspace_name, file_formats, file_name):
"""
Saves the workspace to the different file formats specified in the state object.
:param workspace_name: the name of the output workspace and also the name of the file
:param file_formats: a list of file formats to save
"""
save_name = "SANSSave"
save_options = {"InputWorkspace": workspace_name}
save_options.update({"Filename": file_name})
if SaveType.Nexus in file_formats:
save_options.update({"Nexus": True})
if SaveType.CanSAS in file_formats:
save_options.update({"CanSAS": True})
if SaveType.NXcanSAS in file_formats:
save_options.update({"NXcanSAS": True})
if SaveType.NistQxy in file_formats:
save_options.update({"NistQxy": True})
if SaveType.RKH in file_formats:
save_options.update({"RKH": True})
if SaveType.CSV in file_formats:
save_options.update({"CSV": True})
save_alg = create_unmanaged_algorithm(save_name, **save_options)
save_alg.execute()
# ----------------------------------------------------------------------------------------------------------------------
# Container classes
# ----------------------------------------------------------------------------------------------------------------------
class ReducedDataType(object):
class Merged(object):
pass
class LAB(object):
pass
class HAB(object):
pass
class ReductionPackage(object):
"""
The reduction package is a mutable store for
1. The state object which defines our reductions.
2. A dictionary with input_workspace_type vs input_workspace
3. A dictionary with input_monitor_workspace_type vs input_monitor_workspace
4. A flag which indicates if the reduction is part of a multi-period reduction
5. A flag which indicates if the reduction is part of a sliced reduction
6. The reduced workspaces (not all need to exist)
7. The reduced can and the reduced partial can workspaces (non have to exist, this is only for optimizations)
"""
def __init__(self, state, workspaces, monitors, is_part_of_multi_period_reduction=False,
is_part_of_event_slice_reduction=False, is_part_of_wavelength_range_reduction=False):
super(ReductionPackage, self).__init__()
# -------------------------------------------------------
# General Settings
# -------------------------------------------------------
self.state = state
self.workspaces = workspaces
self.monitors = monitors
self.is_part_of_multi_period_reduction = is_part_of_multi_period_reduction
self.is_part_of_event_slice_reduction = is_part_of_event_slice_reduction
self.is_part_of_wavelength_range_reduction = is_part_of_wavelength_range_reduction
self.reduction_mode = state.reduction.reduction_mode
# -------------------------------------------------------
# Reduced workspaces
# -------------------------------------------------------
self.reduced_lab = None
self.reduced_hab = None
self.reduced_merged = None
# -------------------------------------------------------
# Reduced partial can workspaces (and partial workspaces)
# -------------------------------------------------------
self.reduced_lab_can = None
self.reduced_lab_can_count = None
self.reduced_lab_can_norm = None
self.reduced_hab_can = None
self.reduced_hab_can_count = None
self.reduced_hab_can_norm = None
# -------------------------------------------------------
# Output names and base names
# -------------------------------------------------------
self.reduced_lab_name = None
self.reduced_lab_base_name = None
self.reduced_hab_name = None
self.reduced_hab_base_name = None
self.reduced_merged_name = None
self.reduced_merged_base_name = None
# Partial reduced can workspace names
self.reduced_lab_can_name = None
self.reduced_lab_can_base_name = None
self.reduced_lab_can_count_name = None
self.reduced_lab_can_count_base_name = None
self.reduced_lab_can_norm_name = None
self.reduced_lab_can_norm_base_name = None
self.reduced_hab_can_name = None
self.reduced_hab_can_base_name = None
self.reduced_hab_can_count_name = None
self.reduced_hab_can_count_base_name = None
self.reduced_hab_can_norm_name = None
self.reduced_hab_can_norm_base_name = None
self.out_scale_factor = None
self.out_shift_factor = None