diff --git a/Framework/PythonInterface/mantid/api/src/Exports/ADSValidator.cpp b/Framework/PythonInterface/mantid/api/src/Exports/ADSValidator.cpp index 21ff2b4bfc6a0b5c6c1538de3e1eeeae7eb707d4..07d4ae5cae4eb71ff9dc324ec38b06eea737c18d 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/ADSValidator.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/ADSValidator.cpp @@ -16,9 +16,10 @@ using namespace boost::python; /// This is the base TypedValidator for most of the WorkspaceValidators void export_ADSValidator() { - TypedValidatorExporter<std::string>::define("StringTypedValidator"); + TypedValidatorExporter<std::vector<std::string>> + ::define("StringTypedValidator"); - class_<ADSValidator, bases<TypedValidator<std::string>>, boost::noncopyable>( + class_<ADSValidator, bases<TypedValidator<std::vector<std::string>>>, boost::noncopyable>( "ADSValidator", init<>("Default constructor")) .def(init<const bool, const bool>( "Constructor setting allowMultiple and isOptional.", diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MergeWorkspacesWithLimits.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MergeWorkspacesWithLimits.py index 80a20411a7eb4e336ccb5ffa5b1ce0924c9f8ce1..eacd90f3955b25ca258983f166b1186f9a5186cc 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MergeWorkspacesWithLimits.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MergeWorkspacesWithLimits.py @@ -6,9 +6,12 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) -from mantid.simpleapi import (ConjoinWorkspaces, CropWorkspaceRagged, DeleteWorkspace, MatchSpectra, Rebin, SumSpectra) -from mantid.api import (DataProcessorAlgorithm, AlgorithmFactory, WorkspaceProperty, WorkspaceGroupProperty) -from mantid.kernel import (Direction, FloatArrayProperty) +from mantid.simpleapi import (AnalysisDataService, CloneWorkspace, ConjoinWorkspaces, CropWorkspaceRagged, + DeleteWorkspace, GroupWorkspaces, MatchSpectra, Rebin, SumSpectra) +from mantid.api import (AlgorithmFactory, DataProcessorAlgorithm, WorkspaceProperty, WorkspaceGroup, + WorkspaceGroupProperty, ADSValidator) +from mantid.dataobjects import Workspace2D +from mantid.kernel import (Direction, FloatArrayProperty, StringArrayProperty) import numpy as np @@ -36,66 +39,109 @@ class MergeWorkspacesWithLimits(DataProcessorAlgorithm): # given workspaces must exist # and must be public of ExperimentInfo issues = dict() - ws_group = self.getProperty('InputWorkspaces').value + ws_list = self.getProperty('InputWorkspaces').value + if not self.validate_ws(ws_list): + issues['InputWorkspaces'] = 'InputWorkspaces is not a list of workspaces or group workspace' + spectra_count = 0 + for name_in_list in ws_list: + ws_in_list = AnalysisDataService.retrieve(name_in_list) + if type(ws_in_list) == Workspace2D: + spectra_count += ws_in_list.getNumberHistograms() + if type(ws_in_list) == WorkspaceGroup: + for ws_in_group in ws_in_list: + spectra_count += ws_in_group.getNumberHistograms() + x_min = self.getProperty('XMin').value + if not x_min.size == spectra_count: + issues['XMin'] = 'XMin entries does not match size of workspace group' + x_max = self.getProperty('XMax').value - if not x_min.size == ws_group.size(): - issues['x_min'] = 'x_min entries does not match size of workspace group' - if not x_max.size == ws_group.size(): - issues['x_max'] = 'x_max entries does not match size of workspace group' + if not x_max.size == spectra_count: + issues['XMax'] = 'XMax entries does not match size of workspace group' + return issues + @staticmethod + def validate_ws(ws_in): + for ws in ws_in: + try: + AnalysisDataService.retrieve(ws) + except KeyError: + return False + return True + def PyInit(self): - self.declareProperty(WorkspaceGroupProperty('InputWorkspaces', '', direction=Direction.Input), - doc='The group workspace containing workspaces to be merged.') + self.declareProperty(StringArrayProperty('InputWorkspaces', direction=Direction.Input, validator=ADSValidator()), + doc='List of workspaces or group workspace containing workspaces to be merged.') self.declareProperty(WorkspaceProperty('OutputWorkspace', '', direction=Direction.Output), - doc='The merged workspace') - self.declareProperty(FloatArrayProperty('XMin', [],), - doc='Array of minimum X values for each workspace') - self.declareProperty(FloatArrayProperty('XMax', [],), - doc='Array of maximum X values for each workspace') + doc='The merged workspace.') + self.declareProperty(FloatArrayProperty('XMin', [], direction=Direction.Input), + doc='Array of minimum X values for each workspace.') + self.declareProperty(FloatArrayProperty('XMax', [], direction=Direction.Input), + doc='Array of maximum X values for each workspace.') + self.declareProperty('CalculateScale', True, + doc='Calculate scale factor when matching spectra.') + self.declareProperty('CalculateOffset', True, + doc='Calculate vertical shift when matching spectra.') def PyExec(self): - ws_group = self.getProperty('InputWorkspaces').value + ws_list = self.getProperty('InputWorkspaces').value x_min = self.getProperty('XMin').value x_max = self.getProperty('XMax').value - largest_range_spectrum, rebin_param = self.get_common_bin_range_and_largest_spectra(ws_group) - ws_group = Rebin(InputWorkspace=ws_group, - Params=rebin_param, - StoreInADS=False) - while ws_group.size() > 1: - ConjoinWorkspaces(InputWorkspace1=ws_group[0], - InputWorkspace2=ws_group[1], + scale_bool = self.getProperty('CalculateScale').value + offset_bool = self.getProperty('CalculateOffset').value + flattened_list = self.unwrap_groups(ws_list) + largest_range_spectrum, rebin_param = self.get_common_bin_range_and_largest_spectra(flattened_list) + CloneWorkspace(InputWorkspace=flattened_list[0], OutputWorkspace='ws_conjoined') + Rebin(InputWorkspace='ws_conjoined', OutputWorkspace='ws_conjoined', Params=rebin_param) + for ws in flattened_list[1:]: + temp = CloneWorkspace(InputWorkspace=ws) + temp = Rebin(InputWorkspace=temp, Params=rebin_param) + ConjoinWorkspaces(InputWorkspace1='ws_conjoined', + InputWorkspace2=temp, CheckOverlapping=False) - - ws_conjoined, offset, scale, chisq = MatchSpectra(InputWorkspace=ws_group[0], - ReferenceSpectrum=largest_range_spectrum, - CalculateScale=False) + ws_conjoined = AnalysisDataService.retrieve('ws_conjoined') + ref_spec = ws_conjoined.getSpectrum(largest_range_spectrum).getSpectrumNo() + ws_conjoined, offset, scale, chisq = MatchSpectra(InputWorkspace=ws_conjoined, + ReferenceSpectrum=ref_spec, + CalculateScale=scale_bool, + CalculateOffset=offset_bool) x_min, x_max, bin_width = self.fit_x_lims_to_match_histogram_bins(ws_conjoined, x_min, x_max) ws_conjoined = CropWorkspaceRagged(InputWorkspace=ws_conjoined, XMin=x_min, XMax=x_max) ws_conjoined = Rebin(InputWorkspace=ws_conjoined, Params=[min(x_min), bin_width, max(x_max)]) merged_ws = SumSpectra(InputWorkspace=ws_conjoined, WeightedSum=True, MultiplyBySpectra=False, StoreInADS=False) - DeleteWorkspace(ws_group) DeleteWorkspace(ws_conjoined) self.setProperty('OutputWorkspace', merged_ws) + def unwrap_groups(self, inputs): + output = [] + for name_in_list in inputs: + ws_in_list = AnalysisDataService.retrieve(name_in_list) + if type(ws_in_list) == Workspace2D: + output.append(ws_in_list) + if type(ws_in_list) == WorkspaceGroup: + for ws_in_group in ws_in_list: + output.append(ws_in_group) + return output + @staticmethod - def get_common_bin_range_and_largest_spectra(ws_group): + def get_common_bin_range_and_largest_spectra(ws_list): x_min = np.inf x_max = -np.inf x_num = -np.inf ws_max_range = 0 largest_range_spectrum = 0 - for i in range(ws_group.size()): - x_data = ws_group[i].dataX(0) - x_min = min(np.min(x_data), x_min) - x_max = max(np.max(x_data), x_max) - x_num = max(x_data.size, x_num) - ws_range = np.max(x_data) - np.min(x_data) - if ws_range > ws_max_range: - largest_range_spectrum = i + 1 - ws_max_range = ws_range + for i in range(len(ws_list)): + for j in range(ws_list[i].getNumberHistograms()): + x_data = ws_list[i].dataX(j) + x_min = min(np.min(x_data), x_min) + x_max = max(np.max(x_data), x_max) + x_num = max(x_data.size, x_num) + ws_range = np.max(x_data) - np.min(x_data) + if ws_range > ws_max_range: + largest_range_spectrum = i + ws_max_range = ws_range if x_min.any() == -np.inf or x_min.any() == np.inf: raise AttributeError("Workspace x range contains an infinite value.") return largest_range_spectrum, [x_min, (x_max - x_min) / x_num, x_max] diff --git a/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py b/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py index a5588fb11b516f3810075b1d3f206576eeb7bb4d..6fa87c21b96ce1ebb1118d31f8a81e3e9e5e0e3e 100644 --- a/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py +++ b/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py @@ -105,7 +105,8 @@ def generate_ts_pdf(run_number, focus_file_path, merge_banks=False, q_lims=None, if merge_banks: q_min, q_max = _load_qlims(q_lims) - merged_ws = mantid.MergeWorkspacesWithLimits(InputWorkspaces=focused_ws, XMin=q_min, XMax=q_max) + merged_ws = mantid.MergeWorkspacesWithLimits(InputWorkspaces=focused_ws, XMin=q_min, XMax=q_max, + CalculateScale=False) pdf_output = mantid.PDFFourierTransform(Inputworkspace=merged_ws, InputSofQType="S(Q)-1", PDFType="G(r)", Filter=True) else: